DSH Desktop 全家桶:一套架构,四个平台
这篇文章是整个 DSH Desktop 系列的总览:全家桶里到底有谁、为什么能「一套架构跑四个平台」、四版能力差在哪、整个 workspace 怎么组织、以及你想动手该怎么开始。
一、全家桶里都有谁
先交代背景。DeepSeek Harness(dsh)是 DeepSeek AI 开源的 agent harness(智能体运行框架),采用「一切皆插件」的架构——模型适配器、工具注册表、会话日志、甚至 agent 主循环本身,全是可替换的插件。它自带一套相当完整的 Web UI(原生入口是 dsh web),功能没问题,但始终活在浏览器标签页里。
DSH Desktop 系列要做的,就是把这个 Web UI 变成「一等公民」的原生应用形态——有托盘、有系统通知、有独立的窗口管理,像一个真正的应用那样运行。
目前整个系列共有四个 edition,共用同一套外壳架构、同一条数据面:
| Edition | 渲染 | 运行时 | 平台 |
|---|---|---|---|
dsh-desktop | Electron 内置 Chromium | Electron 官方运行时 | Windows / Linux / macOS |
dsh-desktop-hos | Electron 37(内置 Chromium) | Electron-on-HarmonyOS 运行时 | 鸿蒙 2in1 / 平板(HAP) |
dsh-desktop-ark | 系统 ArkWeb | 进程内 Node(libnode.so) | 鸿蒙 2in1 / 平板(HAP) |
dsh-desktop-android | 系统 WebView | 进程内 Node(libnode.so) | Android 手机 / 平板(APK,arm64-v8a) |
四个 edition 的差别,从头到尾只有一句话:由谁提供窗口,由谁提供 Node。 界面、数据面、扩展方式完全相同——都是把 dsh 的 Host 在进程内跑起来,然后让自家窗口去加载那份未经修改的标准 dsh Web UI。
为什么这么执着于「零改动」?因为 dsh 还在 developer preview,上游动得很勤。一个外壳钉一个上游 tag,升级就是重跑产物管线,而不是重做补丁。 一旦把界面重写一遍,就等于把上游最活跃的部分永久 fork 进自己的仓库——四个版本一共只用一个 workspace,谁也不想背上四个永久 fork。
二、共享的骨架:进程内 Host + webserver + 同源数据面
全家桶能成立,靠的是 dsh 一个很值钱的架构事实:dsh 已完成 Host/Client 分层,而且它的 webserver 同时服务 SPA 前端页面和 /api 接口。
于是四个 edition 采用完全相同的方案——进程内 Host + webserver + 同源数据面:
┌─ 应用壳进程(也承载 dsh Host)────────────────────────────┐
│ runProfile('desktop') → { ctx, shutdown } │
│ ├─ webserver ← 绑定本机回环端口,服务 dist + /api │
│ ├─ apiProxy ← RPC 网关 │
│ └─ connection ← 已把 /api + WebSocket 注册到 webserver│
│ 就绪后 loadURL(http://127.0.0.1:<随机端口>/) │
│ ┌─ 桌面能力:托盘 / 通知 / 窗口状态(订阅 ctx 事件) │
└──────────────▲───────────────────────────────────────────┘
│ (同源;渲染层走 HTTP/WS,无自定义协议) │
┌──────────────┴───────────────────────────────────────────┐
│ 视图层:loadURL(同源 URL) │
│ 标准 dsh Web UI(WebApiClient:fetch /api + WS 事件流) │
└──────────────────────────────────────────────────────────┘
因为渲染进程加载的就是 webserver 自己服务的页面,它和 /api 天然同源——fetch('/api/xxx') 和 WebSocket('/api/events.mux') 统统不需要 CORS、不需要鉴权、不需要自定义协议,也不需要新增任何 IPC 载体(Electron 版本甚至不需要窗口控制 IPC,渲染层全走 HTTP/WS 同源)。
不同平台只改一处绑定方式:
- 桌面端:
127.0.0.1:<随机端口>,Electron 主进程里loadURL,换来零 CORS、零鉴权、零 Host 头改写。 - HarmonyOS Edition(ark):
127.0.0.1:<随机端口>同源回环,ArkWeb 直接loadUrl()。 - Android Edition:
127.0.0.1:<随机端口>+ 一次性?token=换签名 cookie,之后页面走/api+ WebSocket。 - Electron on HarmonyOS(hos):因为鸿蒙渲染进程访问不了
127.0.0.1,改成0.0.0.0:<随机端口>+ 局域网 IP 建连,同时在内嵌渲染进程出栈前把Host/Origin改写回 loopback,让 dsh 的 loopback-only 特权方法围栏照旧通过。
这一条,是整个设计「上游代码保持原样」能成立的最根本原因。
三、四个成员,各自的性格
同一个骨架,四个平台各自长出不同的模样——每家都用自己平台最顺手的运行时,代价也各不相同。
🖥 dsh-desktop:桌面三端的「原装正主」
最容易理解的一个:Electron + Electron Forge,Windows / Linux / macOS 三端通用(Windows 出 Squirrel 安装器、macOS 出 DMG、Linux 出 deb/rpm,外加三平台免安装 ZIP)。
桌面能力最全:系统托盘、原生通知、常规标题栏、剪贴板图片粘贴、窗口状态持久化、F11 全屏。dsh 补丁只有 3 个(禁用 HMR、禁用原生目录选择器、关闭首启欢迎提示),用于绕开 Electron V8 缺失的少数内部符号。
🪟 dsh-desktop-hos:Electron on HarmonyOS Edition
鸿蒙上没有官方 Electron,标准答案是「用 ArkUI 把界面重写一遍」——代价是背上一个永久 fork。本版走的是另一条路:把 Electron 37 整个塞进 HAP 里,跑在鸿蒙窗口里的就是官方 dsh Web UI,逐字节复用、界面零重写。
代价也最重:要 JIT 就得申请 ALLOW_WRITABLE_CODE_MEMORY 这个 ACL 受限权限(只对平板 / 2in1 开放,也卡着上架这条路);上游补丁多达 13 个(禁 symlink / 禁 hardlink / loopback 隔离 / os.homedir() 指向沙箱……)。HAP 是 Electron 体量(数百 MB)。
🧩 dsh-desktop-ark:HarmonyOS Edition
完全不含 Electron 的版本:系统 ArkWeb 渲染 + 进程内真实 Node。不打包任何浏览器内核,也不把界面用 ArkUI 重写——同一个 dsh Host、同一套外壳、同一条数据面。
最亮眼的是零受限权限装机:默认跑无 JIT 的 compat 形态(--jitless),声明面收敛为零 ACL;WASM 不可用时自动补一层纯 JS 的 fetch 兼容层,UI 正常对话不塌。上游补丁 0 条(profile + bundle + 已审计垫片),包体 HAP 约 88 MB,升上游 tag 只需重跑产物管线。
📱 dsh-desktop-android:Android Edition
同一套架构搬到 Android:系统 WebView 渲染 + 进程内真实 Node(libnode.so + node::Start)。鸿蒙上最痛的几件事在 Android 直接「还给你」——JIT 直接可用无需受限权限、符号链接语义正常、子进程可 exec、前台服务可保活;但 Android 又塞回来五件新账:assets 不是路径、主线程不能碰 node::Start、没有 rg、没有 git、content:// 不是路径。
逐个击破后:node::Start 变成显式状态机(崩溃即终态,重启应用是唯一出路)、缺失的二进制能换纯 JS 就换纯 JS(进程内 rg 替身、isomorphic-git 的 21 个工具、worker 线程里跑 pnpm),终端面板这种绕不开的则随包投放原生 libpty_node.so、用 S6 垫片解禁打通;解包责任也前移到 Kotlin 的 PayloadInstaller(防 zip-slip、sha 幂等)。上游补丁同样 0 条,APK 约 135 MB。
📟 Android 的 PTY:不止「能用」,而是真终端
Android Edition 的终端能力是全功能 PTY——基于 node-pty 实现(配合随包的原生 libpty_node.so 与垫片解禁),不是「哨兵行模拟」那种弱化版终端。终端面板里能调用的命令也相当饱满:
- 预置 CLI 五件套:
node/python/git/uv/pnpm,外加npm/npx/corepack/pip——随包自带,设备上无需安装任何东西。 - 系统内置命令:Android 固件
/system/bin常驻的完整命令集——toybox全文本/文件工具集、awk/sed/tr、tar/gzip、sha256sum、curl、ping,以及pm/getprop/logcat等框架命令。
也就是说,Agent 在一个 Android 终端面板里,既能用系统原生的文本处理与网络工具,也能直接跑 Node / Python 生态——桌面端那份「全功能系统环境」的体验,在手机上换了一种方式补齐。
如果把四个 edition 拉到一起看成本结构:桌面版用官方 Electron 换最省事的全功能;hos 用「13 个补丁 + 大包体」换鸿蒙上的保真度;ark 用「免权限 + 小包体」换灵活度;android 用「大引擎 + 一次性授权」换最少的平台折衷。它们不是替代关系,是四种明码标价的取舍。
四、一个矩阵,看懂四版能力差距
一家人也得算清楚账。整个 workspace 维护了一份逐行回源代码核实的 42 行能力矩阵(对每个 edition 的 profile、bundle、seam 插件、能力桥、manifest 都核对过,还带「不一致项台账」)。下面这份是它的简化视图:
图例:✅ 已核实可用|🟢 源码已交付(真机/端到端实证待补)|⚠️ 受限/部分可用|❌ 无或已决策不做|⏸ 暂缓
| 能力 | Desktop | Electron on HarmonyOS | HarmonyOS Edition | Android Edition |
|---|---|---|---|---|
| 读 / 列目录 / 写文件 | ✅ | ✅ | ✅ | ✅ |
| 删除 / 移动 / 复制 / chmod | ✅ | ✅ | ❌ | 🟢 |
| Shell 命令执行 | ✅ | ✅ | ⚠️ | 🟢 |
| PTY / 终端面板 | ✅ | ❌ | ❌ | ✅ |
| 内容搜索与 glob(ripgrep) | ✅ | ✅ | ❌ | ✅ |
| web_search / web_fetch | ✅ | ✅ | ⚠️ | ✅ |
| 文件导出 / 外发 | ✅ | ⚠️ | ⚠️ | 🟢 |
| 后台任务 | ✅ | ⚠️ | ⚠️ | ✅ |
| 子 agent | ✅ | ✅ | ⚠️ | ✅ |
| todo / goal / present / 向用户提问 | ✅ | ✅ | ✅ | ✅ |
| 技能(skill) | ✅ | ✅ | ⚠️ | ⚠️ |
| workflow / ralph | ✅ | ❌ | ❌ | ❌ |
| read_image | ✅ | ✅ | ✅ | ✅ |
| 插件市场 | ✅ | ✅ | ✅ | 🟢 |
| Git | ✅ | ✅ | ✅ | 🟢 |
| 系统通知 | ✅ | ❌ | ⚠️ | 🟢 |
| 剪贴板读图 / 写文本 | ✅ | ⚠️ | ⚠️ | 🟢 |
| 工作区目录选择器 | ✅ | ⚠️ | ✅ | ✅ |
| 提权审批 | ✅ | ✅ | ⚠️ | ⚠️ |
| 后台常驻 | ✅ | ⚠️ | ⚠️ | 🟢 |
| 托盘 / 状态栏图标 | ✅ | ✅ | ❌ | ❌ |
| 单实例 | ✅ | ❌ | ⚠️ | ✅ |
| 窗口状态记忆 / 全屏 | ✅ | ✅ | ❌ | ❌ |
| 进程级沙箱执行 | 🟢 | ❌ | ❌ | ❌ |
| 开机自启 | ⏸ | ❌ | ❌ | ❌ |
几个值得展开的要点:
1. 「基础三件套」全绿。 读文件、列目录、写文件、todo/goal/present/提问、read_image、插件市场、Git——这四个 edition 的脑干部分全部可用,这是「同一套 Host 复用到四端」最直接的证明。
2. PTY 与进程沙箱是能力的试金石。 终端面板如今桌面端与 Android 都能上——Android 靠节点级 PTY 集成(随包 libpty_node.so + S6 垫片解析原生库、解禁 terminal-controller 与 ui-sidebar-terminal)实现;鸿蒙两版没有 node-pty 的 aarch64 产物、也缺 /dev/ptmx,所以画不上。进程级沙箱(landlock 类)四个里只有桌面端是🟢,三个轻量端统一如实申报 sandbox: 'none',靠 fs 层的围栏兜底。它们的共同态度是:做不到就写清根因,绝不假装成功。
3. 补丁数量本身就是一张成绩单:3(desktop)→ 13(hos)→ 0(ark)→ 0(android)。 越往后越「零补丁」,靠的是把平台差异从「改上游」搬进「profile + bundle + 一层带标记、可审计的垫片」——每一条垫片都有唯一标记、启动期自检断言、登记理由与撤销条件。「零补丁」不是口号,是一份能被审计的清单。
4. JIT / ACL 一条线串起四版。 桌面端 JIT 随便用;hos 要 JIT 就得申请 ACL 受限权限(上架还被卡);ark 选择 --jitless 收敛到零 ACL(代价是 WASM 缺失,得补纯 JS fetch 兼容层);android 自分发没有 ACL 概念,JIT 直接可用。
5. 图标 / 托盘 / 窗口状态这类「桌面味道」能力,移动端明确不做。 Android 没有托盘,就用系统通知 + 前台服务替代;而这些决策也用矩阵里那一格 ❌ 明明白白写出来。
完整 42 行矩阵、逐条源码锚点和不一致项台账,都在 workspace 的
docs/能力对照清单.md里,欢迎直接去核对。
五、workspace:全家桶的集装箱
四个 edition 不是四套孤立的仓库,而是被一个聚合工程钉在一起的:deepseek-harness-workspace。
它把所有工程以 git submodule 形式固定版本,目录结构恰好还原各封装工程构建脚本期望的兄弟目录布局。clone 一次,四个 edition 的依赖、构建、开发全部就地解决:
deepseek-harness-workspace/ # 本仓库 —— submodule 容器
├── dsh-desktop/ # [submodule] Electron 桌面封装(Windows/Linux/macOS)
├── dsh-desktop-hos/ # [submodule] Electron on HarmonyOS Edition(HAP)
├── dsh-desktop-ark/ # [submodule] HarmonyOS Edition —— ArkWeb + 进程内 Node(HAP)
├── dsh-desktop-android/ # [submodule] Android Edition —— 系统 WebView + 进程内 Node(APK)
├── deepseek-harness/ # [submodule] dsh —— 被封装的 Agent 主机(上游)
├── dsh-market/ # [submodule] 可视化插件市场(npm 包 "dshmarket")
├── dsh-plugins/ # 通用、可共享的 dsh 插件 —— 命名 dsh-plugin-XXX
├── skills/ # 通用、可共享的 dsh 工具技能 —— 功能性 kebab-case 名
├── harmonypc-electron/ # [submodule] Electron-on-HarmonyOS 运行时(Electron 37 / Node 22.17)
├── dsh-desktop-website/ # [submodule] 四个 edition 的产品官网
└── harmonypc-electron-versions/ # 运行时发行版归档 + Electron 头文件指南
几个值得注意的设计约定:
- 插件两层分工,问一句「把它装到另一个 dsh 壳上还能工作吗?」:能 → 放
dsh-plugins/走通用层(dsh-plugin-XXX);不能 → 放各封装工程自己的plugins/(宿配套补丁 / profile / 运行期适配)。 - 技能同款两层,但技能名不加前缀、一律功能性 kebab-case——因为
name是模型可见标识,归属靠目录表达,不靠名字。 - 运行时构件发布成包:
@fellow99/node-bridge把真实 Node(NAPI bootstrap + dlopen + node::Start)嵌进应用进程,@fellow99/node-runtime承载libnode.so引擎(版本号 = Node 版本,SHA-256 锁定)。四个封装工程消费完全相同的上游构件。 - 当前版本:四个 edition 均为 v0.2.2,统一钉在 dsh
dsh-v0.2.2-rc.1;任一工程升级时同步更新版本表。
六、怎么开始
全家桶开箱,一个命令:
git clone --recursive https://github.com/fellow99/deepseek-harness-workspace.git
cd deepseek-harness-workspace
git submodule update --init --recursive # 拉取/刷新全部固定版本的 submodule
各 edition 的构建说明由各自 README 维护,大致走向:
- 桌面端:
npm run build:dsh(应用补丁并构建 dsh + 插件市场)→npm start/npm run package。 - Electron on HarmonyOS:三阶段构建(collect-runtime → build-dsh → collect-dsh),再经 DevEco / hvigor 构建并签名 HAP。
- HarmonyOS Edition:ohpm 拉取
@fellow99/node-bridge+@fellow99/node-runtime→ 装配载荷 →hvigorw assembleHap。 - Android Edition:
assemble-payload.mjs物化 dsh 运行树 →package-payload.mjs打载荷 →provision-engine.mjs投放引擎 →./gradlew assembleFullDebug/assembleFullRelease→adb install。
写在最后
DSH Desktop 全家桶的核心,浓缩成一句话:抓住「dsh 的 webserver 本来就同源服务页面和 API」这个事实,然后用「进程内 Host + webserver + 同源数据面」这一套骨架,把同一份官方 Web UI 装进桌面、两代鸿蒙和 Android 四个原生窗口。
它换来什么?四个平台、零重写前端、零上游源码补丁(轻量三端)、统一的可审计适配层。它付了什么?不同平台的补丁数与包体、鸿蒙两版拿不下的 PTY 与进程沙箱、以及每一格都「如实写出根因」的诚实边界。
如果你也想把一个 agent harness 吃干榨净到每一个设备上,这套家族可以给你一份完整的参考答案。
代码和文档都在这里:
- 工程总览(workspace):https://github.com/fellow99/deepseek-harness-workspace
- 桌面工程(Windows / Linux / macOS):https://github.com/fellow99/dsh-desktop
- Electron on HarmonyOS 版:https://github.com/fellow99/dsh-desktop-hos
- 鸿蒙 Edition(ArkWeb):https://github.com/fellow99/dsh-desktop-ark
- Android Edition:https://github.com/fellow99/dsh-desktop-android
- 上游 DeepSeek Harness:https://github.com/deepseek-ai/deepseek-harness
感谢各位关注,欢迎访问我的GitHub主页:https://fellow99.github.io/
更多推荐




所有评论(0)