codex@macbookpro
·
2026-04-01
README.md
1# BAA Firefox
2
3Firefox 插件的正式能力已经收口到四件事:
4
5- 为 Claude / ChatGPT / Gemini 维持单个平台单空壳页
6- 向本地 `conductor` 上报登录态元数据
7- 在浏览器本地持有原始凭证并代发 API 请求
8- 在 Claude / ChatGPT / Gemini 上观察最终 assistant message,并通过 `browser.final_message` 做 raw relay
9
10另有一条受限的 thin-plugin delivery 附属能力:
11
12- 对 `Claude` / `ChatGPT` / `Gemini` 提供 DOM adapter 方式的 text-only `inject_message` / `send_message`
13- adapter 会把平台选择器、page readiness、重试和 fail-closed 错误收口到统一模块;Gemini 同时兼容 `rich-text-field` / `rich-textarea` 的 Quill composer 变体
14- 这不是通用浏览器自动化框架
15
16页面对话 UI、会话回读和 DOM 自动化仍然不是正式主能力。`browser.final_message` 只负责最终文本转发,不负责 BAA parser;delivery adapter 只服务 text-only delivery 的最小执行面。
17
18## 当前默认连接
19
20- 本地 WS bridge:`ws://100.71.210.78:4317/ws/firefox`
21- 本地 HTTP 入口:`http://100.71.210.78:4317`
22
23管理页只保留:
24
25- 本地 WS 状态
26- 本地 HTTP 状态
27- 空壳页 / 账号 / 登录态指纹 / 端点元数据概览
28- `Pause` / `Resume` / `Drain`
29
30## 空壳页模式
31
32每个平台最多保留一个专用 shell tab:
33
34- Claude:`https://claude.ai/#baa-shell`
35- ChatGPT:`https://chatgpt.com/#baa-shell`
36- Gemini:`https://gemini.google.com/#baa-shell`
37
38这些标签页只是登录环境和同源请求壳,不再承载业务会话语义。
39
40插件行为:
41
42- 只把带 `#baa-shell` 的平台页认作正式 bridge 壳页
43- 如果壳页被导航到其他业务 URL,插件会把它从正式能力里摘掉
44- 需要代理请求时,插件会优先复用或重新收口到对应平台的壳页
45
46## Runtime 模型
47
48插件现在把壳页状态拆成两层:
49
50- `desired`:这个平台是否应该保有一个正式 shell tab
51- `actual`:浏览器里当前真实存在的 shell tab 状态
52
53默认行为:
54
55- `tab_open` / `tab_focus` / `tab_reload` 会把对应平台写进 `desired`
56- `tab_restore` 只会恢复 `desired=true` 但 `actual` 缺失的平台
57- 插件管理页启动、浏览器重开或扩展重载后,会自动对之前明确启用过、但当前缺失的 shell tab 做一次后台恢复
58- 如果手工打开 Claude `new`、ChatGPT 根页或 Gemini `app` 这类平台根页,插件也会把它们收进受管理 shell 集合
59- tab 生命周期事件和 `30s` 周期巡检都会刷新 `actual`
60- 管理页的“空壳页”和“平台状态”面板会直接显示 `desired / actual / drift`
61
62## 插件管理动作
63
64控制器页内部统一支持这些动作:
65
66- `plugin_status`
67- `ws_reconnect`
68- `controller_reload`
69- `tab_open`
70- `tab_focus`
71- `tab_reload`
72- `tab_restore`
73
74除了 legacy `open_tab` / `reload` WS 消息外,也可以通过扩展内消息调用:
75
76```js
77browser.runtime.sendMessage({
78 type: "plugin_runtime_action",
79 action: "tab_restore",
80 platform: "claude"
81});
82```
83
84通过本地 WS 接到正式管理动作时,插件还会回传结构化 `action_result`,至少包含:
85
86- `accepted`
87- `completed`
88- `failed`
89- `reason`
90- `results`
91- `shell_runtime`
92
93读取当前 runtime:
94
95```js
96browser.runtime.sendMessage({
97 type: "get_plugin_runtime_status"
98});
99```
100
101`ws_reconnect` 支持额外测试参数:
102
103- `disconnectMs` / `disconnect_ms` / `delayMs` / `delay_ms`
104- `repeatCount` / `repeat_count`
105- `repeatIntervalMs` / `repeat_interval_ms` / `intervalMs` / `interval_ms`
106
107例如:
108
109```js
110browser.runtime.sendMessage({
111 type: "plugin_runtime_action",
112 action: "ws_reconnect",
113 disconnectMs: 3000,
114 repeatCount: 3,
115 repeatIntervalMs: 500
116});
117```
118
119## 上报的元数据
120
121插件会通过本地 WS 发送:
122
123- `platform`
124- `account`
125- `credential_fingerprint`
126- `freshness`
127- `captured_at`
128- `last_seen_at`
129- `shell_runtime`
130- `endpoints`
131- `endpoint_metadata`
132
133其中:
134
135- `account` 是尽力识别出的账号标识,优先 email,其次平台侧账号 hint
136- `credential_fingerprint` 是浏览器本地从真实凭证计算的不可逆摘要
137- `endpoint_metadata` 包含方法、归一化路径、首次观测时间、最近观测时间
138
139为兼容现有 bridge 汇总,`credentials` 消息仍会带一个 `headers` 对象,但值全部是脱敏占位符,只用于保留 header 名称和数量,不包含原始值。
140
141`shell_runtime` 里会带每个平台的:
142
143- `desired`
144- `actual`
145- `drift`
146
147当前 `conductor` 已消费这部分字段,并会把它暴露到 `GET /v1/browser` 和最近一次 `action_result` 读面。
148
149## 明确不上报的敏感值
150
151以下内容仍只允许停留在浏览器本地,不通过 bridge 回传给 `conductor`:
152
153- 原始 `cookie`
154- 原始 `authorization` / `token`
155- 原始 header 值
156- 页面 UI 状态
157
158补充:
159
160- 插件会 live 发送 `browser.final_message.raw_text`
161- 这层只保留最终 assistant message 原文,不上传中间 stream chunk
162- Claude final-message 会优先使用 `completion` SSE 片段;如果上游改成 `content_block_delta.text_delta`,会自动走 text-delta fallback,并继续忽略 `thinking` / 协议元数据
163- 当前服务端只做接收和最近快照保留,不把它写进现有浏览器元数据持久化表
164
165`network_log` / `sse_event` 这类诊断路径不再向 WS 回传请求头值。
166
167## 浏览器本地代发边界
168
169插件仍然会在本地保存最近一次可用的原始请求头快照,用于:
170
171- Claude 同源 API 代发
172- ChatGPT 同源 API 代发
173- Gemini 基于持久化 shell / conversation 发送模板的本地代发
174
175这些原始值只在浏览器内部使用,不进入 `conductor` 的 WS 元数据上报。
176
177## How To Load
178
1791. Open Firefox.
1802. Visit `about:debugging#/runtime/this-firefox`.
1813. Click `Load Temporary Add-on...`.
1824. Choose [manifest.json](/Users/george/code/baa-conductor/plugins/baa-firefox/manifest.json).
1835. Firefox should open `controller.html` automatically.
184
185## How To Run
186
1871. Load this extension temporarily.
1882. Make sure local `conductor-daemon` is listening on `http://100.71.210.78:4317`.
1893. Open `controller.html` and confirm:
190 - `本地 WS` becomes `已连接`
191 - `本地 HTTP` reaches `已连接` or enters visible auto-retry
1924. Let the plugin open or refocus the shell tab for the target platform.
1935. Sign in on that shell tab if needed.
1946. Wait for the management page to show account / fingerprint / endpoint metadata.
195
196## Verification
197
198- WS connect: controller page shows `本地 WS = 已连接`
199- HTTP sync: controller page shows `本地 HTTP = 已连接` or visible retry
200- Shell tabs: platform cards show the dedicated shell tabs instead of arbitrary business tabs
201- Metadata: account / fingerprint / endpoint panels populate without exposing raw header values
202- `GET /v1/browser`: merged record shows `view` / `status` and does not expose raw credential values
203- Disconnect / aging: persisted record remains readable after disconnect and later changes `fresh -> stale -> lost`
204- Proxying: server-initiated `api_request`、`request_cancel` 和 SSE `stream_*` 仍会通过 shell tab 完成
205
206## Conductor 对接现状
207
208- `GET /v1/browser` 已经会合并活跃 bridge 和持久化记录,并返回 `view`、`status`、`account`、凭证指纹和端点元数据
209- client 断连或长时间老化后,持久化记录仍可读取,但状态会转成 `stale` / `lost`
210- 当前正式浏览器写接口已经收口到 `POST /v1/browser/actions`、`POST /v1/browser/request`、`POST /v1/browser/request/cancel`
211- `/v1/browser/{claude,chatgpt,gemini}/*` 保留给 helper / legacy 包装与辅助回读