- commit
- 41a4dc3
- parent
- fe001a6
- author
- im_wower
- date
- 2026-03-24 10:58:21 +0800 CST
chore: move desktop bugs and browser-control tasks into coordination/ Move from Desktop to version-controlled coordination/ directory: - bugs/ -> coordination/bugs/ (BUG-008, BUG-009, BUG-010 + FIX cards) - baa-conductor-browser-control-tasks/ -> coordination/tasks/browser-control/ Also rename BUG-009 codexd turn status bug to BUG-010 to avoid collision with BUG-009 conductor-daemon test listener leak.
12 files changed,
+1040,
-0
1@@ -0,0 +1,99 @@
2+# BUG-008: codexd 第二个 session/thread 发 turn 后 app-server 响应超时,反复 reconnect 直至 failed
3+
4+## 现象
5+
6+向 codexd 创建第一个 session 并发 turn,成功完成(turn.completed)。
7+
8+创建第二个 session(新 threadId)并发 turn,消息被 app-server 接收(item/started + item/completed),但此后等待响应时超时,触发 Reconnecting... N/5,最终 failed。
9+
10+第一次 turn 的完整回复已在 events.jsonl 里出现(seq 55,agentMessage 完整),证明链路本身通;第二次 turn 卡在等 app-server 返回内容阶段。
11+
12+## 触发路径
13+
14+```text
15+POST /v1/codexd/sessions -> session A (thread A) 创建成功
16+POST /v1/codexd/turn -> turn 成功,Codex 回复,turn.completed
17+
18+POST /v1/codexd/sessions -> session B (thread B) 创建成功
19+POST /v1/codexd/turn -> item/started + item/completed(消息已发)
20+ -> 等待 ~30s
21+ -> Reconnecting... 2/5
22+ -> Reconnecting... 3/5 ...
23+ -> Reconnecting... 5/5
24+ -> lastTurnStatus: failed
25+```
26+
27+## 根因
28+
29+当前判断(未完全确认):
30+
31+codex app-server 是单进程,内部以 thread 为单位管理会话。第一个 thread idle 后,第二个 thread 发起 turn 时,app-server 内部可能出现:
32+
33+- 旧 thread 未完全 idle,新 thread 的响应流被阻塞
34+- app-server 在处理第二个 thread 时内部状态机卡住,不产出 output token,导致 codexd 侧等待超时
35+- timeout waiting for child process to exit 说明 codexd 等 app-server 子进程退出时超时,但子进程实际未退出(child.status: running),可能是 codexd 的生命周期管理和 app-server 的 thread 模型存在错配
36+
37+仍需验证的点:
38+- 重启 codexd 后只建一个 session 是否稳定复现成功
39+- 两个 session 复用同一个 threadId 是否能规避
40+- app-server stdout 里是否有内容但 codexd 未读到
41+
42+## 复现步骤
43+
44+```bash
45+# 1. 创建 session A,发 turn,等 turn.completed
46+curl -X POST http://127.0.0.1:4319/v1/codexd/sessions \
47+ -H 'Content-Type: application/json' \
48+ -d '{"purpose":"duplex"}'
49+
50+curl -X POST http://127.0.0.1:4319/v1/codexd/turn \
51+ -H 'Content-Type: application/json' \
52+ -d '{"sessionId":"<sessionId_A>","input":"你是谁?"}'
53+
54+# 等 turn.completed 后,创建 session B
55+curl -X POST http://127.0.0.1:4319/v1/codexd/sessions \
56+ -H 'Content-Type: application/json' \
57+ -d '{"purpose":"duplex"}'
58+
59+curl -X POST http://127.0.0.1:4319/v1/codexd/turn \
60+ -H 'Content-Type: application/json' \
61+ -d '{"sessionId":"<sessionId_B>","input":"1+1等于几?"}'
62+
63+# 轮询,预期出现 lastTurnStatus: failed + Reconnecting... N/5
64+curl http://127.0.0.1:4319/v1/codexd/sessions/<sessionId_B>
65+```
66+
67+## 当前影响
68+
69+- 单次会话(只建一个 session)可以正常完成,链路通
70+- 多 session 场景(顺序创建多个 thread)大概率失败
71+- 影响 codexd 作为 duplex 对话代理的实用性,每次对话理论上都会建新 session/thread
72+
73+## 修复建议
74+
75+### 方案 A(推荐调查方向):复用已有 thread,不每次新建
76+
77+如果 app-server 单进程内多 thread 存在状态竞争,先在 codexd 里改为默认复用同一个 thread,通过 turn 的上下文区分会话,而不是每个 session 建独立 thread。
78+
79+### 方案 B:session 结束时显式关闭 thread
80+
81+在创建新 session 前,先对旧 session 发 close,确保 app-server 内旧 thread 完全 idle 后再启动新 thread。
82+
83+### 方案 C:检查 codexd 读取 app-server stdout 的逻辑
84+
85+timeout waiting for child process to exit 可能是 codexd 误认为子进程已退出。检查 app-server-transport.ts 里 onClose 的触发条件,确认是否在第二个 thread 上错误触发了关闭逻辑。
86+
87+## 严重程度
88+
89+High —— 单次对话能通,但多轮/多 session 场景(即 duplex 核心用法)无法稳定工作。
90+
91+## 发现时间
92+
93+2026-03-23 by Claude
94+
95+## 备注
96+
97+- events.jsonl seq 55 完整记录了第一次 turn 的回复,Codex 回复内容:「我是 Codex,一个在你的工作区里直接读代码、改代码、跑命令并帮你解决工程问题的 AI 编程助手。」
98+- seq 59 turn.completed 出现,第一次链路完全通
99+- 第二次失败的 error detail: codexErrorInfo.responseStreamDisconnected.httpStatusCode = null,additionalDetails = "timeout waiting for child process to exit"
100+- child 进程(PID 20904)在失败后仍处于 running 状态,不是 crash
1@@ -0,0 +1,123 @@
2+# BUG-009: conductor-daemon 的 `index.test.js` 会遗留本地 HTTP listener,导致 `node --test` 长时间不退出
3+
4+## 现象
5+
6+运行:
7+
8+```bash
9+cd /Users/george/code/baa-conductor
10+node --test apps/conductor-daemon/src/index.test.js
11+```
12+
13+测试进程可能长时间不退出,父进程会一直挂在 `node --test` 上。
14+
15+现场检查时可观察到:
16+
17+- 子进程仍在监听随机本地端口;本次现场是 `127.0.0.1:61147`
18+- `curl http://127.0.0.1:61147/healthz` 返回 `ok`
19+- `curl http://127.0.0.1:61147/v1/system/state` 还能读到测试写入的状态,包含 `requested_by: "integration_test"`
20+- Node 采样显示主线程在 `libuv` 的 `kevent` 里睡眠,不是忙等
21+- Node 诊断报告只剩一个被引用的 libuv `tcp` handle:监听 `127.0.0.1:61147`
22+
23+这说明不是 Node 自身卡死,而是测试遗留了本地 HTTP server,事件循环一直不空。
24+
25+## 触发路径
26+
27+```text
28+node --test apps/conductor-daemon/src/index.test.js
29+-> 最后一个测试:
30+ "ConductorRuntime exposes a local Firefox websocket bridge over the local API listener"
31+-> runtime.start() 启动本地 HTTP listener + Firefox WS bridge
32+-> 测试流程在清理前异常 / 卡住
33+-> runtime.stop() 与 rmSync(...) 没执行
34+-> 本地 listener 残留
35+-> 因为 test runner 带了 --test-timeout=0,进程可一直挂住
36+```
37+
38+## 根因
39+
40+当前判断基本明确:
41+
42+- 最后一个测试位于 `/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.test.js:1671`
43+- 该测试的清理逻辑是顺序写在测试尾部的,不在 `try/finally` 里
44+- 只要在 `waitForWebSocketOpen`、`queue.next(...)`、`fetch(...)`、`socket.close(...)`、`runtime.stop()` 之前任一处卡住或抛错,清理就不会执行
45+- 清理没执行时,`ConductorRuntime` 起的本地 HTTP server 会继续监听随机端口
46+- 现场对 `73386` 发送 `SIGUSR2` 后生成的诊断报告:
47+ `/Users/george/code/baa-conductor/report.20260323.231806.73386.0.001.json`
48+ 其中唯一仍被 `ref` 住的有效 libuv handle 是监听 `127.0.0.1:61147` 的 `tcp` handle
49+
50+仍需补的确认点:
51+
52+- 是测试里某个 `await queue.next(...)` 真正超时未返回,还是某次断言失败后直接跳过清理
53+- 是否只有最后一个 Firefox WS 测试缺 `finally`,还是同文件里其它起 server 的测试也需要统一收口
54+
55+## 复现步骤
56+
57+```bash
58+cd /Users/george/code/baa-conductor
59+
60+node --test apps/conductor-daemon/src/index.test.js
61+
62+# 另开一个终端,找出残留 listener
63+lsof -nP -iTCP -sTCP:LISTEN | rg 'node'
64+
65+# 如果测试挂住,随机端口还能回 healthz
66+curl -sS http://127.0.0.1:<port>/healthz
67+
68+# 打诊断报告,确认 libuv 剩余句柄
69+kill -USR2 <child_node_pid>
70+jq '.libuv' /Users/george/code/baa-conductor/report.*.<child_node_pid>.*.json
71+```
72+
73+## 当前影响
74+
75+- 影响 `apps/conductor-daemon/src/index.test.js` 的本地测试稳定性
76+- 会把发起测试的上层 `codex` / shell 会话一起挂住,形成看似“父进程卡死”的现象
77+- 会在本机留下随机本地端口 listener,干扰后续排障
78+- 当前证据指向测试/清理路径问题,不指向线上 `conductor-daemon` 主服务逻辑
79+
80+## 修复建议
81+
82+### 方案 A(推荐)
83+
84+把 `/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.test.js:1671` 这个测试改成严格的 `try/finally` 收口:
85+
86+- `runtime.start()` 后立即建立清理责任
87+- `finally` 里无条件执行 `queue.stop()`、`socket.close(...)`、`await runtime.stop()`、`rmSync(...)`
88+- `socket.close(...)` 最好等待 `close` 事件或至少做好幂等清理
89+
90+### 方案 B
91+
92+给所有会起本地 HTTP server / WebSocket server 的测试加统一 helper,例如:
93+
94+- `withRuntimeFixture(...)`
95+- helper 内部统一 `start/stop/cleanup`
96+
97+这样可以避免单个测试遗漏收尾。
98+
99+### 方案 C
100+
101+给相关测试补一个更短的 fail-fast 超时,而不是完全依赖 `--test-timeout=0`。
102+
103+即使清理再漏,测试也不会无限挂住。
104+
105+## 严重程度
106+
107+Medium
108+
109+原因:
110+
111+- 不直接影响线上 `conductor-daemon` 服务
112+- 但会稳定破坏本地测试和 agent 会话,且不加人工干预就可能无限挂住
113+
114+## 发现时间
115+
116+2026-03-23 by Codex
117+
118+## 备注
119+
120+- 现场残留端口是 `127.0.0.1:61147`
121+- 残留状态里可读到:
122+ - `mode: "paused"`
123+ - `requested_by: "integration_test"`
124+- 这与测试 `/Users/george/code/baa-conductor/apps/conductor-daemon/src/index.test.js:1671` 的行为一致
1@@ -0,0 +1,108 @@
2+# BUG-010: codexd turn 状态停留在 inProgress,未更新为 completed
3+
4+## 现象
5+
6+向 codexd 提交 turn 后,Codex 实际上已经产出完整回复(agentMessage 在 events.jsonl 中有记录),但 session 的 `lastTurnStatus` 始终停留在 `inProgress`,不更新为 `completed`。
7+
8+同时 recentEvents 里出现 `Reconnecting... N/5`,最终 turn 被标记为 `failed` 或一直挂着。
9+
10+已确认的 agentMessage(通过 events.jsonl 直接读取):
11+- "可以,我现在能稳定工作。"
12+- "1+1等于2。"
13+- 其他多条完整回复
14+
15+说明 Codex 子进程正常生成了答案,问题在 codexd 的状态回传链路上。
16+
17+## 触发路径
18+
19+```text
20+POST /v1/codex/turn { sessionId, input }
21+-> accepted: true,turnId 返回
22+-> app-server.turn.started 事件出现
23+-> Codex 产出 agentMessage(item/completed 事件记录到 events.jsonl)
24+-> Reconnecting... 2/5 开始出现
25+-> turn 状态卡在 inProgress(未收到 completed 信号)
26+-> 轮询 GET /v1/codex/sessions/:id 永远看到 lastTurnStatus: inProgress
27+```
28+
29+## 根因
30+
31+当前判断(未完全确认):
32+
33+codex app-server 通过 stdio 和 codexd 通信。Codex 产出回复后,app-server 需要发送 turn 完成的通知(如 `thread/turn/completed` 或类似事件),codexd 收到后才更新 session 状态。
34+
35+`Reconnecting... N/5` + `responseStreamDisconnected` + `timeout waiting for child process to exit` 说明 codexd 在等待 app-server 发送完成信号时,stdio 流断开了或子进程退出了,导致:
36+
37+1. codexd 未收到 turn completed 通知
38+2. session 状态停在 inProgress
39+3. codexd 尝试重连 app-server,但 turn 的完成状态已经丢失
40+
41+agentMessage 能写入 events.jsonl,说明内容已经流过来了,但后续的 turn 完成握手没有成功完成。
42+
43+仍需验证:
44+- app-server 是否发出了 turn/completed 事件
45+- codexd 的 app-server-transport.ts 是否在 stdio 关闭时提前触发了 onClose
46+- 重连后 codexd 是否尝试恢复 turn 状态
47+
48+## 复现步骤
49+
50+```bash
51+# 1. 创建 session
52+curl -s -X POST https://conductor.makefile.so/v1/codex/sessions \
53+ -H 'Content-Type: application/json' \
54+ -H 'Authorization: Bearer <TOKEN>' \
55+ -d '{"purpose":"duplex"}'
56+# 记录 sessionId
57+
58+# 2. 发 turn
59+curl -s -X POST https://conductor.makefile.so/v1/codex/turn \
60+ -H 'Content-Type: application/json' \
61+ -H 'Authorization: Bearer <TOKEN>' \
62+ -d '{"sessionId":"<sessionId>","input":"你好,用一句话介绍自己"}'
63+
64+# 3. 持续轮询 session 状态(等 60s+)
65+curl -s https://conductor.makefile.so/v1/codex/sessions/<sessionId> \
66+ -H 'Authorization: Bearer <TOKEN>'
67+# 预期 lastTurnStatus 卡在 inProgress 或变成 failed
68+
69+# 4. 直接读 events.jsonl 验证 Codex 实际已回复
70+grep agentMessage /Users/george/code/baa-conductor/logs/codexd/codexd/events.jsonl \
71+ | python3 -c "import sys,json; [print(json.loads(l)['detail']['params']['item']['text']) for l in sys.stdin]"
72+# 预期:能看到完整回复内容,证明 Codex 已经回答了
73+```
74+
75+## 当前影响
76+
77+High —— 虽然 Codex 能正常回答,但调用方(conductor / AI caller)无法通过 session 状态 API 得知 turn 已完成,导致:
78+
79+- 轮询永远得不到 completed 信号
80+- 回复内容只能通过绕路读 events.jsonl 获取,无法走正式 API
81+- conductor 的任务编排无法基于 turn 完成事件触发后续动作
82+
83+## 修复建议
84+
85+### 方案 A(推荐调查方向):检查 app-server-transport.ts 的 onClose 时机
86+
87+确认 stdio 流在 Codex 回复完成后是否提前触发了关闭,导致 codexd 认为连接断开而未处理 turn/completed 事件。
88+
89+### 方案 B:在 codexd daemon 里增加 turn 超时完成兜底
90+
91+如果检测到 agentMessage 的 item/completed 事件已经收到,但 turn 状态还未更新,超过一定时间后主动将 turn 标记为 completed。
92+
93+### 方案 C:在重连逻辑里恢复 turn 状态
94+
95+重连成功后,检查是否有已收到完整内容但未完成的 turn,主动将其推进到 completed。
96+
97+## 严重程度
98+
99+High —— 核心链路(发消息 → 得到完成状态)不通,调用方无法可靠地知道 Codex 什么时候回复完了。
100+
101+## 发现时间
102+
103+2026-03-24 by Claude
104+
105+## 备注
106+
107+- BUG-008 和本 bug 密切相关,BUG-008 描述的是多 session 失败,本 bug 更精确地定位到:即使单 session 也存在 turn 状态不更新的问题
108+- events.jsonl 里已确认的完整 agentMessage:「可以,我现在能稳定工作。」,对应 turn 019d1b95-b947-72c1-b6c2-02ee0a56202e
109+- lastTurnStatus 可能的值:inProgress / completed / failed;问题是 completed 从未出现
+98,
-0
1@@ -0,0 +1,98 @@
2+# BUG-XXX: 简短标题
3+
4+## 现象
5+
6+清楚描述可观察到的问题现象。
7+
8+建议包含:
9+
10+- 哪个接口 / 页面 / 脚本出问题
11+- 返回了什么
12+- 预期应该是什么
13+- 是否稳定复现
14+
15+## 触发路径
16+
17+写清楚最短触发链路,例如:
18+
19+```text
20+POST /v1/exec
21+-> 某个 shell 命令
22+-> 某个脚本
23+-> 失败 / 超时 / 错误返回
24+```
25+
26+## 根因
27+
28+如果已经确认根因,就直接写。
29+
30+如果还没完全确认,可以写:
31+
32+- 当前判断
33+- 高概率根因
34+- 仍需验证的点
35+
36+## 复现步骤
37+
38+给出别人可以直接照抄的最小复现步骤。
39+
40+示例:
41+
42+```bash
43+curl -s http://100.71.210.78:4317/some/endpoint \
44+ -X POST \
45+ -H 'Content-Type: application/json' \
46+ -d '{"foo":"bar"}'
47+```
48+
49+## 当前影响
50+
51+写清楚影响面:
52+
53+- 是否影响主流程
54+- 是否只影响某类目录 / 某类脚本 / 某个页面
55+- 是完全不可用还是降级可用
56+
57+## 修复建议
58+
59+如果已经有候选方案,按顺序写:
60+
61+### 方案 A(推荐)
62+
63+写最直接、最建议的修法。
64+
65+### 方案 B
66+
67+写备选方案。
68+
69+### 方案 C
70+
71+如果有额外兜底方案再写。
72+
73+## 严重程度
74+
75+从下面选一个,并简单解释:
76+
77+- Low
78+- Medium
79+- High
80+
81+## 发现时间
82+
83+格式建议:
84+
85+`YYYY-MM-DD by <发现者>`
86+
87+例如:
88+
89+`2026-03-22 by Codex`
90+
91+## 备注
92+
93+可选。
94+
95+写一些不适合放在上面结构里的补充信息,例如:
96+
97+- 临时绕过方式
98+- 是否已经在线上观察到
99+- 是否已有相关日志文件
+79,
-0
1@@ -0,0 +1,79 @@
2+# FIX-BUG-008
3+
4+```text
5+你在仓库 /Users/george/code/baa-conductor 工作。
6+
7+必须从当前 main 基线开始:main@02b3d6a。
8+不要从其他任务分支切出。
9+如果本地已有旧 worktree/分支,不要复用,重新从 main 建干净 worktree。
10+
11+任务:修复 codexd 在第二个 session/thread 上发 turn 容易超时并反复 reconnect 的问题
12+建议分支:fix/codexd-second-thread-timeout
13+
14+先读:
15+1. /Users/george/Desktop/bugs/BUG-008-codexd-second-thread-turn-timeout.md
16+2. /Users/george/code/baa-conductor/apps/codexd/src/daemon.ts
17+3. /Users/george/code/baa-conductor/apps/codexd/src/app-server-transport.ts
18+4. /Users/george/code/baa-conductor/packages/codex-app-server/src/*
19+5. /Users/george/code/baa-conductor/docs/runtime/codexd.md
20+
21+背景:
22+- 现在第一个 session/thread 的 turn 能成功完成
23+- 第二个新 session/thread 的 turn 容易卡住
24+- 之后会进入 reconnect,最终 failed
25+- 这直接破坏 codexd 作为 duplex 多会话代理的核心能力
26+
27+目标:
28+- 让 codexd 在同一个独立 app-server child 上,顺序处理多个 session/thread 的 turn 时稳定工作
29+- 至少修到:
30+ - 第一轮 session 正常
31+ - 第二轮新 session 也能正常完成 turn
32+ - 不再出现“第二个 thread 稳定失败”的模式
33+
34+要求:
35+- 只在这些范围内工作:
36+ - apps/codexd/**
37+ - packages/codex-app-server/**
38+ - docs/runtime/**
39+- 不要修改 apps/conductor-daemon/**
40+- 不要恢复 codex exec 正式模式
41+- 不要引入新的架构方向
42+
43+建议调查方向:
44+1. codexd 的 app-server client 生命周期
45+- 第二个 thread 开始前,client / transport 是否仍然处于健康状态
46+- 有没有错误把“thread 完成”当成“child/stream 结束”
47+
48+2. transport 关闭逻辑
49+- 检查 app-server-transport.ts
50+- 确认 onClose / disconnect / reconnect 是否在第二个 thread 上被误触发
51+
52+3. thread 模型
53+- 检查 createSession / createTurn 对 threadId 的处理
54+- 确认新 thread 的 turnStart / turnSteer 是否和当前状态机兼容
55+
56+4. 最小修复优先
57+- 优先修“第二个 session/thread turn 失败”
58+- 不要顺手做大重构
59+
60+验收标准:
61+- 增加一个稳定复现并覆盖修复的测试
62+- 至少覆盖:
63+ - 第一个 session turn 完成
64+ - 第二个 session turn 也完成
65+ - 不出现 reconnect/fail
66+- 至少跑:
67+ - npx --yes pnpm -F @baa-conductor/codexd typecheck
68+ - npx --yes pnpm -F @baa-conductor/codexd build
69+ - node --test apps/codexd/src/index.test.js
70+ - 如有必要,加你新增的专项 test
71+ - git diff --check
72+
73+结束时:
74+- 提交并推送该分支
75+- 最终回复里明确说明:
76+ - 根因是什么
77+ - 第二个 thread 为什么之前会失败
78+ - 你改了哪些生命周期/transport/session 逻辑
79+ - 现在如何验证多个 session/thread 已经能顺序工作
80+```
+23,
-0
1@@ -0,0 +1,23 @@
2+# bugs
3+
4+当前目录只保留:
5+
6+- 仍未修复、仍有效的 bug
7+- 一个通用 `BUG-TEMPLATE.md`
8+- 对应 bug 的修复任务卡
9+
10+当前有效 bug:
11+
12+1. `BUG-008` — codexd 第二个 session/thread 发 turn 容易超时(已部分缓解,待正式关闭)
13+2. `BUG-009` — conductor-daemon 测试遗留 HTTP listener 导致进程挂住(无修复卡)
14+3. `BUG-010` — codexd turn 状态卡在 inProgress,与 BUG-008 相关(无修复卡)
15+
16+修复任务:
17+
18+- FIX-BUG-008:`/Users/george/code/baa-conductor/coordination/bugs/FIX-BUG-008.md`
19+
20+## 编号规则
21+
22+- BUG-XXX:bug 报告
23+- FIX-BUG-XXX:对应修复任务卡(给 Codex 执行)
24+- 编号按发现顺序递增,不复用
1@@ -0,0 +1,86 @@
2+# baa-conductor 浏览器控制当前任务
3+
4+## 最短用法
5+
6+以后直接对 Codex 说:
7+
8+```text
9+读 /Users/george/Desktop/baa-conductor-browser-control-tasks/T-BRW002.md,完成任务。
10+```
11+
12+或:
13+
14+```text
15+读 /Users/george/Desktop/baa-conductor-browser-control-tasks/T-BRW003.md,完成任务。
16+```
17+
18+或:
19+
20+```text
21+读 /Users/george/Desktop/baa-conductor-browser-control-tasks/T-BRW004.md,完成任务。
22+```
23+
24+这些任务卡已经包含:
25+
26+- 仓库和基线要求
27+- 分支 / worktree 约束
28+- 修改范围限制
29+- 验收标准
30+- 结束时必须说明的内容
31+
32+## 当前状态
33+
34+- `T-BRW001` 已完成:
35+ - 分支:`feat/browser-ws-command-surface`
36+ - 提交:`667fc6a`
37+ - 状态:已合进 `main` 并已推送
38+- `VERIFY-BROWSER-CONNECTION` 已完成
39+- 目前真正活跃的开发任务:
40+ - `T-BRW002`
41+ - `T-BRW003`
42+- `T-BRW004` 还不能开始,必须等 `T-BRW002`、`T-BRW003` 都合进主线
43+
44+## 当前可执行顺序
45+
46+1. 先做 `T-BRW002`
47+2. 再做 `T-BRW003`
48+ - `T-BRW001` 的 WS command surface 已经在当前 `main`
49+3. 最后在三项都合主线后做 `T-BRW004`
50+
51+当前唯一有效基线:
52+
53+- 仓库:`/Users/george/code/baa-conductor`
54+- 分支:`main`
55+- 提交:`main@667fc6a`
56+
57+目标:
58+
59+- 让 `conductor` 通过本地 Firefox WS bridge 控制浏览器插件
60+- 增加网页控制能力:
61+ - 打开/聚焦标签页
62+ - 请求凭证刷新
63+ - 代理页面 API 请求
64+ - 发起 Claude 网页对话
65+ - 读取当前对话内容
66+- 外部调用方只控制 `conductor` HTTP;不直接控制插件
67+
68+约束:
69+
70+- `Firefox` 插件仍然只跑在 `mini`
71+- 本地双向通讯用 `/ws/firefox`
72+- 远程/CLI/网页 AI 只打 `conductor` HTTP
73+- 先做 `Claude` 页面能力,`ChatGPT/Gemini` 只保留现有监测/凭证逻辑
74+- 不把 `/ws/firefox` 暴露成公网入口
75+
76+推荐顺序:
77+
78+1. `T-BRW001` 已完成并合主线
79+2. 当前先做 `T-BRW002`
80+3. 再做 `T-BRW003`
81+4. 最后跑 `T-BRW004`
82+
83+当前任务:
84+
85+- `T-BRW002` Firefox 插件 Claude HTTP 代理能力
86+- `T-BRW003` conductor 浏览器 HTTP 接口
87+- `T-BRW004` 文档与 e2e smoke 收口
1@@ -0,0 +1,77 @@
2+你在仓库 `/Users/george/code/baa-conductor` 工作。
3+
4+必须从当前 `main` 基线开始:`main@8a3a964`。
5+不要从其他任务分支切出。
6+如果本地已有旧 worktree/分支,不要复用,重新从 `main` 建干净 worktree。
7+
8+任务:Firefox WS bridge server command surface
9+建议分支:`feat/browser-ws-command-surface`
10+
11+先读:
12+1. `/Users/george/code/baa-conductor/apps/conductor-daemon/src/firefox-ws.ts`
13+2. `/Users/george/code/baa-conductor/docs/api/firefox-local-ws.md`
14+3. `/Users/george/code/baa-conductor/plugins/baa-firefox/controller.js`
15+4. `/Users/george/code/baa-conductor/docs/firefox/README.md`
16+
17+背景:
18+- 现在 Firefox WS 已支持:
19+ - `state_snapshot`
20+ - `action_request`
21+ - `credentials`
22+ - `api_endpoints`
23+- 插件端其实已经能处理服务端下发的:
24+ - `open_tab`
25+ - `api_request`
26+ - `request_credentials`
27+ - `reload`
28+- 但 `conductor-daemon` 现在还没有正式把这些 server -> client 命令做成可调用面,`api_request` 仍然是 `not_implemented`
29+
30+目标:
31+- 先把 Firefox WS bridge 的服务端“命令面”补齐
32+- 让 `conductor` 具备向插件发消息、等待回包、管理请求生命周期的基础能力
33+- 这一步先做 transport / registry / request-response,不做 Claude 页面业务路由
34+
35+要求:
36+- 只在这些范围内工作:
37+ - `apps/conductor-daemon/**`
38+ - `docs/api/**`
39+ - `docs/firefox/**`
40+- 不要修改 `plugins/baa-firefox/**`
41+- 不要改 `codexd`
42+- 不要做最终 `/v1/browser/*` HTTP 产品面
43+
44+需要完成:
45+1. 在 `firefox-ws.ts` 中增加 server -> client 命令发送基础设施
46+ - 能按 `clientId` 或默认活跃 client 发送命令
47+ - 能跟踪 request id
48+ - 能等待 `api_response`
49+ - 能处理超时、client disconnect、replacement
50+
51+2. 正式支持这些 outbound 命令
52+ - `open_tab`
53+ - `request_credentials`
54+ - `reload`
55+ - `api_request`
56+
57+3. 增加一个最小 bridge 服务层
58+ - 例如 `FirefoxBridgeService` / `FirefoxCommandBroker`
59+ - 不要把复杂逻辑塞满 `firefox-ws.ts`
60+
61+4. 文档更新
62+ - `docs/api/firefox-local-ws.md`
63+ - 写清哪些消息已经正式双向支持
64+
65+验收标准:
66+- 有可测试的 server -> client request/response 基础能力
67+- `api_request` 不再是 `not_implemented`
68+- `node --test apps/conductor-daemon/src/index.test.js` 通过
69+- `pnpm -F @baa-conductor/conductor-daemon typecheck` 通过
70+- `pnpm -F @baa-conductor/conductor-daemon build` 通过
71+- `git diff --check` 通过
72+
73+结束时:
74+- 提交并推送该分支
75+- 在最终回复里明确说明:
76+ - 新增了哪些 WS outbound 命令
77+ - request-response 生命周期怎么做
78+ - 还没做哪些 HTTP 产品接口
1@@ -0,0 +1,104 @@
2+## 最短提示词
3+
4+```text
5+读 /Users/george/Desktop/baa-conductor-browser-control-tasks/T-BRW002.md,完成任务。
6+```
7+
8+上面这一句就够了;本文件已经包含完整约束、修改范围、验收标准和结束要求。
9+
10+你在仓库 `/Users/george/code/baa-conductor` 工作。
11+
12+必须从当前 `main` 基线开始:`main@667fc6a`。
13+不要从其他任务分支切出。
14+如果本地已有旧 worktree/分支,不要复用,重新从 `main` 建干净 worktree。
15+
16+任务:Firefox 插件 Claude HTTP 代理能力
17+建议分支:`feat/firefox-claude-page-automation`
18+
19+先读:
20+1. `/Users/george/code/baa-conductor/plugins/baa-firefox/controller.js`
21+2. `/Users/george/code/baa-conductor/plugins/baa-firefox/content-script.js`
22+3. `/Users/george/code/baa-conductor/plugins/baa-firefox/page-interceptor.js`
23+4. `/Users/george/code/baa-conductor/docs/firefox/README.md`
24+5. `/Users/george/code/baa/baa-firefox/README.md`
25+6. `/Users/george/code/baa/baa-extension/background.js`
26+7. `/Users/george/code/baa/baa-extension/page-interceptor.js`
27+
28+背景:
29+- 现在插件已有:
30+ - Claude 页面右下角浮层
31+ - controller 页
32+ - request hook / credential / endpoint 监测
33+- 页面内代理链路其实已经存在:
34+ - service/controller 能收到 `api_request`
35+ - content script 能把请求转到页面上下文
36+ - page interceptor 能在页面里用真实凭证发 `fetch`
37+- 参考仓库 `baa-firefox` / `baa-extension` 的主线也不是 DOM 自动化,而是:
38+ - 拦截真实请求
39+ - 学习凭证和 endpoint
40+ - 在页面上下文里直接代发 HTTP 请求
41+
42+目标:
43+- 先只做 `Claude` 页面
44+- 让插件本地具备:
45+ - 基于已捕获的凭证和 endpoint 发起一轮 Claude HTTP 对话
46+ - 基于 API 响应 / SSE 读取当前对话内容
47+ - 给后续服务端暴露最小页面状态
48+- 这些能力后续会通过 `conductor` 的 WS bridge 被调用
49+- 本任务主线是 HTTP-first,不是 DOM-first
50+
51+要求:
52+- 只在这些范围内工作:
53+ - `plugins/baa-firefox/**`
54+ - `docs/firefox/**`
55+- 不要改 `apps/conductor-daemon/**`
56+- 不要做 ChatGPT/Gemini 自动化
57+- 保持当前中文 UI
58+- 不要把“解析输入框、点击发送按钮”当主方案
59+- 只有 API 无法提供的信息,才允许加最小 DOM 兜底
60+
61+需要完成:
62+1. 基于当前代理链路补齐 Claude HTTP 能力
63+ - 复用已捕获的 `credentials`
64+ - 复用已发现的 Claude endpoint
65+ - 能在页面上下文里代发 Claude 请求
66+ - 能把 HTTP 响应和 SSE 结果整理成可消费结果
67+
68+2. 增加或收口插件内部消息协议
69+ - 例如:
70+ - `claude_send`
71+ - `claude_read_conversation`
72+ - `claude_read_state`
73+ - 这些消息优先驱动 HTTP 代理,不要求模拟真实 DOM 点击
74+
75+3. 结果结构要适合后续服务端消费
76+ - 当前对话标题(如果可取)
77+ - 最近消息列表
78+ - role/content/timestamp(能取多少取多少)
79+ - 页面 busy 状态
80+ - 当前 URL
81+
82+4. 文档更新
83+ - `docs/firefox/README.md`
84+ - 写清当前只支持 Claude
85+ - 写清当前主线是凭证抓取 + endpoint 发现 + 页面内 HTTP 代理
86+ - 明确哪些信息来自 API / SSE,哪些是 DOM 兜底
87+
88+验收标准:
89+- 插件端可以通过 runtime message:
90+ - 发送 Claude prompt
91+ - 读取当前对话内容
92+ - 读取当前页面状态
93+- `node --check plugins/baa-firefox/controller.js`
94+- `node --check plugins/baa-firefox/background.js`
95+- `node --check plugins/baa-firefox/content-script.js`
96+- `node --check plugins/baa-firefox/page-interceptor.js`
97+- `git diff --check`
98+
99+结束时:
100+- 提交并推送该分支
101+- 在最终回复里明确说明:
102+ - Claude 能力是如何基于凭证、endpoint 和页面内 HTTP 代理实现的
103+ - 提供了哪些 runtime message
104+ - 哪些信息来自 API / SSE,哪些信息仍依赖最小 DOM 兜底
105+ - 当前有哪些已知限制
1@@ -0,0 +1,87 @@
2+## 最短提示词
3+
4+```text
5+读 /Users/george/Desktop/baa-conductor-browser-control-tasks/T-BRW003.md,完成任务。
6+```
7+
8+上面这一句就够了;本文件已经包含完整约束、修改范围、验收标准和结束要求。
9+
10+你在仓库 `/Users/george/code/baa-conductor` 工作。
11+
12+必须从当前 `main` 基线开始:`main@667fc6a`。
13+不要从其他无关任务分支切出。
14+如果本地已有旧 worktree/分支,不要复用,重新建干净 worktree。
15+
16+任务:conductor 浏览器 HTTP 接口
17+建议分支:`feat/conductor-browser-http-surface`
18+
19+先读:
20+1. `/Users/george/code/baa-conductor/apps/conductor-daemon/src/local-api.ts`
21+2. `/Users/george/code/baa-conductor/apps/conductor-daemon/src/firefox-ws.ts`
22+3. `/Users/george/code/baa-conductor/docs/api/README.md`
23+4. `/Users/george/code/baa-conductor/docs/api/firefox-local-ws.md`
24+5. `/Users/george/code/baa-conductor/docs/firefox/README.md`
25+
26+背景:
27+- 目标是:外部调用方只打 `conductor` HTTP
28+- `conductor` 再通过本地 `/ws/firefox` 控制 Firefox 插件
29+- 当前还没有正式的 `/v1/browser/*` 产品面
30+- 插件侧 Claude 主线应以“页面内 HTTP 代理”能力为主,而不是 DOM 自动化
31+
32+目标:
33+- 增加最小但正式的浏览器 HTTP 接口
34+- 让 CLI / 网页 AI / 其他调用方可以通过 `conductor`:
35+ - 打开 Claude 页面
36+ - 发起 Claude 对话
37+ - 读取当前 Claude 对话内容
38+ - 读取浏览器 bridge 状态
39+
40+要求:
41+- 只在这些范围内工作:
42+ - `apps/conductor-daemon/**`
43+ - `docs/api/**`
44+ - `README.md`
45+- 不要修改 `plugins/baa-firefox/**`
46+- 不要引入公网暴露 `/ws/firefox`
47+- 当前先只做 Claude
48+
49+建议接口:
50+1. `GET /v1/browser`
51+ - bridge 状态摘要
52+ - 当前 client
53+ - Claude 页基本状态(如果能读到)
54+
55+2. `POST /v1/browser/claude/open`
56+ - 打开或聚焦 Claude 标签页
57+
58+3. `POST /v1/browser/claude/send`
59+ - 发送一轮 prompt
60+
61+4. `GET /v1/browser/claude/current`
62+ - 读取当前 Claude 对话内容和页面状态
63+
64+5. 可选:
65+ - `POST /v1/browser/claude/reload`
66+ - `POST /v1/browser/credentials/request`
67+
68+接口原则:
69+- 先本地可用
70+- 返回 JSON
71+- 出错结构统一
72+- 如果当前没有活跃 Firefox client,要返回清晰的 `503` / `409` 风格错误
73+- Claude 动作优先通过本地 WS 转发到插件已有的 HTTP 代理能力
74+
75+验收标准:
76+- `conductor` 有正式 `/v1/browser/*` 接口
77+- 至少具备 open / send / current 这 3 个动作
78+- `pnpm -F @baa-conductor/conductor-daemon typecheck`
79+- `pnpm -F @baa-conductor/conductor-daemon build`
80+- `node --test apps/conductor-daemon/src/index.test.js`
81+- `git diff --check`
82+
83+结束时:
84+- 提交并推送该分支
85+- 在最终回复里明确说明:
86+ - 新增了哪些 `/v1/browser/*` 接口
87+ - 哪些动作通过本地 WS 转发给插件的页面内 HTTP 代理
88+ - 当前只支持哪些平台
1@@ -0,0 +1,75 @@
2+## 最短提示词
3+
4+```text
5+读 /Users/george/Desktop/baa-conductor-browser-control-tasks/T-BRW004.md,完成任务。
6+```
7+
8+上面这一句就够了;本文件已经包含完整约束、修改范围、验收标准和结束要求。
9+
10+你在仓库 `/Users/george/code/baa-conductor` 工作。
11+
12+必须从当前 `main` 基线开始。
13+开始前先确认:
14+
15+- `T-BRW002` 已经合进主线
16+- `T-BRW003` 已经合进主线
17+
18+如果这两个条件有任意一个不满足,不要开始本任务。
19+
20+不要从其他任务分支切出。
21+
22+任务:浏览器控制文档与 e2e smoke 收口
23+建议分支:`feat/browser-control-e2e-smoke`
24+
25+先读:
26+1. `/Users/george/code/baa-conductor/docs/api/README.md`
27+2. `/Users/george/code/baa-conductor/docs/firefox/README.md`
28+3. `/Users/george/code/baa-conductor/docs/api/firefox-local-ws.md`
29+4. `/Users/george/code/baa-conductor/plugins/baa-firefox/docs/conductor-control.md`
30+
31+目标:
32+- 在功能分支都合入后,做一轮最小闭环:
33+ - `conductor HTTP`
34+ - `/ws/firefox`
35+ - 插件
36+ - Claude 页面
37+- 并把文档、curl 示例、smoke 脚本收口
38+- Claude 侧闭环以“页面内 HTTP 代理”链路为准,不要求 DOM 自动化冒充用户点击
39+
40+要求:
41+- 只在这些范围内工作:
42+ - `docs/**`
43+ - `scripts/runtime/**`
44+ - `tests/**`
45+- 不要继续大改业务代码
46+- 重点是收口和验证
47+
48+需要完成:
49+1. 增加最小 smoke
50+ - 打开 Claude 页
51+ - 读 bridge 状态
52+ - 发一轮 prompt
53+ - 读取当前对话内容
54+
55+2. 更新文档
56+ - AI/CLI 先读哪个 describe
57+ - 浏览器控制接口怎么调
58+ - 哪些能力只在本地可用
59+
60+3. 给出最小 curl 示例
61+ - `/v1/browser`
62+ - `/v1/browser/claude/open`
63+ - `/v1/browser/claude/send`
64+ - `/v1/browser/claude/current`
65+
66+验收标准:
67+- 至少有一条 smoke 脚本或测试能跑通整个链路
68+- 文档和实际接口一致
69+- `git diff --check`
70+
71+结束时:
72+- 提交并推送该分支
73+- 在最终回复里明确说明:
74+ - smoke 覆盖了哪些步骤
75+ - 文档入口在哪
76+ - 还有哪些平台暂未支持
1@@ -0,0 +1,81 @@
2+你在仓库 `/Users/george/code/baa-conductor` 工作。
3+
4+必须基于当前主线验证,不要新建功能分支,不要修改代码。
5+当前基线:`main@8a3a964`
6+
7+当前状态:此任务已完成,保留为归档验证卡;除非需要重新验证当前 live 环境,否则不要重复执行。
8+
9+任务:验证 Firefox 插件与本地 `conductor` / `codexd` 的连接状态,确认当前连接问题到底在服务端、插件端,还是页面端。
10+
11+先读:
12+1. `/Users/george/code/baa-conductor/docs/firefox/README.md`
13+2. `/Users/george/code/baa-conductor/docs/api/firefox-local-ws.md`
14+3. `/Users/george/code/baa-conductor/docs/api/README.md`
15+4. `/Users/george/code/baa-conductor/plugins/baa-firefox/controller.js`
16+5. `/Users/george/code/baa-conductor/plugins/baa-firefox/background.js`
17+
18+目标:
19+- 不改代码,只做一次清晰的连接验证
20+- 给出当前链路每一段是否正常:
21+ - `conductor`
22+ - `status-api`
23+ - `codexd`
24+ - Firefox 本地 HTTP
25+ - Firefox 本地 WS
26+ - `controller.html` 是否只保留一个
27+- 如果有失败,要明确定位在哪一层
28+
29+需要验证的内容:
30+
31+1. 服务端健康
32+- `http://100.71.210.78:4317/healthz`
33+- `http://100.71.210.78:4317/rolez`
34+- `http://100.71.210.78:4318/v1/status`
35+- `http://127.0.0.1:4319/healthz`
36+- `http://127.0.0.1:4319/describe`
37+- `http://100.71.210.78:4317/v1/codex`
38+
39+2. Firefox WS 握手
40+- 验证 `ws://100.71.210.78:4317/ws/firefox`
41+- 至少确认:
42+ - 能连接
43+ - 能收到 `state_snapshot`
44+ - 如果用相同 `clientId` 建第二个连接,旧连接会被替换
45+
46+3. 插件默认配置
47+- 核对插件默认值是否是:
48+ - `Control API = http://100.71.210.78:4317`
49+ - `Local API = http://100.71.210.78:4317`
50+ - `WS = ws://100.71.210.78:4317/ws/firefox`
51+
52+4. 浏览器侧状态
53+- 当前是否只存在一个 `controller.html`
54+- 如果开了多个,确认插件现在是否会自动收敛成一个
55+- 如果 Firefox 已加载插件,确认管理页里:
56+ - 本地 WS 是否显示已连接
57+ - 本地 HTTP 是否显示已连接
58+ - 最近错误是否为空
59+
60+5. 结果判定
61+- 明确给出:
62+ - 服务端 OK / 不 OK
63+ - WS OK / 不 OK
64+ - HTTP 同步 OK / 不 OK
65+ - 插件 UI OK / 不 OK
66+ - 如果不 OK,最可能的根因是什么
67+
68+建议命令:
69+- `curl`
70+- 本地 node/ws 最小握手脚本
71+- 如有必要,可用浏览器/插件状态检查
72+
73+不要做的事:
74+- 不修改代码
75+- 不提交任何变更
76+- 不新建分支
77+
78+最终回复必须包含:
79+1. 你实际跑了哪些验证命令
80+2. 每一层的结果
81+3. 如果有问题,问题在服务端、插件端还是页面端
82+4. 下一步最小修复建议