jayantTang/DSH_Mobile

DSH_Mobile

在 iPhone 上远程使用电脑的 DeepSeek Harness:WSS 经公网中转,4G/5G 可用,电脑不需要公网 IP。Native iOS client for remote DSH sessions.

미분류agentdeepseek-harnessdsh

DSH Mobile

中文 · English

把电脑上的 DSH 会话接到 iPhone 上:原生 iOS 客户端、电脑侧连接器、可自建的公网中转。手机与电脑连接同一个 DSH host,看到同一批会话与同一条 消息流;电脑上运行中的任务在锁屏后继续执行,电脑上挂起的提问可在手机上直接回答。

电脑不需要公网 IP,也不需要 VPN。

配图为 App Store 宣传图(8 张中的 4 张,横版拼合),内容出自同一套合成会话:输出是真实 agent
输出,项目为虚构,relay.example.com 是占位符。分张素材与生成方式见 docs/artifacts/demo/。

状态与兼容性

组件 · 当前版本 · 分发方式 iOS App · 1.0 · TestFlight 公开测试(加入);需先安装 TestFlight,构建 90 天后过期 连接器 dsh-plugin-mobile-link · 0.6.0 · npm 中转(DLP v1) · 本仓库 relay-go/(Go,go-0.1.2) · 自行部署

三者的版本组合与发布策略见 docs/VERSIONING.md。 表中版本以 npm 上已发布的为准(npm view dsh-plugin-mobile-link version),不是仓库里 package.json 的值。

前提

  • 电脑上已安装并可运行 DSH(dsh web)。
  • 连接器需要 Node.js ≥ 22。
  • 自建中转需要一台有公网 IP 的主机(macOS 或 Linux)与 Caddy。
  • 从源码构建 App 需要 macOS + Xcode 16 以上;日常使用不需要。

快速开始

A. 使用公共中转

  1. 手机上安装 App:先装 Apple 的 TestFlight,再用 加入测试。
  2. 电脑上安装连接器——按宿主装(两种宿主档案独立,装错不会报错,只是连接器不会被加载):
  • 命令行 web 版(终端里跑 dsh web):dsh plugin --profile web add dsh-plugin-mobile-link
  • 官方桌面版(双击图标打开的应用):用应用内的插件页,或应用自带的 dsh 命令装进 desktop 档案

(普通 npm 版 dsh 会拒绝该档案,这是官方设计)。宿主形态的识别判据(双击图标启动还是敲命令启动)见 docs/ONBOARDING.md。

  1. 登记到中转:dsh-mobile-link enroll --invite --relay wss:///dsh-link
  2. 让连接器用上这个身份:重启一次宿主(dsh web),或在启动时就带上邀请码

(DSH_MOBILE_LINK_INVITE= dsh web)。第 2 步装插件本身不需要重启——命令行 web 宿主会 自己把新装的插件挂上;桌面版按应用内提示。

  1. 手机 App →「扫码配对」,扫描电脑上的二维码:点 DSH 界面左下角的「移动端连接」,小窗里就是

二维码、配对码与有效期(也可用 node scripts/dev/show-pair-qr.mjs 在没有界面的环境里出图)。

邀请码为一次性、绑定一台电脑,在 issue #1 领取; 中转地址与邀请码写在同一行。登录后确认手机顶部显示「已连接」,即为成功。故障排查见 docs/ONBOARDING.md。

B. 自建中转

自建使用仓库内的 Go 实现(relay-go/)。按 relay-go/deploy/README.md §2–§3 在服务器上构建二进制、写入 build.json 并安装 dsh-relay-go.service;Caddy 路由用 relay-go/deploy/Caddyfile.snippet,由 relay-go/deploy/caddy_splice.py 插入既有站点块(§4)。

# 首次部署
sudo systemctl enable --now dsh-relay-go

# 建账号 → 铸邀请码
/opt/dsh-relay-go/bin/dsh-relay admin --db /var/lib/dsh-relay/state.db \
    account-create --name "<名称>"
/opt/dsh-relay-go/bin/dsh-relay admin --db /var/lib/dsh-relay/state.db \
    invite-mint --note "<备注>" --count 1 --relay wss://<站点>/dsh-link

铸出的邀请码回到 A 的第 3 步使用。实时负载与每设备流量: curl -s http://127.0.0.1:8787/stats(仅监听回环)。限额与运维细节见 relay-go/README.md 与 relay-go/deploy/README.md。

组件与数据流

┌──────────────┐   WSS    ┌────────────────────┐   WSS    ┌───────────────────┐
│  iPhone App  ├─────────►│  Relay(公网主机)  │◄─────────┤ 电脑侧连接器       │
│  SwiftUI     │          │  鉴权 + 转发        │          │ (DSH 插件)        │
└──────────────┘          └────────────────────┘          └─────────┬─────────┘
                                                                     │ HTTP + WS
                                                           ┌─────────▼─────────┐
                                                           │ dsh web           │
                                                           │ 127.0.0.1:<port>  │
                                                           └───────────────────┘

组件 · 位置 · 职责 iOS App · 手机 · 会话列表、转写、图片与文件、配对与设备管理 连接器 · 电脑(DSH 插件) · 以 127.0.0.1 访问本机 DSH,转成中转帧 中转 · 公网主机 · 鉴权与按 agentId 转发;不解析会话内容 DSH host · 电脑 · 会话、agent 与工具的真实执行方

产品上只提供经中转这一条连接方式(dsh://direct 是 DEBUG-only 的测试通道)。选型与边界见 docs/ARCHITECTURE.md 与 docs/PAIRING.md。

配置

仓库中出现的 relay.example.com 一律是占位符:中转地址属于部署方,不属于仓库。真值只存在于本机, 且均被 gitignore:

位置 · 用途 · 提供方式 .env.local · 发布脚本、开发探针 · cp .env.example .env.local,填 DSH_SITE / DSH_RELAY_URL / DSH_OTA_HOST ~/.dsh/mobile-link/agent.json · 连接器的中转地址与身份 · dsh-mobile-link enroll --invite --relay ios/DSHMobile/Config.local.xcconfig · App 内预填的中转地址与更新源 · 从 Config.xcconfig 复制后填写

因此直接 clone 构建出的 App 默认连不上任何中转,这是有意设计。

开发

cd ios/DSHMobile/DSHKit && swift test        # 协议层
cd plugins/mobile-link  && npm test          # 连接器
cd relay-go && make test                     # 中转(Go,生产实现)
cd relay && .venv/bin/python -m pytest -q    # 中转回滚实现与黑盒契约基线
npm run check:secrets                        # 本机真值没有进跟踪文件
npm run check:docs                           # 文档规范(结构、口吻、链接)

cd ios/DSHMobile && xcodebuild -scheme DSHMobile \
  -destination 'platform=iOS Simulator,name=DSH-Test' build

上述单测与一次「不带任何本机配置」的 Release 构建由 GitHub Actions 在干净仓库上执行。需要仿真器、 真实中转或开发者团队 ID 的验证不在 CI 内——CI 通过不等于可以发布。

界面测试是一套独立测试台:./test/run.sh prepare → run → report --verdict …,口径见 test/RULES.md,可复制的用例模板见 test/examples/。

文档

文档 · 内容 docs/ONBOARDING.md · 两种部署路径的选择、操作步骤、故障排查 docs/GLOSSARY.md · 术语表(DSH、host、连接器、中转、DLP 等) docs/ARCHITECTURE.md · 架构与关键决策 docs/DSH-PROTOCOL.md · DSH 原生协议参考(权威、面向实现) docs/RELAY-PROTOCOL.md · DLP v1 中转协议规范 docs/CONNECTOR-NOTES.md / docs/RELAY-NOTES.md · 实现与规范的偏差记录 docs/PAIRING.md · 连接方式与配对设计 docs/IMAGES.md · 图片能力的设计约束与实现 docs/VERSIONING.md · 三处部署的版本与发布策略 docs/PRIVACY.md · 隐私说明:App 不收集数据,中转只做转发 docs/dsh-rpc-catalog.json · 某次快照:机器可读的 RPC 目录(不是持续校验的契约) docs/artifacts/samples/ · 从真实 DSH 抓取的响应样例(已脱敏)

参与开发见 CONTRIBUTING.md,安全问题的报告方式见 SECURITY.md, 版本变化见 CHANGELOG.md。

已知限制

  • iOS 安装走 TestFlight:需先安装 Apple 的 TestFlight;测试构建 90 天后过期,到期需安装新构建。

自行部署时也可以走 OTA(部署脚本会生成 https:///ios/):那用 Ad Hoc 描述文件, 只覆盖已登记 UDID 的设备,适合自己用,不适合公开分发。

  • 后台通知覆盖这些场景:从手机发出任务后把 App 退到后台,任务完成、以及 Agent 提问后

等待回答(App 列表顶部会显示一条待回应提示)这两件事,仍会通知到手机。它只在 「有任务在跑,或有待回答的提问」时生效,空闲时不耗电。

  • 这些场景不覆盖:手机在后台时,电脑端新开始的会话唤不起 App(需要 APNs,尚未实现);

长时间未回答的提问可能丢失。

  • 文件发送仅在经中转时可用。

许可

MIT,见 LICENSE。