@xnng/browser-relay 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +445 -0
  3. package/docs/README.zh-CN.md +421 -0
  4. package/docs/benchmarks/browser-gaps-codex-ax.json +418 -0
  5. package/docs/benchmarks/browser-gaps-relay-after.json +655 -0
  6. package/docs/benchmarks/browser-gaps-relay-baseline.json +679 -0
  7. package/docs/benchmarks/browser-readiness-cost.json +106 -0
  8. package/docs/benchmarks/browser-runtime-balanced-headed.json +412 -0
  9. package/docs/benchmarks/browser-runtime-balanced-rtt50.json +412 -0
  10. package/docs/benchmarks/browser-runtime-balanced.json +412 -0
  11. package/docs/benchmarks/browser-runtime-rtt50.json +194 -0
  12. package/docs/benchmarks/browser-runtime.json +254 -0
  13. package/docs/benchmarks/browser-use-parity.json +54 -0
  14. package/docs/benchmarks/codex-extension-audit.json +131 -0
  15. package/docs/benchmarks/codex-native-protocol.md +69 -0
  16. package/docs/benchmarks/codex-native-replay.js +116 -0
  17. package/docs/benchmarks/codex-native-status.json +81 -0
  18. package/docs/benchmarks/codex-native.json +1003 -0
  19. package/docs/benchmarks/extension-sessions.png +0 -0
  20. package/docs/benchmarks/extension-tasks.png +0 -0
  21. package/docs/benchmarks/iframe-routing-regression.json +37 -0
  22. package/docs/browser-use-comparison.md +331 -0
  23. package/docs/browser-use-gap-audit.md +141 -0
  24. package/docs/browser-use-parity.md +105 -0
  25. package/docs/demo/intranet.html +103 -0
  26. package/docs/releases/v1.5.0.md +59 -0
  27. package/docs/releases/v1.5.1.md +16 -0
  28. package/docs/releases/v1.5.2.md +42 -0
  29. package/docs/releases/v1.5.3.md +33 -0
  30. package/docs/releases/v1.5.4.md +42 -0
  31. package/docs/releases/v1.6.0.md +16 -0
  32. package/docs/remote-control-hub.md +523 -0
  33. package/extension/activity.js +328 -0
  34. package/extension/automation.js +1839 -0
  35. package/extension/background.js +1854 -0
  36. package/extension/i18n.js +149 -0
  37. package/extension/icons/icon128.png +0 -0
  38. package/extension/icons/icon16.png +0 -0
  39. package/extension/icons/icon32.png +0 -0
  40. package/extension/icons/icon48.png +0 -0
  41. package/extension/manifest.json +47 -0
  42. package/extension/observations.js +109 -0
  43. package/extension/options.html +289 -0
  44. package/extension/options.js +269 -0
  45. package/extension/popup.html +74 -0
  46. package/extension/popup.js +105 -0
  47. package/extension/protocol.js +45 -0
  48. package/extension/remote-auth.js +18 -0
  49. package/extension/sessions.js +134 -0
  50. package/extension/snapshot.js +161 -0
  51. package/extension/task-groups.js +108 -0
  52. package/extension/tasks.js +186 -0
  53. package/extension/wait.js +89 -0
  54. package/hub/README.md +42 -0
  55. package/hub/package-lock.json +1544 -0
  56. package/hub/package.json +13 -0
  57. package/hub/src/rpc.js +41 -0
  58. package/hub/src/worker.js +322 -0
  59. package/hub/wrangler.example.toml +19 -0
  60. package/package.json +83 -0
  61. package/server/cdp-bridge.js +200 -0
  62. package/server/cli.js +1798 -0
  63. package/server/hub-server.js +258 -0
  64. package/server/install.js +250 -0
  65. package/server/mcp-server.js +504 -0
  66. package/server/npx-runner.js +96 -0
  67. package/server/relay-server.js +1356 -0
  68. package/server/remote-protocol.js +76 -0
  69. package/server/runtime-worker.js +166 -0
  70. package/server/script-runtime.js +189 -0
  71. package/server/sdk.js +307 -0
  72. package/server/service-state.js +103 -0
  73. package/server/snapshot.js +161 -0
  74. package/server/uninstall.js +61 -0
  75. package/server/windows-service-entry.js +58 -0
  76. package/server/windows-service.js +360 -0
  77. package/skills/browser-relay/SKILL.md +192 -0
  78. package/skills/browser-relay/references/legacy-api.md +163 -0
  79. package/skills/browser-relay/references/runtime.md +240 -0
@@ -0,0 +1,523 @@
1
+ # Browser Relay Remote Control Hub 架构与施工草案
2
+
3
+ > **已落地实现(2026-07)**:本文是最初的「方案 B」草案(本地 relay daemon 出站连 Hub)。**实际实现改为「方案 A」**——浏览器插件**直接**连 Hub,并在插件内用 `chrome.debugger` 自己执行命令,本地 relay daemon 不参与远程。Hub = Cloudflare Worker + Durable Object,`secretHash` **仅存内存、不落盘**(设备断开即随 DO 回收)。Capability 为紧凑的 `br-<secret>`(见下方「Capability 格式」)。下文的 daemon 出站流程仅作存档参考。
4
+
5
+ ## 目标
6
+
7
+ 把远程控制从“本地机器暴露 `0.0.0.0:18795` + HTTP token”改成“浏览器端授权 + 本地 daemon 出站连接 + Cloudflare Hub 转发”。
8
+
9
+ 核心原则:
10
+
11
+ - 默认本地控制不变:`browser-relay tabs` 仍然控制 `127.0.0.1:18795`。
12
+ - 浏览器插件是远程控制授权入口;CLI 不做 login、不注册设备。
13
+ - 用户在插件里显式打开 External Control,插件动态生成 capability-style `remote-device-id`。
14
+ - 本地 relay daemon 只监听本机,并主动通过 WSS 连接 Hub;不要求绑定 `0.0.0.0`,不要求路由器端口转发。
15
+ - CLI/MCP 只有传 `--remote-device-id` / `BROWSER_RELAY_REMOTE_DEVICE_ID` 时才走远程。
16
+ - Hub 可用默认官方服务,也必须支持用户一键部署到 Cloudflare Worker + Durable Object。
17
+
18
+ ---
19
+
20
+ ## 总体架构图
21
+
22
+ ```mermaid
23
+ flowchart LR
24
+ subgraph Local[目标机器:用户本地浏览器机器]
25
+ Browser[Chrome / Browser Tabs]
26
+ Ext[Browser Relay Extension\n- External Control 开关\n- 生成 remote-device-id\n- 显示复制命令\n- 撤销 / 重新生成]
27
+ Relay[Local Browser Relay Daemon\n127.0.0.1:18795 only\n现有 HTTP API + CDP bridge\n新增 remote outbound client]
28
+
29
+ Ext <-->|现有本地 /extension WebSocket| Relay
30
+ Relay <-->|CDP / chrome.debugger| Browser
31
+ Ext -->|POST /api/remote/enable\nhub + routeId + secret| Relay
32
+ end
33
+
34
+ subgraph CF[Cloudflare Remote Hub]
35
+ Worker[Cloudflare Worker\nHTTPS/WSS entry\nDeploy to CF]
36
+ DO[Durable Object per routeId\n- 保存在线 device socket\n- pending request map\n- token hash / metadata\n- timeout / offline handling]
37
+ Worker <-->|fetch / WebSocket upgrade| DO
38
+ end
39
+
40
+ subgraph Remote[远程机器 / Agent]
41
+ Agent[AI Agent / Human]
42
+ CLI[browser-relay CLI / MCP\n默认本地\n--remote-device-id 时远程]
43
+ Agent --> CLI
44
+ end
45
+
46
+ Relay ==>|出站 WSS,不开放本地端口| Worker
47
+ CLI ==>|HTTPS RPC\n--remote-device-id xxx\n--remote-host optional| Worker
48
+ DO ==>|request/response frames| Relay
49
+ ```
50
+
51
+ ---
52
+
53
+ ## 组件职责
54
+
55
+ | 组件 | 职责 | 明确不做 |
56
+ |---|---|---|
57
+ | Browser Extension | 用户打开/关闭远程控制;生成和保存 `remote-device-id`;把 hub/route/secret 下发给本地 daemon;显示复制命令和连接状态 | 不让 CLI login;不直接暴露本地端口 |
58
+ | Local Relay Daemon | 保持现有本地 HTTP API;保持 extension/CDP bridge;远程开启后主动连 Hub;把 Hub 转来的请求转发到本机 API | 不绑定公网;不实现账号系统 |
59
+ | Cloudflare Hub | Worker + Durable Object;接收 device 出站 WSS;接收 CLI HTTPS 请求;按 routeId 转发;返回结构化错误 | 不做浏览器自动化逻辑;MVP 不做用户账号 |
60
+ | CLI / MCP | 默认走本地;传 `--remote-device-id` 时解析 capability 并调用 Hub;`--remote-host` 可选 | 不 login;不注册设备;不保存用户账号 |
61
+
62
+ ---
63
+
64
+ ## 用户体验
65
+
66
+ ### 本地试用 MVP
67
+
68
+ 当前本地 MVP 先提供一个 Node 版 Hub,方便在 Cloudflare Worker 落地前跑通链路:
69
+
70
+ ```bash
71
+ # 终端 1:从当前 checkout 启动本地 hub
72
+ BROWSER_RELAY_HUB_PORT=18796 npm run hub
73
+
74
+ # 终端 2:启动/重启本地 relay
75
+ browser-relay restart
76
+ ```
77
+
78
+ 然后打开扩展 Options:
79
+
80
+ 1. `Remote Hub` 填 `http://127.0.0.1:18796`。
81
+ 2. 点击 `Enable External Control`。
82
+ 3. 复制生成的 `remote-device-id`。
83
+ 4. 在任意终端测试:
84
+
85
+ ```bash
86
+ node server/cli.js debug \
87
+ --remote-device-id brd1_xxx \
88
+ --remote-host http://127.0.0.1:18796 \
89
+ --json
90
+ ```
91
+
92
+ 这条链路已经不是直接打本地 relay 端口,而是:CLI -> Hub -> 本地 relay 出站 WSS -> 本地 API。
93
+
94
+ ### 本地模式,不变
95
+
96
+ ```bash
97
+ browser-relay tabs
98
+ browser-relay click '#submit'
99
+ browser-relay network --limit 50
100
+ ```
101
+
102
+ 默认仍然调用:
103
+
104
+ ```text
105
+ http://127.0.0.1:18795
106
+ ```
107
+
108
+ ### 开启远程控制
109
+
110
+ 用户在插件 popup/options 里操作:
111
+
112
+ ```text
113
+ External Control: Off
114
+ Remote Host: https://relay.linso.ai
115
+ [Enable External Control]
116
+ ```
117
+
118
+ 启用后插件生成高熵 capability,并显示:
119
+
120
+ ```text
121
+ External Control: On
122
+ Remote Device ID:
123
+ brd1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
124
+
125
+ Copy command:
126
+ browser-relay tabs --remote-device-id brd1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
127
+ ```
128
+
129
+ 自部署 Hub 时:
130
+
131
+ ```bash
132
+ browser-relay tabs \
133
+ --remote-device-id brd1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
134
+ --remote-host https://browser-relay-hub.username.workers.dev
135
+ ```
136
+
137
+ MCP 环境变量:
138
+
139
+ ```bash
140
+ BROWSER_RELAY_REMOTE_DEVICE_ID=brd1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
141
+ BROWSER_RELAY_REMOTE_HOST=https://browser-relay-hub.username.workers.dev
142
+ browser-relay-mcp
143
+ ```
144
+
145
+ ---
146
+
147
+ ## Capability 格式
148
+
149
+ `remote-device-id` 不是普通公开 ID,而是 capability。知道它的人就有控制权限,所以 UI 和文档都必须标注“像密码一样保管”。
150
+
151
+ 最终格式(已实现):
152
+
153
+ ```text
154
+ br-<secret>
155
+ ```
156
+
157
+ - `br`:版本前缀。
158
+ - `secret`:随机授权密钥(96-bit,base64url,16 字符),用于 device/CLI 鉴权。
159
+ - `routeId`(Worker 用来定位 Durable Object)**不放进 id**,而是从 secret 派生:`routeId = base64url(SHA-256(secret))` 取前 16 字符。CLI(Node crypto)与插件(SubtleCrypto)用同一算法派生,落到同一个 DO。
160
+
161
+ 于是整个 capability 只有约 19 字符,例如 `br-G1PMrqZmTckQP63P`。
162
+
163
+ Hub 只在**内存**里保存 `SHA-256(secret)`(设备在线期间),不存明文、不落盘 —— 设备断开、DO 回收即清空,不留僵尸路由。
164
+
165
+ ---
166
+
167
+ ## 远程启用流程
168
+
169
+ ```mermaid
170
+ sequenceDiagram
171
+ participant User as User
172
+ participant Ext as Browser Extension
173
+ participant Relay as Local Relay Daemon
174
+ participant Hub as CF Worker
175
+ participant DO as Durable Object
176
+
177
+ User->>Ext: Enable External Control
178
+ Ext->>Ext: generate routeId + secret
179
+ Ext->>Hub: WSS /v1/device/connect?routeId=...
180
+ Ext->>Hub: device.auth { secret }
181
+ Hub->>DO: route to DO(routeId)
182
+ DO->>DO: first-writer claim or verify secret hash
183
+ DO-->>Ext: device.authenticated
184
+ Ext->>Ext: send device.hello; mark connected
185
+ Ext-->>User: show remote-device-id and copy command
186
+ ```
187
+
188
+ 说明:
189
+
190
+ - 插件负责生成和保存 capability。
191
+ - daemon 负责维持出站 WSS;如果断线,daemon 自动重连。
192
+ - 如果 daemon 重启,插件可以在下次启动/keepalive 时重新下发 remote config;也可以让 daemon 把 remote config 存到用户本地配置文件。MVP 优先用 daemon 本地配置,插件禁用时调用 revoke/disable。
193
+
194
+ ---
195
+
196
+ ## 远程命令流程
197
+
198
+ ```mermaid
199
+ sequenceDiagram
200
+ participant CLI as Remote CLI / MCP
201
+ participant Worker as CF Worker
202
+ participant DO as Durable Object(routeId)
203
+ participant Relay as Target Local Relay
204
+ participant Ext as Browser Extension
205
+ participant Chrome as Chrome Tab
206
+
207
+ CLI->>Worker: POST /v1/rpc { routeId, method, path, body } + Authorization
208
+ Worker->>DO: forward RPC request
209
+ DO->>DO: verify secret hash, check device socket
210
+ DO->>Relay: rpc.request frame over WSS
211
+ Relay->>Relay: call local http://127.0.0.1:18795/api/...
212
+ Relay->>Ext: existing CDP command path when needed
213
+ Ext->>Chrome: chrome.debugger / CDP
214
+ Chrome-->>Ext: CDP result
215
+ Ext-->>Relay: result
216
+ Relay-->>DO: rpc.response frame
217
+ DO-->>Worker: response
218
+ Worker-->>CLI: HTTP response / structured error
219
+ ```
220
+
221
+ CLI 不需要打开本地 proxy,也不需要 login;每个命令就是一次 HTTPS RPC 到 Hub。之后如果需要长连接/流式日志,再加 WSS client 模式。
222
+
223
+ ---
224
+
225
+ ## Cloudflare Hub 形态
226
+
227
+ 目录建议:
228
+
229
+ ```text
230
+ hub/
231
+ package.json
232
+ wrangler.toml
233
+ src/
234
+ index.ts # Worker entry
235
+ device-object.ts # Durable Object
236
+ protocol.ts # frame/schema helpers
237
+ crypto.ts # hash / timing-safe compare / future E2EE helpers
238
+ README.md # self-host 部署说明
239
+ ```
240
+
241
+ Cloudflare 资源:
242
+
243
+ ```text
244
+ Worker
245
+ - GET / health / docs landing
246
+ - GET /v1/health JSON health
247
+ - GET /v1/device/connect WebSocket upgrade for local relay daemon
248
+ - POST /v1/rpc CLI/MCP request entry
249
+ - GET /v1/status/:routeId optional device online status
250
+
251
+ Durable Object
252
+ - one object per routeId: env.DEVICES.idFromName(routeId)
253
+ - holds current device WebSocket
254
+ - stores secret hash and metadata
255
+ - maps request id -> resolver
256
+ - enforces request timeout
257
+ ```
258
+
259
+ 一键部署按钮:
260
+
261
+ ```md
262
+ [![Deploy to Cloudflare](https://deploy.workers.cloudflare.com/button)](https://deploy.workers.cloudflare.com/?url=https://github.com/reliefeai/browser-relay/tree/main/hub)
263
+ ```
264
+
265
+ 自部署后,用户把 Worker URL 填入插件:
266
+
267
+ ```text
268
+ https://browser-relay-hub.username.workers.dev
269
+ ```
270
+
271
+ ---
272
+
273
+ ## 协议草案
274
+
275
+ ### Device connect
276
+
277
+ ```http
278
+ GET /v1/device/connect?routeId=<routeId>
279
+ Upgrade: websocket
280
+ ```
281
+
282
+ WebSocket 打开后,device 必须先发认证帧。secret 不进入 URL,避免被 CDN、代理或请求日志记录:
283
+
284
+ ```json
285
+ { "type": "device.auth", "secret": "..." }
286
+ ```
287
+
288
+ Hub 验证成功后回复:
289
+
290
+ ```json
291
+ { "type": "device.authenticated" }
292
+ ```
293
+
294
+ 只有收到认证成功帧后,device 才发 hello,并把连接标记为 connected:
295
+
296
+ ```json
297
+ {
298
+ "type": "device.hello",
299
+ "version": "1.0.17",
300
+ "routeId": "...",
301
+ "deviceName": "Liu's Mac",
302
+ "capabilities": ["tabs", "snapshot", "click", "type", "screenshot", "console", "network"]
303
+ }
304
+ ```
305
+
306
+ 认证前发送 `device.hello` 或 `rpc.response` 会被拒绝并关闭;未在限时内认证的连接也会关闭。Hub 为先部署兼容,暂时接受旧版 `?token=` 客户端;新扩展不保留查询参数回退。
307
+
308
+ ### CLI RPC
309
+
310
+ ```http
311
+ POST /v1/rpc
312
+ Authorization: Bearer <secret>
313
+ Content-Type: application/json
314
+ ```
315
+
316
+ ```json
317
+ {
318
+ "routeId": "...",
319
+ "id": "req_...",
320
+ "method": "GET",
321
+ "path": "/api/tabs",
322
+ "headers": {},
323
+ "body": null
324
+ }
325
+ ```
326
+
327
+ Hub 转发给 device:
328
+
329
+ ```json
330
+ {
331
+ "type": "rpc.request",
332
+ "id": "req_...",
333
+ "method": "GET",
334
+ "path": "/api/tabs",
335
+ "headers": {},
336
+ "body": null
337
+ }
338
+ ```
339
+
340
+ Device 返回:
341
+
342
+ ```json
343
+ {
344
+ "type": "rpc.response",
345
+ "id": "req_...",
346
+ "status": 200,
347
+ "headers": { "content-type": "application/json" },
348
+ "body": { "ok": true, "tabs": [] }
349
+ }
350
+ ```
351
+
352
+ ### 结构化错误
353
+
354
+ 设备离线:
355
+
356
+ ```json
357
+ {
358
+ "ok": false,
359
+ "code": "remote_device_offline",
360
+ "message": "Remote Browser Relay device is offline",
361
+ "status": 409,
362
+ "retryable": true
363
+ }
364
+ ```
365
+
366
+ capability 无效:
367
+
368
+ ```json
369
+ {
370
+ "ok": false,
371
+ "code": "invalid_remote_device",
372
+ "message": "Invalid or revoked remote device id",
373
+ "status": 401,
374
+ "retryable": false
375
+ }
376
+ ```
377
+
378
+ 远程超时:
379
+
380
+ ```json
381
+ {
382
+ "ok": false,
383
+ "code": "remote_request_timeout",
384
+ "message": "Remote device did not respond before timeout",
385
+ "status": 504,
386
+ "retryable": true
387
+ }
388
+ ```
389
+
390
+ ---
391
+
392
+ ## 安全边界
393
+
394
+ MVP 安全模型:
395
+
396
+ - 本地 relay 不暴露公网,只监听 `127.0.0.1`。
397
+ - 本地 daemon 主动出站连接 Hub,使用 WSS/HTTPS。
398
+ - `remote-device-id` 是 capability,必须高熵、可撤销、可重新生成。
399
+ - Hub 不存明文 secret,只存 hash。
400
+ - Hub 认证时重新派生并验证 `routeId === base64url(SHA-256(secret)).slice(0,16)`;仅知道 routeId 不能抢占离线设备。
401
+ - 认证失败响应与日志不得包含 secret。
402
+ - CLI 不保存账号态;有 capability 才能控制。
403
+ - 插件 UI 必须提供 Disable / Regenerate。
404
+
405
+ MVP 仍然是 trusted Hub:
406
+
407
+ - 自部署 Cloudflare Hub:用户信任自己的 Worker。
408
+ - 官方默认 Hub:MVP 可先跑通,但隐私上不完美;后续应做 E2EE blind relay。
409
+
410
+ 后续 E2EE 方向:
411
+
412
+ - `secret` 派生两类 key:auth proof key + payload encryption key。
413
+ - Hub 只看 `routeId`、请求 id、长度、时间;看不到 `/api/snapshot`、screenshot、console/network 内容。
414
+ - Worker 只做密文转发,device 和 CLI 端到端加密 request/response payload。
415
+
416
+ ---
417
+
418
+ ## 简略施工计划
419
+
420
+ ### Phase 0:协议和文档落地
421
+
422
+ - 新增本文档。
423
+ - 把 Issue #3 从“公网 token 鉴权”改为“Remote Control Hub / no local port exposure”。
424
+ - 明确不做 CLI login、不要求用户绑定 `0.0.0.0`。
425
+
426
+ ### Phase 1:Cloudflare Hub MVP
427
+
428
+ 实现 `hub/`:
429
+
430
+ - Worker entry:health、device connect、RPC entry。
431
+ - Durable Object:保存在线 device socket、secret hash、pending requests。
432
+ - `wrangler.toml` + DO migration。
433
+ - 一键部署按钮文档。
434
+ - 单元测试:
435
+ - device connect first claim。
436
+ - wrong secret rejected。
437
+ - CLI RPC when device offline returns `remote_device_offline`。
438
+ - CLI RPC routes to live device and returns response。
439
+ - timeout returns `remote_request_timeout`。
440
+
441
+ ### Phase 2:Local Relay remote outbound client
442
+
443
+ 改 `server/relay-server.js`:
444
+
445
+ - 新增 `/api/remote/enable`、`/api/remote/disable`、`/api/remote/status`。
446
+ - remote enable 后建立 outbound WSS 到 Hub。
447
+ - 收到 `rpc.request` 后,调用本机现有 HTTP API 路由并返回 `rpc.response`。
448
+ - 自动重连、心跳、状态记录。
449
+ - 禁用时关闭 WSS 并清理本地配置。
450
+
451
+ 测试:
452
+
453
+ - fake Hub WebSocket 下发 `/api/tabs`,local relay 返回真实 API 结果。
454
+ - disable 后 WSS 关闭,status 显示 off。
455
+ - Hub 断线后自动重连。
456
+
457
+ ### Phase 3:Extension UI 授权入口
458
+
459
+ 改 extension popup/options:
460
+
461
+ - 增加 External Control 区块。
462
+ - Remote Host 输入框,默认官方 Hub。
463
+ - Enable 时生成 `routeId` + `secret`,调用本地 `/api/remote/enable`。
464
+ - 显示 `remote-device-id` 和复制命令。
465
+ - Disable / Regenerate。
466
+ - 显示 online/offline 和 active session 简略状态。
467
+
468
+ 测试:
469
+
470
+ - options/popup 源码静态测试:确保生成 capability、调用 `/api/remote/enable`,不出现 CLI login 文案。
471
+ - 手工浏览器验证:开关、复制命令、禁用撤销。
472
+
473
+ ### Phase 4:CLI / MCP remote flags
474
+
475
+ 改 `server/cli.js`:
476
+
477
+ - 全局参数:
478
+ - `--remote-device-id <brd1_...>`
479
+ - `--remote-host <url>` optional,默认官方 Hub。
480
+ - 环境变量:
481
+ - `BROWSER_RELAY_REMOTE_DEVICE_ID`
482
+ - `BROWSER_RELAY_REMOTE_HOST`
483
+ - 当 remote-device-id 存在时,`relayRequest` 走 Hub `/v1/rpc`;否则保持本地 `RELAY_URL`。
484
+ - CLI help 里说明 capability 是 secret。
485
+
486
+ 改 `server/mcp-server.js`:
487
+
488
+ - 读取同样环境变量。
489
+ - remote 模式下所有工具通过 Hub RPC。
490
+
491
+ 测试:
492
+
493
+ - 未传 remote-device-id 时仍调用本地。
494
+ - 传 remote-device-id 时请求 Hub,method/path/body 正确。
495
+ - remote structured error 在 CLI `--json` 和 MCP `isError` 中保留。
496
+
497
+ ### Phase 5:README / 中文 README / bundled skill
498
+
499
+ 更新:
500
+
501
+ - 本地模式不变。
502
+ - 远程模式推荐流程:插件启用 -> 复制 command -> CLI 使用。
503
+ - Cloudflare 一键部署。
504
+ - `remote-device-id` 安全说明。
505
+ - 不推荐 `0.0.0.0` 裸暴露。
506
+
507
+ ### Phase 6:E2EE blind relay
508
+
509
+ - 定义 `brd2_` capability 格式。
510
+ - CLI 和 local relay 使用 WebCrypto / Node crypto 派生 key。
511
+ - Hub 只路由密文 envelope。
512
+ - 增加兼容:`brd1_` trusted hub,`brd2_` E2EE hub。
513
+
514
+ ---
515
+
516
+ ## 不做项
517
+
518
+ - 不做 CLI login。
519
+ - 不做账号系统作为 MVP 前置条件。
520
+ - 不做公网 HTTP 直连本地 relay。
521
+ - 不做 lightweight locator。
522
+ - 不在第一版做复杂权限 scope;先以 capability + 浏览器显式开关 + revoke/regenerate 保证闭环。
523
+ - 不把 Cloudflare Hub 写死;默认 host 可用,但 self-host 必须是一等路径。