268 lines
19 KiB
Markdown
268 lines
19 KiB
Markdown
# 手机回复 WorkBuddy 会话 · 架构与实施方案(2026-09-28)
|
||||
|
|
|
|||
|
|
> **目标(用户原话)**:让用户能**通过手机对 WorkBuddy 中对话进行回复**。
|
|||
|
|
> **约束**:结合现有 ai1net 架构 —— **服务器节点(+插件)/客户端(+插件)**,复用既有能力,⛔ 不重造。
|
|||
|
|
> **性质**:本文件 = **规划**(架构 + 详细方案)。落地按 §7 分阶段棒次执行,每棒独立验收。
|
|||
|
|
> **证据分级**:`【已验】`有实测读数 | `【源码在】`代码在位未跑 | `【待实测】`机制在位、行为未验证 —— ⛔ 交付时不得把后两类写成已验。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 0 判定(先给结论)
|
|||
|
|
|
|||
|
|
**一句话架构**:**手机在平台门户作答 ⇒ 平台 IM 内核 ⇒ 覆盖网络反隧道 ⇒ 设备侧桥 ⇒ WorkBuddy 钩子把答案交给模型**。
|
|||
|
|
|
|||
|
|
三个关键结论:
|
|||
|
|
|
|||
|
|
1. **能做成,且不需要给 WorkBuddy 打补丁、不需要开任何公网入站口。** WorkBuddy 的钩子契约支持 `permissionDecision: deny` + `permissionDecisionReason`(模型据此重写/继续)与 `additionalContext`(注入上下文)——【已验】本机已装的钩子正在用这两个字段,WorkBuddy 自身 CLI 内分别命中 96/70/42 处。
|
|||
|
|
2. **主要工作量在「客户端侧桥」,不在服务器侧。** 平台侧 IM 房间/消息/**面板(带可点按钮)**/插件桥端点**全部已存在**【源码在】;手机侧只需一个新页面。
|
|||
|
|
3. **有一条硬约束必须先拍板**:若该房间启用 IM 的 E2EE 档位,**设备侧桥(非人端)读不到明文** —— 这正是 IM 线当初记下的三代价之一「agent 代答须重做」。见 §3 D5。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1 现状资产盘点
|
|||
|
|
|
|||
|
|
### 1.1 直接复用(⛔ 不重造)
|
|||
|
|
|
|||
|
|
| 资产 | 载体 | 证据 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 覆盖网络中继 + 设备只拨出 | `src/net/relay/**`;设备节点 `overlay-node-daemon.ps1` | 【已验】真机端到端已跑通(设备声明端口 → 中继端点 → 平台解析 → 打回垫片) |
|
|||
|
|
| 配对仪式(二维码) | `src/web/routes/overlay-pair.ts` + `web/pair.html` | 【已验】六态、28 条判据全绿;生产 `pair.html`/`overlay-pair.js` 已部署 |
|
|||
|
|
| 设备台账与准入 | `overlay_devices` + device-web 四道闸 | 【已验】入口 200 + WS 101;无会话 401、他人设备 404 |
|
|||
|
|
| 用户级开关模式 | `users.device_web_enabled`(默认 0)+ `DSHS_DEVICE_WEB` 运维急停 | 【已验】S5 已上线,26/26 判据 |
|
|||
|
|
| IM 房间/成员/消息 | `src/im/**` + `/api/im/rooms/**` | 【源码在】消息收发/成员/在线态齐全 |
|
|||
|
|
| **IM 面板 + 动作(可点按钮)** | `/api/im/rooms/:id/panels[/:panelId/actions]` | 【源码在】`interactive = 有 onAction`;写入口唯一,`actorId` 取会话不取 body |
|
|||
|
|
| **IM 插件桥(双向长轮询)** | `/api/im/plugins/{register,out/message,out/frame,bridge,bridge/pull,bridge/result}` | 【源码在】M5 已实现插件侧客户端(含每插件令牌 + 实例级单例长轮询闸) |
|
|||
|
|
| **agent 触发与上下文内核** | `src/im/agent-bridge.ts`(370 行) | 【源码在】形态 A 能力机器人 / 形态 B **组员代理**(`autoReply`+`agentRef`)、四条硬约束 |
|
|||
|
|
| 问答数据模型 | 决策库(`options` / `ai_recommendation` / `user_*`) | 【已验】权威 PG `dsl-pg`,已落 135 行;SQLite 兜底 |
|
|||
|
|
| 钩子桥基础设施 | `settings.json.hooks` + `decision_bridge.py` | 【已验】四事件已挂、实测生效 |
|
|||
|
|
|
|||
|
|
### 1.2 需要新增(少量)
|
|||
|
|
|
|||
|
|
| 新增 | 归属 | 说明 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **M6「移动会话面」模块** | 服务器节点 · ai1net 插件 | 手机端问答台账 + 开关 + 面板注册(表前缀 `p_ai1net_mobile_`) |
|
|||
|
|
| **移动会话页** `web/mobile.html` | 服务器节点 · 平台 | 复用 `pair.html` 的登录态与版式;手机唯一入口 |
|
|||
|
|
| **设备侧桥** `wb-mobile-bridge` | 客户端 · 设备 | 本地回环口 + 平台长轮询 + 下行队列(**本方案主体工作量**) |
|
|||
|
|
| **WorkBuddy 钩子分支** | 客户端 · WorkBuddy | 在既有钩子桥上加"手机代答"分支(默认关) |
|
|||
|
|
|
|||
|
|
### 1.3 明确不做
|
|||
|
|
|
|||
|
|
⛔ 不新造第二套取址/中继协议 | ⛔ 不给 relay 加协议 op | ⛔ 不把设备升格为 worker | ⛔ 不引入 AA 式云中转 | ⛔ 不改官方 dsh/WorkBuddy 主程序。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2 架构
|
|||
|
|
|
|||
|
|
### 2.1 三层拓扑
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
① 手机浏览器
|
|||
|
|
https://ai1net.com/mobile.html ← 平台登录态 Cookie(复用)
|
|||
|
|
│ HTTPS 443
|
|||
|
|
▼
|
|||
|
|
② 服务器节点(+插件) 47.77.182.89
|
|||
|
|
├ 门户 / 账号 / 会话 (既有)
|
|||
|
|
├ 设备台账 overlay_devices (既有)
|
|||
|
|
├ IM 内核:房间·成员·消息·面板动作 (既有)
|
|||
|
|
├ 配对端点 overlay-pair (既有)
|
|||
|
|
├ 覆盖网络中继 relay(443 兜底) (既有)
|
|||
|
|
└ ai1net 插件:M5(插件桥)+ M6(移动会话面,新)
|
|||
|
|
▲ wss 反隧道(设备只拨出,⛔ 无公网入站口)
|
|||
|
|
│
|
|||
|
|
③ 客户端(+插件)= 用户自己的电脑
|
|||
|
|
├ 覆盖网络设备节点守护 (既有:overlay-node-daemon.ps1)
|
|||
|
|
├ 设备侧桥 wb-mobile-bridge (新:本地回环 + 平台长轮询)
|
|||
|
|
└ WorkBuddy + ai1net 插件 (钩子分支:手机代答,默认关)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2.2 两条通路(本方案的全部数据流)
|
|||
|
|
|
|||
|
|
**通路 A · 下行(会话 → 手机):让我在手机上看得见"它在等我"**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
WorkBuddy 触发钩子(SessionStart / PreToolUse^AskUserQuestion$ / SessionEnd)
|
|||
|
|
→ 钩子把事件投给本机回环的 设备侧桥(毫秒级,⛔ 不走网络)
|
|||
|
|
→ 桥经 IM 插件面 /api/im/plugins/out/message 上报(每插件令牌)
|
|||
|
|
→ 平台落到房间消息 + M6 台账(p_ai1net_mobile_questions)
|
|||
|
|
→ 手机在 mobile.html 看到「会话 X 在等你答复」+ 选项按钮
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**通路 B · 上行(手机 → 会话):把答案交回模型**
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
手机点选项 / 打字 → POST /api/im/rooms/:id/panels/:panelId/actions(成员校验)
|
|||
|
|
→ M6 面板 onAction 落台账 → 经 IM 插件桥下发(/bridge/result 或 out/frame)
|
|||
|
|
→ 设备侧桥收下并放进【本地答案队列】(带一次性 nonce)
|
|||
|
|
→ 钩子在下一个取用点把它交给模型:
|
|||
|
|
· PreToolUse(阻断式)⇒ permissionDecision:deny + permissionDecisionReason
|
|||
|
|
· UserPromptSubmit(队列式)⇒ additionalContext 注入
|
|||
|
|
→ 会话继续;结果再经通路 A 回手机
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
🔴 **一句话判据**:通路 A 让手机**看见**,通路 B 让手机**说话**;两者都只经**既有面**,⛔ 不新增对外服务。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3 关键设计决策(含取舍 · 可推翻)
|
|||
|
|
|
|||
|
|
| # | 决策 | 选了什么 | 理由 / 代价 |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| **D1** | 承载 | **走 IM 房间承载**,⛔ 不做"手机反代 WorkBuddy 界面" | WorkBuddy 是 Electron 外壳、**无对外 web 面**(承不承载得起反代:不能)⇒ 手机看的是**平台渲染的会话视图**,不是 WorkBuddy 的 UI。代价:视图要做一份,⛔ 不追求"逐像素同桌面" |
|
|||
|
|
| **D2** | 设备侧载体 | **独立守护进程(扩展设备节点)为主**;MCP app 作可选第二形态 | 守护不依赖 WorkBuddy 进程存活、钩子只需本地回环调用(毫秒级,远低于钩子超时);与既有 device shim 同构。代价:多一个要装的东西 |
|
|||
|
|
| **D3** | 触发形态 | **形态 B 组员代理**(`autoReply`+`agentRef`),⛔ 不用形态 A bot | 代理**不占成员位**、借用户本人身份回写 ⇒ 与"用户的会话"语义一致,且复用 agent-bridge 既有四条硬约束(禁自激/预算/静默期/排队) |
|
|||
|
|
| **D4** | 答案送达路径 | **两段式**:实时窗口内用阻断式;超时转队列式 | 钩子有超时上限【待实测具体值】⇒ 不能无限阻塞等待。超时后钩子仍返回 `deny` + reason「已推送到手机,请先暂停该动作」⇒ **会话不被卡死**(这是关键:⛔ 不能为了手机把桌面会话挂住) |
|
|||
|
|
| **D5** | **E2EE 档位** | **该房间不启用 E2EE**(走平台可见档) | 设备侧桥是非人端,加密房**读不到明文**;IM 线原决策已记此代价「agent 代答须重做」。代价:该房消息对平台可见 ⇒ 若不可接受,则须走"设备侧持钥+棘轮持久化"(另立一棒,成本显著更高) |
|
|||
|
|
| **D6** | 默认状态 | **默认关**(`users.mobile_reply_enabled = 0`),用户自己开 | 沿用 S5 已验证的开关模式;关闭时手机入口整体不存在 ⇒ **可见面零扩大** |
|
|||
|
|
| **D7** | 与桌面弹窗的关系 | **默认不拦弹窗**;仅在开"手机代答"且命中窗口时才接管 | 阻断式会 `deny` 掉原生弹窗(用户回桌面看不到)⇒ 必须由开关显式授权,⛔ 不静默抢答 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4 服务器节点(+插件)侧
|
|||
|
|
|
|||
|
|
### 4.1 平台进程(47 / 106)
|
|||
|
|
|
|||
|
|
| 项 | 内容 | 状态 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| IM 内核 | 房间 / 成员 / 消息 / **面板动作** | 复用,⛔ 零改动 |
|
|||
|
|
| 设备台账 + 四道闸 | `overlay_devices` + `deviceWebDecision` | 复用,⛔ 零改动 |
|
|||
|
|
| 配对 | `overlay-pair` 五端点 | 复用;新增一对「答题码」语义(见 4.3) |
|
|||
|
|
| 新增静态页 | `web/mobile.html`(移动会话页) | **新**(复用 `pair.html` 登录态/版式) |
|
|||
|
|
| 新增用户字段 | `users.mobile_reply_enabled`(默认 0,v19 迁移) | **新**(照 `device_web_enabled` 的 D 档流程) |
|
|||
|
|
|
|||
|
|
### 4.2 ai1net 插件 · 新增 M6「移动会话面」
|
|||
|
|
|
|||
|
|
- **一个包一个库**:仍 `dshs_pl_ai1net`;表名前缀 **`p_ai1net_mobile_`**(模块分段,⛔ 不与 M1–M5 混)。
|
|||
|
|
- **精确路径路由**(⛔ 全精确,无前缀/通配;沿用两端交集纪律):
|
|||
|
|
|
|||
|
|
| 方法 | 路径 | 干什么 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| GET | `/api/ai1net/mobile/pending` | 本设备待答问题列表(只回当前用户本人的设备) |
|
|||
|
|
| POST | `/api/ai1net/mobile/answer` | 提交答案(**只收一次**,带 nonce) |
|
|||
|
|
| GET | `/api/ai1net/mobile/state` | 开关 + 桥在线态 + 队列深度(给手机页首屏) |
|
|||
|
|
|
|||
|
|
- **卡片**:M6 出 1 张卡(`plugins.item` 槽位),显示「手机代答」开关 + 桥在线 + 今日问答数。
|
|||
|
|
- **面板注册**:M6 向 IM 注册一个交互面板(`onAction`),手机上的「选项按钮」即此面板的 action。
|
|||
|
|
|
|||
|
|
### 4.3 答案的一次性语义(⛔ 防重放)
|
|||
|
|
|
|||
|
|
沿用 `overlay-pair` 的码语义:每个待答问题带 **一次性 nonce**(128 bit CSPRNG),答案写入即烧码;重复提交 ⇒ `409`;过期 ⇒ `410`。**判据**:同 nonce 二次提交必拒。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5 客户端(+插件)侧
|
|||
|
|
|
|||
|
|
### 5.1 设备侧桥 `wb-mobile-bridge`(本方案主体)
|
|||
|
|
|
|||
|
|
| 职责 | 设计 | 判据 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 本地服务口 | **只绑 `127.0.0.1`**(沿用 device shim 纪律);⛔ 不暴露整机 | `ss -lntH` 只见回环;外部连不上 |
|
|||
|
|
| 平台长轮询 | 走 M5 既有插件桥(`/api/im/plugins/bridge` 长轮询 + `/pull` + `/result`);**每插件令牌 fail-closed** | 取不到令牌 ⇒ 不发任何请求 |
|
|||
|
|
| 答案队列 | 本地落盘队列(带 nonce + 过期时间),供钩子按序取用 | 队列可回读、可对账;过期项具名丢弃 |
|
|||
|
|
| 下行上报 | 会话事件(含待答题干/选项)→ 平台 IM | 平台侧可见即判通 |
|
|||
|
|
| 生命周期 | 随设备节点守护起停(复用 `-Action install/uninstall`) | 停守护 ⇒ 平台立刻"离线"(具名状态,⛔ 不静默) |
|
|||
|
|
|
|||
|
|
### 5.2 WorkBuddy 钩子分支(在既有钩子桥上增,⛔ 不改其原有行为)
|
|||
|
|
|
|||
|
|
| 事件 | 原行为(保留) | 新增分支 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `SessionStart` | 注入提问规范 | + 向桥注册本会话(拿到会话键) |
|
|||
|
|
| `PreToolUse ^AskUserQuestion$` | 提问规范门 + 落库 | + **若开关开**:上报待答 → 短窗等待 → 命中则 `deny` + `permissionDecisionReason="用户已在手机上作答:<选项>(<理由>)—— 这是答复,不是拒绝"` |
|
|||
|
|
| `UserPromptSubmit` | 逐轮识别 + 回收决策 | + 若队列有**未取用**答案 ⇒ `additionalContext` 注入 |
|
|||
|
|
| `SessionEnd` | 未答收口 | + 桥侧会话下线 |
|
|||
|
|
|
|||
|
|
🔴 **两条硬纪律**(沿用既有钩子桥的教训):
|
|||
|
|
1. **fail-open** —— 桥不可达/超时/异常 ⇒ **按原逻辑放行**,⛔ 绝不因为手机把桌面会话弄坏;
|
|||
|
|
2. **留痕先于一切** —— 每次取用/放弃都写审计流水,⛔ 否则"没调用"与"静默失败"无法区分(该桥已因此踩过坑)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6 数据面(插件库 `dshs_pl_ai1net`)
|
|||
|
|
|
|||
|
|
| 表 | 关键列 | 用途 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `p_ai1net_mobile_questions` | `question_id` · `device_id` · `session_key` · `stem` · `options_json` · `state` · `nonce` · `expires_at` | 待答问题 |
|
|||
|
|
| `p_ai1net_mobile_answers` | `question_id` · `actor_user_id` · `choice` · `text` · `via` · `answered_at` | 作答(`actor_user_id` 恒取会话) |
|
|||
|
|
| `p_ai1net_mobile_outbox` | `seq` · `device_id` · `kind` · `payload_json` · `state` | 下行待投递队列 |
|
|||
|
|
|
|||
|
|
- ⛔ **包内零数据库动作**(不 import 驱动、不拼 SQL)—— 沿用 `DB-03 §二` 红线;建库在平台侧,**先建库再投放**。
|
|||
|
|
- 列级 `maxBytes` 唯一把关人仍是包内 `data-limits.js`;**改声明必回读两处**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7 分阶段实施(每棒做完即停,判据可机器验)
|
|||
|
|
|
|||
|
|
| 棒 | 目标 | 验收判据(可机器验) |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **S1** | 设备侧桥骨架:本地回环口 + IM 插件注册 + 长轮询 | 注册 `200`;长轮询有包;`ss` 只见 `127.0.0.1`;取不到令牌 ⇒ 具名拒绝 |
|
|||
|
|
| **S2** | **下行通路**:钩子上报 → 手机可见 | 手机页出现该会话待答项;题干/选项与桌面弹窗一致(逐字比对) |
|
|||
|
|
| **S3** | **上行·作答**:手机作答 → 模型收到 | 会话继续且模型回复/动作体现**用户所选**;同 nonce 二次提交 `409`;过期 `410` |
|
|||
|
|
| **S4** | **上行·续聊**:手机自由发言 | 注入生效(`additionalContext` 或 automation 起新会话),且**不打断**正在跑的任务 |
|
|||
|
|
| **S5** | 开关 + 台账 + 手机页收口 | 开关关 ⇒ 入口与阻断**整体不存在**(可见面零扩大);开关开 ⇒ 全链 200/101 |
|
|||
|
|
| **S6** | 真机 + 回归 | 真手机端到端一次;**既有线零回归**(配对 28 条 · S5 26 条 · 既有入口无变化) |
|
|||
|
|
|
|||
|
|
🔴 每棒的"完成"= **交付门禁**通过(⛔ 改完/build 过/已 commit 都不算交付)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8 安全与权限(R5:本方案只收窄,不扩大)
|
|||
|
|
|
|||
|
|
| 面 | 处置 |
|
|||
|
|
|---|---|
|
|||
|
|
| 设备侧暴露 | **只绑回环**;⛔ 不新开公网入站口(复用 443);端口窗口沿用 `20000..20999` |
|
|||
|
|
| 平台准入 | 复用四道闸(平台开关 / 登录用户本人 / 台账 active+desktop / relay 有在线口) |
|
|||
|
|
| 身份键 | `actorId` **恒取会话**,⛔ 不取 body 自报值(沿用既有纪律) |
|
|||
|
|
| 凭据 | 长期设备凭据仍**只落设备侧**;手机**从不持有**设备凭据(沿用配对线的 G5 结论) |
|
|||
|
|
| 一次性 | 每个答案带 nonce,写即烧(§4.3) |
|
|||
|
|
| 默认状态 | 全链**默认关**;开启 = 用户显式动作(D6) |
|
|||
|
|
| 内容可见性 | 🔴 本节最需注意:走平台可见档(D5)⇒ 会话正文对该房间平台侧可见。**这是本方案唯一的"面扩大",必须由用户拍板** |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9 回滚(每项都有独立回滚点)
|
|||
|
|
|
|||
|
|
| 变更 | 回滚 |
|
|||
|
|
|---|---|
|
|||
|
|
| 钩子新增分支 | 摘钩子(既有 `install_hooks --rollback` 幂等)或设 `DSH_DECISION_OFF=1` 秒级急停 |
|
|||
|
|
| 用户开关 | `users.mobile_reply_enabled` 置 `0` ⇒ 入口与阻断立即消失 |
|
|||
|
|
| 设备侧桥 | 设备节点守护 `-Action uninstall`;桥进程停止 ⇒ 平台显示离线 |
|
|||
|
|
| 平台静态页/路由 | 删 `mobile.html` + 撤回路由(生产 `lib-bak-*` 兜底) |
|
|||
|
|
| 插件 M6 | 模块级回滚(表分段 ⇒ 一次迁移牵动不了 M1–M5) |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 10 未验证项与风险(⛔ 不得当成已定)
|
|||
|
|
|
|||
|
|
1. **钩子超时的实际上限**【待实测】—— 决定前置窗口 T1 能开多长;若上限很短 ⇒ 直接以 D4 的队列式为主。
|
|||
|
|
2. **`deny` 语义对模型的真实影响**【待实测】—— 模型可能把 deny 读成"工具被拒"而非"用户答复"。缓解:`reason` 里写明"这是答复不是拒绝",并在 S3 用真机验收;⛔ 不靠猜。
|
|||
|
|
3. **阻断式会吞掉桌面弹窗**(D7)—— 产品取舍,已用开关收敛;⚠️ 若用户同时在桌面点,存在双答竞速 ⇒ 需"先到先得 + 另一方收到具名失效"。
|
|||
|
|
4. **MCP app 作第二载体的进程生命周期**【未公开】—— 采用与否以实测为准。
|
|||
|
|
5. **WorkBuddy 升级可能改钩子契约** —— 红线 R1:⛔ 不自动升级;契约变更须走独立"测试→评估→修复"。
|
|||
|
|
6. **决策库遗留缺陷会污染问答对**(该库自报:同题重复识别、答复错配 2 条)—— 若 M6 复用其口径,须先排除,⛔ 否则答案可信度受损。
|
|||
|
|
7. **权威库不自起**(`dsl-pg` 实测处于 Exited 状态)—— 若复用决策库,须纳入探活。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 11 边界(⛔ 不重造清单,交付时逐条自查)
|
|||
|
|
|
|||
|
|
1. ⛔ 不新造取址 / 中继协议 / 第二套配对 / 第二套 IM 内核(全部已在)。
|
|||
|
|
2. ⛔ 不让设备成为"被外部直接连入"的一方(设备只拨出;D8 用户已拍板"先不开端口")。
|
|||
|
|
3. ⛔ 不把设备升格为平台 worker(沿用既有决定:设备形态 =「带端口的终端」)。
|
|||
|
|
4. ⛔ 不在服务器上 build(`/opt/dshs/src` 陈旧,会盖坏产物)。
|
|||
|
|
5. ⛔ 不引入 AA 云中转(用户已定 B 方案:用自己的覆盖网络)。
|
|||
|
|
6. ⛔ 不跨线并行改 `aliyun-dsh-server` / `ai1net-dsh-desktop`(各线在活动)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 附录:本次取证读数(可复跑)
|
|||
|
|
|
|||
|
|
| # | 取证点 | 读数 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | `strings app.asar \| grep hookSpecificOutput/permissionDecision/additionalContext` | **96 / 70 / 42** —— 契约字段存在 |
|
|||
|
|
| 2 | 本机已装钩子 `decision_bridge.py` | 用 `permissionDecision:deny`+`permissionDecisionReason` 打回残缺提问;用 `additionalContext` 注入常驻规矩 ⇒ **契约在跑** |
|
|||
|
|
| 3 | `settings.json` hooks | 四事件(SessionStart / PreToolUse `^AskUserQuestion$` / UserPromptSubmit / SessionEnd) |
|
|||
|
|
| 4 | `src/web/routes/im.ts` | 房间/成员/消息/**panels**/**panels actions**/插件桥(register·out·bridge·pull·result)/gateway/presence/stats 全在位 |
|
|||
|
|
| 5 | `src/im/agent-bridge.ts` | 370 行;形态 A bot / 形态 B 组员代理;四条硬约束(禁自激·预算·静默期·房间级限速排队) |
|
|||
|
|
| 6 | `overlay-pair` + `pair.html` | 六态、28 条判据全绿、生产已部署 |
|
|||
|
|
| 7 | `users.device_web_enabled` + S5 | 用户级开关模式已验证(默认 0) |
|
|||
|
|
| 8 | `E:/dsh-worker-dev/bin/overlay-node-daemon.ps1` | 设备节点守护在位(含 `-Action install/uninstall/status`) |
|
|||
|
|
| 9 | `dsh-plugin-ai1net` M5 | 插件侧 SDK 已实现(每插件令牌 + 单例长轮询闸) |
|