- 变更规模:新增 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/ 知识文件,按口径入库)
14 KiB
手机 App 经 ai1net 覆盖网络操作 WorkBuddy 会话 · 架构与分工(2026-09-28)
🔴 本件已被取代(v1 → v2) ⇒ 执行请以
手机App经覆盖网络操作WorkBuddy-架构定稿v2-20260928.md为准。 本件作废的具体结论:§3.3「垫片承载形态改为独立进程」已撤销 —— 用户澄清「客户端插件」指 DSH 客户端上的插件(DSH 有完整插件宿主),故垫片维持既有 DSH Host 插件形态。 本件其余取证(复用清单、端口区间、gateway 端点、forwardHeaders逻辑可复用)仍然有效,v2 已并入。
用户口径(原话):「通过 dsh 平台的覆盖网络去实现,功能做到插件中:本地 dsh 客户端插件 + dsh 平台插件配合,让手机 app 通过 ai1net 网络使用」 性质:架构定稿 + 分工 + 分步。落地按 §5 棒次执行。 与前一版关系:本文件取代前一版的"连接方式待定" —— D1 已定 = 走 ai1net 覆盖网络(方案 C)。
0 判定(三句话)
- 能成,而且约 80% 是复用 —— 那条线(手机接入线)已经把"手机经中继看到桌面"整条跑通(配对 28 条判据全绿、设备入口真机 200/101),六个复用件全部在位(§2)。
- 要新做的只有三处(§3):把垫片的上游从"本机 DSH Web"换成"本机 WorkBuddy gateway"、把凭据注入从"DSH 签名 Cookie"换成"gateway 令牌"、把垫片的承载形态从"DSH Host 侧插件"改成"独立进程"(WorkBuddy 没有 DSH Host)。
- 🔴 一个必须先发现的事实:gateway 端口每次重启都会变(实测
50753 → 59914)⇒ 垫片必须动态发现,⛔ 不能写死。
1 目标架构(一条链,四段,复用三段)
手机 App(Android 客户端)
│ HTTPS 443(平台登录态)
▼
① ai1net 平台(服务器节点 47)—— 【既有,零改动】
├ 设备入口 /u/<uid>/desk/<hostId>/* ← device-web.ts(202 行:五道闸 + 整站前缀转发)
├ 配对 overlay-pair(二维码六态) ← 28 条判据全绿
├ 设备台账 overlay_devices + 准入四道闸 ← 既有
└ 覆盖网络中继 relay(wss 走 443,⛔ 不开端口)← 既有
▲ 设备只拨出(无公网入站口)
│
② 用户电脑 —— 【既有守护 + 改造后的垫片】
├ 节点守护 overlay-node-daemon.ps1(声明端口) ← 既有
└ 【设备侧垫片】只绑 127.0.0.1:20090 ← 既有范式,改上游
· Host → 127.0.0.1:<gateway口>(过 Host 校验)
· 注入 gateway 凭据
▼
③ 本机 WorkBuddy gateway(127.0.0.1:<动态口>)—— 【既有,官方自带】
· GET /api/v1/jobs 会话列表
· GET /api/v1/jobs/{id}/stream ⭐ 实时尾随(SSE)
· POST /api/v1/jobs/{id}/reply ⭐ 发送指令
▼
④ WorkBuddy 会话 —— 【既有,就是桌面那份会话库】
一句话:手机走的是你们已经跑通的那条路,只是到了电脑里换了最后一段的目标(DSH Web → WorkBuddy gateway)。
2 复用清单(⛔ 全部已核实存在,不重造)
| # | 件 | 位置 | 状态 |
|---|---|---|---|
| ① | 设备侧垫片源码 | E:/github/dsh-client/packages/device-shim |
✅ 在位(含 forwardHeaders / pair-page.js / oauth-dsh.js) |
| ② | 平台设备入口 | D:/github/dsh_shenxian/src/web/routes/device-web.ts |
✅ 202 行,整站前缀转发(一条前缀管全站) |
| ③ | 配对五端点 | src/web/routes/overlay-pair.ts |
✅ 已部署,六态 |
| ④ | 设备台账 + 四道闸 | src/web/routes/overlay-device.ts |
✅ |
| ⑤ | 节点守护 | E:/dsh-worker-dev/bin/overlay-node-daemon.ps1 |
✅ 含 -Action install/uninstall/status |
| ⑥ | 节点配置(端口/凭据) | E:/dsh-worker-dev/overlay/overlay-node.local.json |
✅ ports:[20090] · relayUrl=wss://ai1net.com/dshs-relay |
关键既有约束(照抄,⛔ 别重新发明):
- 中继只连回环:
factory(port,'127.0.0.1'),⛔ 永不接受可路由地址。 - 声明端口必须在中继允许区间:47 生产实测
--base 19000 --span 3000⇒ 19000..21999。 - ⛔ 不能直接声明 WorkBuddy gateway 的口 —— 原因有二:① 它是随机口、可能落在区间外;② 区间内需要有真实回环监听者,而 gateway 的口不归我们管。⇒ 这正是垫片存在的理由。
- 中继走 443(
wss://ai1net.com/dshs-relay)⇒ 功能全可用、⛔ 不用开任何端口。
3 三处新做/改(本方案的真正工作量)
3.1 垫片上游改目标:DSH Web → WorkBuddy gateway
| 项 | 现状(DSH 版) | 本方案(WorkBuddy 版) |
|---|---|---|
| 上游 | 127.0.0.1:<webServer.port>(实测 19387) |
127.0.0.1:<gateway口>(动态,见 3.4) |
| 端口来源 | DSH 注入的 webServer 服务 |
⛔ 拿不到 ⇒ 自行发现 |
| 转发变换 | Host → 127.0.0.1:<port>;Origin 归一 |
同样需要(gateway 也有 Host 校验 hostValidation) |
3.2 凭据注入改方式:DSH 签名 Cookie → gateway 令牌
- DSH 版:Cookie 是 authority 绑定的(名字 =
dsh-auth-+sha256(authority),载荷里 authority 必须与 Host 逐字相等)⇒ 所以必须改写 Host。 - WorkBuddy 版:鉴权是
?password=<令牌>或 Cookie,不绑定 authority。- ✅ 有利:Host 改写只为过 gateway 的 Host 校验,不带凭据语义 ⇒ 简单。
- 🔴 约束:鉴权中间件有防爆破限流
2 次/分钟+12 次/小时⇒ 绝不能每次请求都带 query 密码。 - 选定的做法:垫片首次用
?password=换到 Cookie,之后全程复用 Cookie(Cookie 不在限流口径内)。 - ⚠️ 备选做法(若 Cookie 方案不通):垫片维护一个"已认证会话",只对
401响应重取 Cookie。
3.3 垫片承载形态:DSH Host 插件 → 独立进程
- 现状:垫片是 DSH Host 侧插件(
inject: ['connection','webServer']),跑在 DSH Host 进程内 —— 因为它要从connection拿 DSH 凭据、从webServer拿端口。 - 🔴 WorkBuddy 没有 DSH Host,插件形态只有
skill/mcp-app⇒ 垫片无法作为 WorkBuddy 插件运行。 - ⇒ 改为独立进程,由既有节点守护拉起(守护本来就管进程编排与端口声明)。
- ✅ 无损失:垫片本体只是"绑回环 + 反代 + 改头",与是否跑在 DSH 内无关;
forwardHeaders的逻辑可原样复用。
3.4 🔴 动态发现 gateway 端口(新增的必做项)
- 实测:重启后
50753 → 59914⇒ 写死必炸。 - 发现判据(三项同时成立才算):
- 监听者是
WorkBuddy.exe(或其后代进程); GET /返回 200 且正文含CodeBuddy Gateway/CodeBuddy Remote Control;GET /api/v1/health返回 401(路由在、需鉴权)。
- 监听者是
- 兜底:也可由用户敲
/gateway status读出地址后填入配置(⛔ 该命令模型不能代敲)。 - ⚠️ 发现失败要 fail-closed(不启、具名报错),⛔ 不许静默用上一次的端口。
4 与既有那条线的差异表(一眼看清改了什么)
| 维度 | 手机接入线(DSH 版 · 已跑通) | 本方案(WorkBuddy 版) | 判定 |
|---|---|---|---|
| 手机侧 | 浏览器 + 门户登录态 | Android 客户端(用户要求) | ⚠️ 换形态 |
| 平台侧 | 设备入口 / 五道闸 / 台账 / 配对 / 中继 | 完全相同 | ✅ 零改动 |
| 设备侧暴露 | 垫片只绑 127.0.0.1:20090 |
相同 | ✅ 复用 |
| 垫片上游 | 本机 DSH Web(19387) | WorkBuddy gateway(动态口) | ⚠️ 改 |
| 垫片凭据 | DSH 签名 Cookie(authority 绑定) | gateway 令牌 → Cookie | ⚠️ 改 |
| 垫片承载 | DSH Host 侧插件 | 独立进程(守护拉起) | ⚠️ 改 |
| 对外端口 | 0 个(全走 443) | 相同 | ✅ 复用它已验的分层 |
| 会话库 | 桌面 DSH | 桌面 WorkBuddy(同一份) | ⚠️ 换目标 |
5 分工与步骤
棒 0(前置 · 本会话,随时可做)—— 端口发现 + 只读实测
| # | 做什么 | 判据 |
|---|---|---|
| 0.1 | 写端口发现脚本(按 §3.4 三项判据) | 能稳定找到当前 gateway 口;⛔ 找不到即 fail-closed |
| 0.2 | U1 只读实测:/api/v1/jobs 是否含桌面正在聊的会话 |
有 ⇒ 本方案成立;无 ⇒ 只能操作 gateway 自起的会话(须回头改目标) |
| 0.3 | 记录 settings.gateway / 令牌取得路径 |
令牌可得(用户敲 /gateway status) |
棒 1(设备侧 · 本地 dsh 客户端插件)—— 垫片改造
| # | 做什么 | 判据 |
|---|---|---|
| 1.1 | fork device-shim 的 forwardHeaders 与反代骨架,上游改 gateway |
curl 127.0.0.1:<垫片口>/api/v1/jobs 经垫片返回 JSON(不再 401) |
| 1.2 | 凭据注入:首跳换 Cookie、之后复用 | 连续 50 次请求无 429(证明没在打限流) |
| 1.3 | 改独立进程形态,写进节点守护的拉起清单 | 守护 -Action status 可见;停守护 ⇒ 端口撤 |
| 1.4 | 端口声明:区间内新口(与 DSH 版并存,⛔ 不覆盖 20090) | relay /status 出现该端口 |
棒 2(平台侧 · dsh 平台插件配合)—— 零改动 + 一处确认
| # | 做什么 | 判据 |
|---|---|---|
| 2.1 | 确认 device-web.ts 的整站前缀转发对"非 DSH 后端"同样成立 |
经设备入口访问垫片,/api/v1/jobs 通 |
| 2.2 | 若需区分两条通道(DSH / WorkBuddy),用不同端口 + 不同设备行区分,⛔ 不改判据 | 两条通道互不影响 |
| 2.3 | 门户/接口层:让客户端能取到"我的设备"列表 | 客户端能列出可用设备 |
⚠️ 本条与用户口径的偏差(需说明):按核实结果,平台侧不需要新插件 ——
device-web.ts已是通用的整站前缀转发,准入四道闸与后端是谁无关。⇒ "dsh 平台插件配合"这一项实际是零改动。若用户期望的是"平台侧也出一个插件形态的东西"(如 M 系列模块),那是另一种做法(在插件里再包一层),成本更高且无必要 —— 见 §7 待确认项。
棒 3(手机侧 · Android 客户端)—— 已投对接单,需按本方案更新
| # | 做什么 | 判据 |
|---|---|---|
| 3.1 | 更新对接单:D1 从"隧道/局域网"改为"走 ai1net 覆盖网络"(§8 已做) | 对接单里连接方式段已改 |
| 3.2 | 客户端只认设备入口地址(https://<门户>/u/<uid>/desk/<hostId>/…)+ 平台登录态 |
手机打开即得会话列表 |
| 3.3 | MVP:列表 / 历史 / SSE 尾随 / 发送 / 重连 | 见对接单 §7 |
棒 4(联调)
真机端到端 + 断网重连 + 中继侧零协议改动复核(判据:src/net/relay/** 无新增 op)。
6 风险与红线
| # | 项 | 处置 |
|---|---|---|
| 1 | gateway 端口会变 | §3.4 动态发现 + fail-closed |
| 2 | 限流(2/min) | 垫片换 Cookie 后复用;⛔ 客户端不许轮询(对接单已列为硬约束) |
| 3 | 权限面 | gateway 能执行任务、改会话 ⇒ 设备入口准入必须保持四道闸 + 默认关;⛔ 不新增共享密钥、⛔ 不把令牌落平台库 |
| 4 | WorkBuddy 侧无 Host 插件形态 | 垫片改独立进程(§3.3);⛔ 不要试图做成 WorkBuddy 插件 |
| 5 | 两条通道并存 | 端口/设备行分开,⛔ 不动 DSH 那条已验通的 |
| 6 | E:/github/dsh-client 0 commit |
动它之前先入库(回滚唯一保障) |
| 7 | R5 只收窄 | 本方案不开任何对外端口、不新增暴露面 ⇒ ✅ 合规 |
7 待确认(一轮一问)
问题:垫片(设备侧桥)放在哪个仓、由哪条线做?
为什么需要你定:垫片现在的家在 E:/github/dsh-client/packages/device-shim(属手机接入线的客户端仓),而它的上游目标要改成 WorkBuddy(属本会话的宿主侧知识)。归属不同,动的人不同,回滚责任也不同。
- 候选 1 · 在
dsh-client仓新建同源包(如packages/wb-gateway-shim),由手机接入线做 —— 与既有垫片同源、复用最顺、风格一致。缺点:要跨线交接,本会话只能出规格不能落地。 - 候选 2 · 由本会话另起一个独立小进程,放在本工作区 —— 本会话可直接做完、闭环快。缺点:与既有垫片两套代码(同类逻辑两份),日后维护要记住两处。
- 候选 3 · 直接改既有
device-shim支持"上游可配"(一个包两种目标)—— 一份代码、最省。缺点:动的是那条线已验通的成果(28 条判据绿),有回归风险。
倾向候选 3 的变体:不改既有行为,只给它加一个"上游目标"配置项(默认仍是 DSH,⛔ 不改变现有语义)⇒ 一份代码、零回归、两条通道共用。若那条线不同意,退候选 1。
附:本次取证读数
| # | 取证点 | 读数 |
|---|---|---|
| 1 | gateway 存活 | 127.0.0.1:59914 → 200;重启前旧口 50753 → 502(端口会变) |
| 2 | 鉴权 | /api/v1/health → 401 |
| 3 | 监听范围 | 仅 127.0.0.1 |
| 4 | 中继区间(生产实测) | --base 19000 --span 3000 ⇒ 19000..21999 |
| 5 | 节点配置 | ports:[20090] · relayUrl=wss://ai1net.com/dshs-relay(走 443) |
| 6 | 垫片现状 | DSH Host 侧插件;inject:['connection','webServer'];上游 = webServer.port |
| 7 | 垫片关键变换 | forwardHeaders(rawHeaders, authority, cookie):Host → authority、剥上游 set-cookie |
| 8 | 平台设备入口 | device-web.ts 202 行,/u/<uid>/desk/<hostId>/…,五道闸单一入口,整站前缀转发 |
| 9 | 六个复用件 | 全部 EXIST |
| 10 | gateway 官方后门 | CODEBUDDY_CODE_CORS_ORIGINS 环境变量 + settings.gateway.corsOrigins(如需配 origin 用) |