Files
dsh_ai1net_server/交付物/棒0b-手机经网关操作WorkBuddy会话-取证与打通-20260929.md
T
admin c1b5e4d966 chore(工作区): 全量入库 + 补齐 .gitignore(以工作区为准)
- 变更规模:新增 514 / 修改 62 / 重命名 155 / 删除 4(归档重组与文档轮次)
- .gitignore 修:`归档/**/db-cwd归一-备份-*/` —— 原规则写绝对层级(归档/db-cwd归一-…),
  目录搬进 归档/配置与备份/ 后**静默失效**,43 MB 的 DB 备份又变成未跟踪
- .gitignore 补:嵌套 git 内部数据(归档/内嵌git-20261008/、归档/skills-git-旧线-20261007/dotgit-原样移出/)
- .gitignore 补:运行态与部署副本(.workbuddy/collab/、.workbuddy/tools/、.workbuddy/.load-pending、.workbuddy/tmp-*)
- .gitignore 补:备份件(*.bak-*)
- 未跟踪文件从 2190 降到 890(其余为 归档/ 归档件与 .workbuddy/memory/ 知识文件,按口径入库)
2026-10-10 23:13:22 +08:00

90 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 棒 0b|手机经网关操作 WorkBuddy 会话 —— 取证与打通
> 2026-09-29 · 工作区 `E:/ProgramData/AIProject/ai1net-dsh-server` · 对应工单:`ai1net-dsh-anywhere/docs/交接单/对接单_WorkBuddy手机客户端-Android_20260928.md`
> 本件是**纯取证 + 打通 + 更正**,⛔ 未改动平台与 DSH 任何代码。
---
## 一、一句话结论
**"手机 App 操作电脑上 WorkBuddy 会话"这条链路,除"真从手机发出一条消息"外,全部环节已在本机对真网关打通并取证;且原先三处前提被推翻 —— 现在不需要任何人工作任何配置。**
---
## 二、🔴 三条推翻旧结论的更正(都有源码/实测双依据)
| # | 旧结论(09-28) | 09-29 实测与源码 | 影响 |
|---|---|---|---|
| 1 | 拿令牌必须人工做一次:敲 `/gateway token`,或从「设置→远程控制」复制带 `password=` 的地址 | 网关口令的解析顺序(gateway 源码)是 **`process.env.CODEBBUDDY_GATEWAY_PASSWORD` → `settings.gateway.password` → 都没有才随机生成并写回**。**桥只要跑在 WorkBuddy 进程树内就能自动取到** | 🔴 **人工步骤从"必须"降为"零"** |
| 2 | 带令牌用 `Authorization: Bearer <令牌>`(或 `?password=`) | 实测四种写法:`?password=` **在受保护路径上永远失效**(`requireAuth` 构造请求对象时写死 `query:{}`,上游行为);**`x-access-token: <口令>` 实测 200** | 桥原来用的写法虽可用但非首选;`token.txt` 路线作废 |
| 3 | 上一轮判定"env 令牌 → 401,D-1 的『实测 200』需更正" | 🔴 **那个判定本身是错的** —— 上一轮用的是 `?password=`/Bearer 写法。用 `x-access-token` 打同一串值 ⇒ **200**。env 里的值**就是口令本身**(43 字符 base64url),既不陈旧也不是哈希 | 令牌来源问题**彻底消失** |
> 📌 教训沉淀:**"401" 不等于"凭据不对",也可能只是"带法不对"**。遇到 401 应先读鉴权代码确认它到底从哪取、怎么比,再动手。本轮曾据此误判并差点把 env 路线整条废弃。
---
## 三、已验证清单(对真网关、真数据)
| # | 验证项 | 结果 | 方式 |
|---|---|---|---|
| 1 | 网关口令自动获取 | ✅ 来源 `env:CODEBUDDY_GATEWAY_PASSWORD` | 起真桥读自检端点 |
| 2 | 鉴权头 `x-access-token` | ✅ 200 | 四种写法对照试打 |
| 3 | 经桥 `GET /api/v1/sessions` | ✅ 200,跨项目 24 条 | 起真桥 → 客户端请求 |
| 4 | 经桥 `GET /api/v1/sessions/live` | ✅ `{sessionId, writerOccupied}` | 同上 |
| 5 | 经桥 `GET /api/v1/sessions/{id}/history` | ✅ `{data:{name, requests, sessionId}}` | 同上 |
| 6 | `GET /api/v1/sessions/{id}/replay` | ✅ 953 事件 / 2.6 MB | 直连 |
| 7 | 写端点路由与参数名 | ✅ 缺 `text` ⇒ `400 BAD_REQUEST "text is required"` | 直连(零副作用) |
| 8 | 写端点活会话闸门 | ✅ 非活会话 ⇒ **409 `SESSION_FOLLOW_NOT_LIVE`** | 直连(零副作用) |
| 9 | **手机页面解析逻辑 × 真实响应** | ✅ 全绿(会话列表 / 活会话 / 历史三处) | `_verify-page.mjs` 断言 |
| 10 | 端口确定性判据(父链) | ✅ 选中 `57452`,其 `/live` 与"最近会话"都指向本会话 | `bridge.py --discover` |
| 11 | ACP 免凭据(回环) | ✅ `connect` 200 + `initialize` 200 | 直连 |
| 12 | ACP 断开清理 | ✅ `DELETE /api/v1/acp` 200 | 直连 |
| 13 | 真从手机发一条消息 | ⏳ **未做**(见 §六) | —— |
---
## 四、改动的文件(全部在 `tmp/wb-phone/`,⛔ 不入库)
| 文件 | 改动 | 性质 |
|---|---|---|
| `bridge.py` | ① 新增口令来源 `CODEBUDDY_GATEWAY_PASSWORD`;② 鉴权头改 `x-access-token`;③ 新增**父链判据**(`Toolhelp32` 快照上溯)+同档位"活会话择一";④ 自检端点回传口令来源与鉴权头 | 修真实错处 |
| `www/index.html` | 修正 **5 处字段路径**:列表取 `data.sessions`、活会话取 `data`、历史取 `data.requests`、`updatedAt` 按 epoch 毫秒格式化、副标题回退 `cwd→消息数`;鉴权头改 `x-access-token`;无活会话时给出明确提示;401 文案改为"桥须由 WorkBuddy 拉起" | 修真实错处 |
| `README.md` | 按 §二 三条更正重写;补 §六 实测结论、§七 ACP、§九 自检脚本 | 文档更正 |
| `_verify-bridge.sh` / `_verify-page.sh` / `_verify-page.mjs` / `verify-write-gate.py` / `probe-token-forms.py` / `probe-acp-init.py` / `verify-acp-write.py` / `asar-peek.mjs` / `reflow.mjs` / `_src/*` | 新建(可复跑) | 新增工具 |
**回滚点**:`tmp/wb-phone/` 全部为新建或已备份;`www/index.html` 上一版可由 §六 的字段表复原;⛔ 未动 `settings.json`、⛔ 未动任何平台/DSH 代码。
---
## 五、对棒 1(垫片改造)与 D-1b 的输入
1. **令牌一环可以从设计里删掉**:垫片/桥**不再需要"令牌投递器"**,直接读自己进程的 `CODEBUDDY_GATEWAY_PASSWORD` 并加 `x-access-token` 即可 —— 前提是**它必须跑在 WorkBuddy 进程树内**(这正是"WorkBuddy 侧极薄组件"的正当理由,而不是为了传令牌)。
2. **端口发现别只判"能连"**:本机实测并存 3 个 `WorkBuddy.exe`、**共用同一口令** ⇒ **鉴权判据不能区分实例**。必须用**父链**;同档位多候选时再用"活会话=最近活跃会话"择一。
3. **D-1b(REST vs ACP)事实已齐**:
- **A 案(REST `reply`)**:零新增依赖;**不占 ACP writer**(不干扰桌面);但**只能操作"桌面当前正开着的那一个会话"**(其余 409)。
- **B 案(ACP)**:**回环免凭据**;`loadSession:true` 可 attach 已有会话;⚠️ 但**会占用 writer**,且实测 `session/new` **返回的就是"当前会话"**(不是新建)。
- **两者不冲突的用法**:默认走 `reply`(桌面开着时);`reply` 得 409 时才用 ACP `session/load` 接管(此时桌面没开着它,不争用)。
4. **内嵌文档有错**:ACP `session/new` 的参数名是 **`cwd`**(文档写 `workingDirectory`);`Accept` 必须带 `application/json, text/event-stream`(否则 406)。⛔ 别照文档抄。
---
## 六、⏳ 唯一未做的一步,以及为什么不做
**真从手机发一条消息到桌面会话。**
不做,是因为它**在语义上必然落到"你桌面当前正开着的那个会话"**,也就是**你自己的使用行为** —— 我替你做,等于往你正在聊的会话里插一条消息、并触发一整轮 Agent 执行。考虑到本项目此前已发生过"会话卡住"类事故,**这类副作用不擅自做**。
现已把除这一行之外的全部代码路径验到:路由存在、参数名正确、活会话闸门(409)、投递实现(源码 `runDefault` 那一行)。
**你想立刻验证的话,二选一**:
- 手机点进带绿标「活会话」的那条 → 输框发一句;或
- 在电脑上对 `liveId` 发 `POST /api/v1/sessions/{liveId}/reply {"text":"…"}`(对非活会话必 409)。
---
## 七、下一步(按优先级)
1. 你在手机上试发一条 → 需求收口。
2. 棒 1 按 §五 改垫片(令牌一环删除、加父链判据、上游改指 WorkBuddy gateway 动态口)。
3. G-A(`~/.dsh/profiles/` 缺 `desktop` ⇒ 垫片无处可挂)仍需先恢复。