Files
dsh_ai1net_server/交付物/手机App经覆盖网络操作WorkBuddy-架构与分工-20260928.md
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

14 KiB
Raw Permalink Blame History

手机 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 判定(三句话)

  1. 能成,而且约 80% 是复用 —— 那条线(手机接入线)已经把"手机经中继看到桌面"整条跑通(配对 28 条判据全绿、设备入口真机 200/101),六个复用件全部在位(§2)。
  2. 要新做的只有三处(§3):把垫片的上游从"本机 DSH Web"换成"本机 WorkBuddy gateway"、把凭据注入从"DSH 签名 Cookie"换成"gateway 令牌"、把垫片的承载形态从"DSH Host 侧插件"改成"独立进程"(WorkBuddy 没有 DSH Host)。
  3. 🔴 一个必须先发现的事实: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)
  • 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 ⇒ 写死必炸。
  • 发现判据(三项同时成立才算):
    1. 监听者是 WorkBuddy.exe(或其后代进程);
    2. GET / 返回 200 且正文含 CodeBuddy Gateway / CodeBuddy Remote Control;
    3. 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 用)