packages/dsh-remote-web-ui
zhu1090093659/dsh-web手机/PC 远程操控 dsh web 工作区:扫码配对、令牌门控通道、SSE 实时同步,提供移动端与完整桌面 GUI 两种远程形态。
Android 配套桥接:局域网扫码配对(可吊销的设备 Token 与 TLS 指纹)、手机连接与设备管理面板,以及向配对原生 App 提供会话、实时事件与审批的 HTTPS 接入代理。
Android:以下都是 App 的真实渲染(Compose 截图测试基线,apps/android/app/src/screenshotTestDebug/reference/),示例数据为虚构。
截图基线由 .github/workflows/regen-screenshots.yml 自动生成,已覆盖浅色 / 深色、中文 / 英文、普通 / 大字号。
![]() | ![]() | ![]() | ![]() |
| 首页 · 等你处理 / 进行中 / 最近 | 对话 · 正文、改动卡与输入区 | 看改动 · 文件差异 | 设置 |
![]() 01 · 首页 · 等你处理 / 进行中 / 最近 | ![]() 02 · 对话 · 正文、改动卡与输入区 | ![]() 03 · 审批 · 决策栏替换输入区 |
![]() 04 · 看改动 · 文件差异 | ![]() 05 · 设置 | ![]() 06 · 新任务 |
![]() 07 · 电脑离线 | ![]() 08 · 轨迹 | ![]() 09 · 欢迎 / 扫码配对 |
![]() 10 · 等电脑批准 | ![]() 11 · 首页 · 深色 / 英文 | ![]() 12 · 对话 · 深色 / 英文 |
![]() 13 · 审批 · 深色 / 英文 | ![]() 14 · 改动列表 · 深色 | ![]() 15 · 外观设置 · 深色 / 英文 |
iOS:同样是 App 的真实渲染(SwiftUI 截图测试基线,apps/ios/Tests/__Snapshots__/),示例数据为虚构。
基线只由 .github/workflows/ios-regen-screenshots.yml 在 CI 上重录,不在本地生成;命名约定 Snapshot_<页面号>_<场景>_<light|dark>_<zh|en>.<variant>.png,主页面覆盖浅 / 深 × 中 / 英 × 默认 / 大字号(accessibility3)。
![]() | ![]() | ![]() | ![]() |
| 首页 · 等你处理 | 对话 · 运行中 | 审批 · 决策栏替换输入区 | 看改动 · 本轮改动列表 |
![]() 首页 · 深色 / 英文 | ![]() 设置 · 浅色 / 中文 | ![]() 欢迎 / 扫码配对 · 深色 / 英文 |
[!IMPORTANT] 本项目为独立的社区项目。 Cetus 与 DeepSeek 无隶属、授权或背书关系;DeepSeek Harness 的名称与相关标识归各自所有者。问题请在本仓库反馈,不要提交给上游。
项目处于公开 Beta。 正式支持范围是可信局域网。出门优先用 Tailscale(零服务器、直连);中继(DLP/1)是免配置备选,仍为实验性功能。插件、App 与同步协议迭代较快,升级前请看
CHANGELOG.md与 兼容矩阵。
电脑和手机在同一个 Tailscale 网络里时,配对二维码会自动带上 Tailscale 地址。手机先试局域网主地址,不通再试这条直连,都失败才走中继。不需要自己填 100.x 地址,也不用另开一台服务器。中继是没装 Tailscale 时的免配置备选。细节见 REMOTE_ACCESS.md。
iOS 的后台不给常驻 SSE,手机离开 App 后就没有连接;推送网关补上这一段。它由用户电脑上的插件把端到端加密的通知密文交给一个开源、无状态的网关,网关只把密文转给 APNs——看不到通知内容,也没有任何路径向电脑下命令。批准与回复仍走局域网 / Tailscale / DLP/1 中继。
K(AES-256-GCM)在插件侧加密,K 只存在手机 Keychain 与插件 state 里;网关拿不到,也伪造不出可被通知扩展解密的通知。逐字节协议合同(POST /v1/push、GET /v1/keys、GET /healthz、密钥与字段定义、错误码与红线)见 docs/rfc/0002-push-gateway.md;网关实现(Go,cmd/dlpush)在 push/,可与官方网关互换自建。
Cetus 让运行在电脑、家中主机或远程服务器上的 DeepSeek Harness 拥有一个经过配对的原生手机入口。电脑继续运行 DSH、工具与工作区;手机负责看会话、发消息、收实时事件、处理审批与提问。
它不是远程桌面,也不是把 DSH Web 塞进手机浏览器:一个仓库、四个发布物、一条配对信任链。
| 发布物 | 位置 | 作用 | 分发 |
|---|---|---|---|
DSH 插件 dsh-cetus | src/ | 手机 HTTPS 接入代理、配对与设备状态机、电脑端「手机连接」面板 | 本仓 git 源(github:lunaship/dsh-cetus,固定版本见 Releases) |
| Android App | apps/android/ | 扫码配对、原生会话工作台、实时流、审批与提问 | 签名 APK,见 Releases(app-v*) |
| iOS App | apps/ios/ | 同上的原生 iOS 客户端(SwiftUI,iOS 26+),另含通知扩展与 Live Activity | 源码公开;需自行用 Xcode 签名构建,官方构建待发布 |
| Relay | relay/ | 远程连接的哑管道中继(DLP/1,cmd/dlp-relay),只拼接两条 WSS | 源码公开;可用官方中继或自建,无需接入码 |
| Push Gateway | push/ | 无状态推送网关(DLPUSH/1,cmd/dlpush),只把端到端加密的通知密文转给 APNs | 源码公开;官方网关或自建,默认关闭 |
stateDir,不碰真实配对——这条规则来自一次真实事故,写在 AGENTS.md 的红线里。capabilities.control)。/plan、/goal 等)。flowchart LR
subgraph Phone ["手机"]
AppA["Android App<br/>Kotlin · Jetpack Compose"]
AppI["iOS App<br/>SwiftUI · Liquid Glass"]
end
subgraph Computer ["运行 DSH 的电脑"]
direction TB
Plugin["dsh-cetus 插件<br/>手机 API · 配对与设备状态机"]
Panel["「手机连接」面板<br/>仅本机回环"]
Host["DSH Host<br/>会话 · 工具 · 工作区"]
end
Relay["Relay(Go · DLP/1)<br/>只拼接两条 WSS"]
Push["Push Gateway(Go · DLPUSH/1)<br/>无状态 · 只转密文"]
APNs["APNs"]
AppA <-->|"HTTPS + 设备 token<br/>SSE:事件 · 审批 · 提问"| Plugin
AppI <-->|"HTTPS + 设备 token<br/>SSE:事件 · 审批 · 提问"| Plugin
Panel -->|"同源回环 POST"| Plugin
Plugin -->|"回环 RPC · 127.0.0.1"| Host
AppA -.->|"远程(同一张连接码)"| Relay
AppI -.->|"远程(同一张连接码)"| Relay
Relay -.->|"内层 TLS 字节流"| Plugin
Plugin -.->|"端到端加密密文(默认关闭)"| Push
Push -.->|"HTTP/2 + JWT"| APNs
APNs -.->|"NSE 本地解密"| AppI
一条请求的生命线、目录契约与两条关键设计线(审批式工作区注册、SSE 续传)见 docs/ARCHITECTURE.md;手机 API 的字段级契约见 docs/MOBILE_SYNC_CONTRACT.md。
dsh-cetus/
├── src/ # DSH 插件
│ ├── index.js # 入口:路由注册、配对 / 设备状态机、Runtime 装配
│ ├── mobile-api.js # 手机 HTTPS API 唯一实现(/dsh-link/mobile/*)
│ ├── panel.js # 「手机连接」面板源码(client.js 由 build-client.mjs 生成)
│ ├── workspace-*.js # 工作区注册、改动转发、文件与目录沙箱
│ └── remote/ # 远程连接:Agent、运行时、state(DLP/1)
├── relay/ # DLP/1 中继服务端(Go,dlp-relay),独立部署
├── push/ # DLPUSH/1 推送网关(Go,dlpush),无状态、只转密文
├── apps/ios/ # iOS App(XcodeGen:xcodegen generate 后用 Xcode 打开)
│ ├── App/ # SwiftUI 界面(Features 按页面分目录)
│ ├── Packages/ # DLModels / DLCore / DLSecurity / DLNet / DLRemote / DLUI
│ ├── Extensions/ # NotificationService(NSE 解密)、LiveActivity、Share
│ ├── Tests/__Snapshots__/ # SwiftUI 截图测试基线(只由 CI 重录)
│ └── docs/ # 页面对照表与 iOS 视觉规则
├── apps/android/ # Android App(Android Studio 打开这里)
│ ├── app/src/main/java/dev/deeplinks/
│ │ ├── core/ # 跨屏契约:主题 / 排版 / 颜色 token、本地化、加密、布局推导
│ │ │ └── remote/ # DLP/1:自动选路、隧道 socket、远程路由
│ │ ├── native/ # 工作台屏幕与 Compose 组件
│ │ └── devices/ # 配对、扫码与设备管理
│ ├── app/src/test/ # JVM 单测与架构门禁(token / 间距 / 色源 / 体量预算)
│ ├── app/src/screenshotTest/ # Compose 截图测试;基准图在 screenshotTestDebug/reference
│ └── docs/ # 视觉合同与 UI 贡献规则
├── test/ # 插件 node:test 套件
├── scripts/ # 真中继端到端、架构冒烟、内测证据收集
├── testdata/dlp1/ # DLP/1 三端共用测试向量(JS / Go / Kotlin)
├── testdata/push/ # DLPUSH/1 加密测试向量(hpke / content)
└── docs/ # 架构、同步契约、兼容矩阵、RFC、内测计划
在运行 DSH 的电脑上安装插件,并启动 DSH Web:
dsh plugin --profile web add github:lunaship/dsh-cetus
dsh web
上面装的是 main(当前 Beta 源)。要固定版本,在地址后加 Releases 里的插件 tag,例如 #v0.1.0-beta.18;插件与 App 的配套关系见 兼容矩阵。
配对:打开 DSH Web 设置 →「手机连接」,用 App「扫描二维码」或「从相册识别」(选择一张含连接二维码的截图)完成配对。
开始使用:在 App 里选择已配对的电脑,进入会话工作台。
[!NOTE] 配对不需要账号。远程访问(内置远程连接、Tailscale、Cloudflare Tunnel)见
REMOTE_ACCESS.md。不要把18640端口直接做路由器端口转发。
>= 20,pnpm(插件依赖锁定在 pnpm-lock.yaml)minSdk 26、targetSdk 36;AGP 9.3、Kotlin 2.4)1.25(仅中继与推送网关,两个模块各自独立)brew install xcodegen)pnpm install
npm run prepack # 生成面板 client.js + 全量测试
npm test # 仅跑 node:test 套件
开发期可直接挂本地目录:dsh plugin --profile web add /path/to/dsh-cetus。改完源码需重启 host 才生效。
[!WARNING] 插件 state 默认全局共享(
~/.dsh/dsh-cetus/state.json,不分 profile)。旧的~/.dsh/dsh-links/会在升级后自动迁移,且源目录原样保留为备份 / 回滚点,无需手动处理。任何冒烟或联调都必须通过stateDir配置隔离,且不得调用吊销类操作——否则会吊销你真实手机的配对。
cd apps/android
./gradlew :app:assembleDebug :app:testDebugUnitTest :app:lintDebug
./gradlew :app:validateDebugScreenshotTest # 截图基线校验
./gradlew :app:updateDebugScreenshotTest # 改 UI 后更新基线,逐张人工审图后随 PR 提交
debug 变体的包名带 .debug 后缀,与签名 release 共存、互不覆盖;真机设备测试一律走 debug 变体(完整命令见 apps/android/README.md)。
cd apps/ios
# 先生成构建元数据(project.yml 用 configFiles 引用,缺文件会让 xcodegen 报错)
node ../../scripts/build-metadata.mjs --platform ios
xcodegen generate # project.yml → Cetus.xcodeproj(.xcodeproj 不入库)
xcodebuild -scheme Cetus -destination 'platform=iOS Simulator,name=iPhone 17 Pro' build
xcodebuild -scheme Cetus -destination 'platform=iOS Simulator,name=iPhone 17 Pro' test
截图基线只允许由 .github/workflows/ios-regen-screenshots.yml 在 CI 上重录,禁止提交本地基线;改 UI 后先触发该 workflow,再把新基线随 PR 提交。约束与目录契约见 apps/ios/AGENTS.md,页面对照见 apps/ios/docs/page-mapping.md。
cd relay
gofmt -l . && go vet ./... && go build ./... && go test ./... -race
自建部署见 relay/README.md。
cd push
gofmt -l . && go vet ./... && go build ./... && go test ./... -race # 门禁,CI 见 ci-push.yml
网关配置走环境变量:DLPUSH_LISTEN(默认 :8080)、DLPUSH_HPKE_KEYS、APNS_KEY_P8_PATH(0600,不进 git)、APNS_KEY_ID、APNS_TEAM_ID、APNS_BUNDLE_ID、DLPUSH_RATE_MINUTE(默认 10)、DLPUSH_RATE_HOUR(默认 120)、DLPUSH_VERSION。协议与红线见 docs/rfc/0002-push-gateway.md。
CI 分四路:插件跑面板生成物一致性、node:test、打包清单与依赖审计;中继跑 race 测试、vet 与控制帧 fuzz;推送网关跑 gofmt / go vet / race 测试与模糊测试;Android App 跑 JVM 单测(含 DLP/1 三端共用向量)+ lint、截图校验与 debug / release 构建,模拟器 job 真正执行设备测试(冷启动冒烟 + 公式 / Mermaid 渲染链路 + TokenCrypto 并发首生),release 的 R8 mapping 上传为制品用于崩溃反混淆。iOS 由 ci-ios.yml 在 macOS runner 上跑本地化目录检查、构建、单测与截图校验,另有真机端到端(ios-e2e.yml)与性能(ios-performance.yml)工作流。Android App 单测里包含一组架构门禁:
| 门禁 | 守住什么 |
|---|---|
DesignTokenUsageTest / ComponentLanguageTest | 颜色、圆角、字号只能来自 token,组件语法统一 |
DshPaletteProvenanceTest | 主题色取自 DSH 调色板镜像,偏离必须写明原因 |
DshSpacingUsageTest | 间距走 DshSpace 刻度,刻度外存量只降不升 |
CodeHygieneTest | 文件与函数体量预算,只降不升 |
| 截图测试 | 设计系统、对话流、审批 / 提问卡、改动面板的亮 / 暗、中 / 英、大字号基线 |
插件不发布到 npm registry:直接以本仓 git 源安装/更新。Android App 只发本机签名的 APK,附在 app-v* Release 上;iOS App 目前以源码分发,官方构建待发布。完整核对清单见 RELEASING.md。
FLAG_SECURE。iOS 侧同类凭据(设备 token、证书指纹、端到端推送密钥 K)只存 Keychain,kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly 且 kSecAttrSynchronizable = false(不进 iCloud 钥匙串)。完整说明见 PRIVACY.md 与 SECURITY.md。
CN=DSH Links, OU=lunaship, O=lunaship, C=CN
SHA-256: 38f71adf8b67d81042c99a3ec0dfdafb4303dd31e3fc491068ccd534cb482a47
签名证书仍使用旧名称;校验已发布 APK 时请以 SHA-256 指纹为准。
安装前可用 apksigner verify --print-certs <apk> 核对。
Cetus 以 MIT 许可发布。
「Cetus」名称、logo 与应用图标不在 MIT 授权范围内;第三方 fork 请更换名称、图标与 applicationId 后再分发。随包的第三方库与资源保留各自许可,见 THIRD_PARTY_NOTICES.md 与 apps/android/THIRD_PARTY_NOTICES.md。
project.yml 生成,.xcodeproj 不入库。