# 交接单 · 桌面线:设备接入垫片**常驻化**(V1 最后一跳) - 出具:主会话(手机接入线)· 2026-09-30 10:2x - 归属线:**ai1net-dsh-desktop**(桌面/客户端线) - 目标:手机查看并可回复桌面 WorkBuddy 中会话(`[手机接入]`) - 🔴 **这一件是 V1 的最后一跳**(V2–V7 已全 pass,V1 唯一非 pass) ## 一、你接手时的既成事实(⛔ 别重做,别推翻) **A 方案(口令入站通道)已由本线落地并端到端实证** —— 它解决的是"**脱离会话起的垫片拿不到网关口令**": | 侧 | 改了什么 | 位置 | |---|---|---| | 插件侧 | 新增只绑回环的 `POST /__device_access/token`:**内存持有**(不落盘/不进日志/不回显)+ **探活通过才采纳**;`credentialDesc()`/`readGatewayToken()` 改为 **env 优先、其次内存入站** | `E:/ProgramData/AIProject/dsh-plugin-ai1net/lib/device-access.js`(模块⑥;`dist/` 已同步,md5 与 lib 一致) | | 宿主侧 | `deliver-gateway-token.py`(在哪一侧投、60s 节流、只打回环、失败静默 rc=0)+ 钩子 `PreToolUse` 接管 | `…ai1net-dsh-server/.workbuddy/collab/deliver-gateway-token.py`、`.workbuddy/tools/wb-result-hook.py` | **实测读数(可复跑)**: ``` 脱离会话式起法(env 里没有口令) 自检 → credential.source=missing present=false ← 现状:只能 503 塞错口令 → 400 token-rejected-by-gateway ← 安全阀有效,⛔ 没被塞坏 投真口令 → 200 {"credential":{"source":"inbound","present":true}} 经垫片打 /api/v1/health → 200 ← 口令真被带上并转发成功 ``` 🔑 **由此解掉的那个堵点**:A 之前"用计划任务起桌面栈"是**走不通**的(计划任务上下文 `envPresent=false / envLen=0`,垫片 fail-closed `rc=3`)⇒ **现在不堵了**:垫片能在**没有口令**的情况下先起来(它只在 20090 上监听,"口令缺失"不阻止监听),随后由钩子把口令投进去。 ## 二、请你做的(三件,按顺序) 1. **找/确认"不起 Electron UI 也能把 DSH 宿主拉起来"的起法** - 已知障碍:`launch-desktop-dev-017.mts`(`ai1net-dsh-desktop/.workbuddy/_devkit/`)**没有无界面开关**,它 `require('electron')` 并用 **electron 内置 node** 跑宿主(`release.nodeVersion = electron 的 node 版本`)。 - 要判的:`apps/desktop-host`(`@deepseek-ai/dsh-desktop-host`,`main=lib/index.js`)能否用**普通 node** 直接起(它是否真依赖 Electron API)。**能** ⇒ 首选;**不能** ⇒ 走"启动文件夹/独立窗口"(`deploy.md §5b` 已列的三条死路之外那条可行路)。 2. **把它做成durable**(⛔ 挂在某个会话名下会随会话回收而断 —— 这是已知遗留单点) - 候选:**启动文件夹** / **计划任务**(`schtasks` 被程序黑名单硬拦,但 §5b 说计划任务这条路对**中继客户端**已走通 ⇒ 照那条走)。 - ✅ A 已使"计划任务"重新可行(见上)。 3. **起来了就验**(判据,⛔ 不许只看"进程在") - `20090` **LISTENING**(⛔ 只认 `netstat`,本机有 Proxifier 会代理回环 ⇒ `curl`/`connect` 会假阳); - `curl --noproxy '*' http://127.0.0.1:20090/__device_access/selfcheck` ⇒ `credential.present=true`(`source` 应为 `env:…` 或 `inbound`); - `curl --noproxy '*' http://127.0.0.1:20090/api/v1/health` ⇒ **非 401**; - **最后一枪**:打平台设备入口 `https://ai1net.com/u/bdf89014-c66f-4060-a2df-995d8c18a951/desk/d-bdf89014-c66f-4060-a2df-995d8c18a951-626dc095/api/v1/info`(**要带门户会话 Cookie**)⇒ **不再是 `503 {"error":"instance_starting"}`**。 ⚠️ 复现姿势(我踩过):`sid` 是 **Secure** cookie ⇒ `http://127.0.0.1:3080` **不带 Cookie**会假回 401;必须 `curl -k --resolve ai1net.com:443:127.0.0.1` 走 https。 - 验不到口令自动进来时:`curl -X POST --data "<口令>" http://127.0.0.1:20090/__device_access/token`(⚠️ 别把口令写进命令历史/日志)。 ## 三、边界(⛔ 越线即事故) - ⛔ **不要改 A 的通道设计**(尤其⛔ 不许去掉"**探活通过才采纳**"那一步 —— 只绑回环的端点若无条件采纳,一个错口令就能把垫片打成持续 401)。 - ⛔ **不要让口令落盘**(不改回 C 方案)。 - ⛔ 不动正在跑的看板 `127.0.0.1:8788`(它是主会话起的,还挂着)。 - ⛔ 不动中继客户端(`DSH-Overlay-Node-Dev`):它已治本、且是手机接入线的关键路径。 - ⚠️ 若判断"必须起 Electron UI",**先回报**(那会弹窗口且活不过会话,净收益要重新算)。 ## 四、判据汇总(做完回报用) | # | 判据 | 期望 | |---|---|---| | 1 | `20090` LISTENING | ✅(只认 netstat) | | 2 | 自检 `credential.present` | `true`(`source=env:*` 或 `inbound`) | | 3 | 经垫片 `/api/v1/health` | 非 401 | | 4 | 平台设备入口 | **不再 503 `instance_starting`** | | 5 | 起法是否 durable | 说明挂在哪个持久机制上(启动文件夹/计划任务),⛔ 不是"某条会话" | **回报落点**:本工作区 `交付物/`,并在回报里**明确写**「V1 的最后一跳是否打通」——它决定 `goal.json.acceptance_state.V1` 能否置 pass。