Back to home@keke-shy

dsh-desktop

Minimal Electron desktop shell embedding the official DeepSeek Harness web profile

Stars
0
Language
TypeScript
Created
Aug 16, 2026
Updated
Aug 22, 2026

Introduction

dsh-desktop

基于官方 DeepSeek Harness 构建的最小 Electron 桌面壳:在 Electron 主进程内启动官方 web profile,把浏览器界面装进一个沙箱化的原生窗口,并提供托盘、单实例、有序退出、驻留开关与安装包构建。

它不是 Harness 的替代品,也不 fork 上游源码。智能体、模型、工具、会话和 Web UI 全部来自官方 @deepseek-ai/dsh-* 包;本仓库只负责「窗口 + 托盘 + 进程生命周期 + 一个极窄的启动适配面」。

设计原则

  1. 极窄兼容面:整个仓库只有 src/boot.ts 一个文件 import 官方包。上游破坏性变更首先、也只在该文件里体现。
  2. 精确锁版本:上游各包独立发布且 latest dist-tag 陈旧,因此所有 @deepseek-ai/* 依赖都精确 pin 到 0.1.0-rc.6,不写 ^。升级 = 显式改版本 + 重跑 check
  3. 轻量:不内置插件市场/自动更新器;v1 只有窗口、托盘、单实例、loopback-only、安全导航锁与打包。
  4. 安全优先:渲染进程 sandbox + contextIsolation、无 Node 集成、无 preload/IPC 桥、导航锁同源、外链白名单协议、webserver 强制 127.0.0.1:0

架构

flowchart LR
    subgraph EL["Electron 主进程"]
        M["main.ts<br/>单实例 · fail-loud · 有序退出"]
        B["boot.ts(唯一兼容面)<br/>boot() + provideCmdline() + 注入 agent-presets root"]
        D["desktop.ts<br/>沙箱窗口 + 托盘 + 导航锁 + 驻留开关"]
    end
    subgraph HOST["官方 DSH 插件树(web profile)"]
        W["dsh-base + dsh-web-app<br/>webserver / agent / tool / session / 前端 dist"]
        P["agent-presets<br/>standard / code / cordis / minimal(来自 dsh 包)"]
    end
    R["沙箱 renderer<br/>官方 Web UI"]

    M --> B --> HOST --> W
    B --> P
    M --> D --> R
    W <-->|"loopback HTTP + WebSocket (127.0.0.1:0)"| R

详见 docs/architecture.mddocs/compatibility.md

快速开始

npm install          # 安装依赖(会下载 Electron 二进制)
npm run dev          # 编译并启动 Electron

首次运行会在 ~/.dsh/profiles/web/ 初始化官方 web profile(与 dsh --profile web 一致)。 实际对话需要 DEEPSEEK_API_KEY(可放在 ~/.dsh/.env,与官方一致)。 模型选择、命令菜单、Agent 预设都来自 @deepseek-ai/dsh 包自带的 config/agent-presets,已随依赖自动安装。

驻留开关

关闭窗口时的行为由环境变量控制,默认关闭即退出(最不容易误解):

DSH_DESKTOP_MINIMIZE_TO_TRAY=1 npm run dev   # 关闭窗口 → 隐藏到托盘,托盘「Quit」才退出
行为
未设置 / 0 / false关闭窗口 = 退出应用
1 / true / yes / on关闭窗口 = 隐藏到托盘(驻留)

打包

打包依赖 electron-builder(已列入 devDependencies)。打包前需要完整的 npm install(不要 --ignore-scripts,Electron 二进制与原生模块需要脚本完成)。

npm run package:dir       # 目录版(调试用,输出 dist/)
npm run dist:win          # Windows NSIS 安装包(x64,可自选安装目录)
npm run dist:win:local    # 推荐:自动处理「用户名带撇号」等本机坑的封装(见下)
npm run dist:mac          # macOS DMG
  • 图标:Windows 安装包/EXE 使用 build/app-icon.png(官方蓝鲸图标,256×256)。它由 build/app-icon.iconpm run gen:icon 放大生成——原始 .ico 最大只有 225×225,而 electron-builder 要求 ≥256×256。换源图标后重跑 npm run gen:icon 即可。
  • dist:win:local 封装脚本scripts/dist-win.mjs):①自动检测用户名里是否有撇号/引号,若有就把本次构建的 home 重定向到项目内的 .dsh-build-home/(已 gitignore,绕过 MSB4100,不污染项目外路径);②默认走 https://npmmirror.com/mirrors/electron/ 镜像下载 Electron zip(国内到 GitHub 常超时 ETIMEDOUT),如需自定义镜像设 ELECTRON_MIRROR 即可。
  • 打包产物在 dist/。macOS 目标当前未配 .icns 图标,会回退到默认图标;如需要可补一个 512×512 的 build/app-icon.png 并设置 mac.icon

体积为什么大(正常现象)

安装包约 120–150 MB(解包后 500+ MB),主要构成:

  • Electron 运行时本身(~200 MB)+ node-pty/koffi 等原生模块。
  • 完整的 DeepSeek Harness(~195 个 @deepseek-ai/* 包):agent 循环、LLM 适配器、工具、会话持久化、沙箱、subprocess、终端,以及官方 Web 前端dsh-web-frontend 的构建产物 + 全部 ui-* 客户端插件)。
  • 附带各包的 .map/.d.ts 文件(未做体积裁剪)。

这与社区桌面版(安装包 141 MB)是同一量级——本质是「把整个 Harness + 浏览器 UI + Electron 一起装进安装包」。若后续要瘦身,可优先排除 .map/.d.ts、裁剪用不到的 CLI 依赖。

依赖闭包:为什么把 195 个包显式列出来

Harness 大量用 peerDependenciescordiscordis-plugin-*dsh-invariants 等都是 peer)。npm 会装这些 peer,但 electron-builder 只打包 dependencies 闭包、丢弃 peer-only 的包,导致安装后启动报 ERR_MODULE_NOT_FOUND: Cannot find package '@deepseek-ai/cordis-plugin-group'

解决:把 node_modules 里全部 @deepseek-ai/* 包显式列入 dependenciesscripts/gen-deps.mjs 自动生成)。升级 Harness 版本后重跑 npm run gen:deps 即可同步。

客户端插件为什么必须 asarUnpack

浏览器端的插件(ui-*client-runtime 等)不是直接 require,而是宿主通过 ~/.dsh/profiles/node_modules 里的符号链接healProfilesModuleFallback 创建)解析、再走 /plugins/<id>/client.js 下发。若 node_modules 被封进 app.asar,符号链接就会指向 app.asar/node_modules/... 这种虚拟路径(Windows junction 指向它是死链接),客户端插件被静默跳过,界面报 dsh-client-app-shell: pending (slots, sessions, layout)

解决:build.asarUnpackpackage.json + node_modules/** 解包成真实文件,src/paths.tsunpackedAsarPath()app.asar/... 映射到 app.asar.unpacked/...,让符号链接指向真实目录。这不会额外增肥(asar 本就不压缩,解包前后体积一样)。

Windows 打包前置:Visual Studio Build Tools(必须)

Harness 含原生 C++ 模块 node-pty(Shell/PTY 执行的后端,依赖链 dsh-base → dsh-subprocess-local → node-pty)。它自带 Node 平台的预编译二进制,但没有 Electron 43 对应 ABI 的预编译产物,所以 electron-builder 的 @electron/rebuild 会回退到 node-gyp 源码编译。若本机没有 MSVC,就会报:

⨯ Error: Could not find any Visual Studio installation to use
⨯ node-gyp failed to rebuild '...\node_modules\node-pty'

解决:安装 Visual Studio 2022 Build Tools,勾选 「使用 C++ 的桌面开发」 工作负载(含 MSVC v143、Windows SDK、CMake),然后重跑打包:

  1. 下载:https://visualstudio.microsoft.com/zh-hans/downloads/#build-tools-for-visual-studio-2022
  2. 安装时勾选「使用 C++ 的桌面开发」。
  3. 重开终端,再执行 npm run dist:win

安装 VS 后,electron-builder 会把 node-pty(以及 koffi 等其它原生模块)针对 Electron ABI 重新编译,打包即可完成。

为什么必须 MSVCnode-gyp 在 Windows 上只认 MSVC(cl.exe)。Dev-C++ 的 MinGW(gcc)、VS Code(纯编辑器)都无法替代。node-pty 只为 Node 提供预编译二进制、不为 Electron 提供,所以任何 Electron 版本都需现场编译,绕不开 MSVC。

C 盘没空间:用精简的 vs_BuildTools.exe(不是完整 VS),在「安装位置」页把 Build Tools 与下载缓存改到 D 盘,主体(MSVC + Windows SDK,几个 GB)就落在 D 盘;C 盘只留少量不可移动的共享组件。勾选工作负载后还可在「安装详细信息」里去掉用不到的组件以缩小体积。

Windows 用户名含撇号(如 sh'y)会触发另一个错@electron/rebuild 把 Electron 头文件缓存放到了 C:\Users\sh'y\.electron-gyp\,这个带撇号的路径会被嵌入 MSBuild 表达式,报 MSB4100 ... 应为布尔值而不是 ...。直接用 npm run dist:win:local 即可自动把 home 重定向到项目内的 .dsh-build-home/,无需手动设环境变量。

MSB8040: 此项目需要缓解了 Spectre 漏洞的库:node-pty 的 winpty 构建开启了 Spectre 缓解,需要额外安装「Spectre 缓解库」组件(默认 C++ 工作负载不含它)。VS Installer →「修改」→「单个组件」→ 搜 Spectre → 勾选 MSVC ... x64/x86 Spectre-mitigated libs(winpty 用到 ATL,如有 C++ ATL ... Spectre Mitigations 也一并勾选)→「修改」。该组件同样落在 Build Tools 的安装盘,不占 C 盘。

另:npm 11.17 的 allow-scripts 会默认拦截安装脚本(npm warn allow-scripts ... node-pty ...)。这不影响开发运行(node-pty 自带 Node 预编译二进制),也不影响上面的打包流程(electron-builder 会自行 rebuild),无需额外批准。

校验

npm run check        # build + typecheck + 单元测试
npm run typecheck
npm test             # 纯逻辑单元测试(不依赖 Electron 运行时)

目录结构

build/
  app-icon.ico    官方蓝鲸图标(窗口 / 托盘 / EXE 共用)
src/
  main.ts         Electron 入口:进程生命周期编排
  boot.ts         兼容面:唯一 import 官方包的地方(注入 agent-presets root)
  desktop.ts      窗口/托盘/导航锁/驻留开关的 Electron 适配
  window.ts       BrowserWindow 安全配置(纯函数,可测)
  tray.ts         托盘(加载官方图标并缩放)
  shutdown.ts     幂等、有界的有序退出
  loopback.ts     loopback URL + webServer.port 结构读取(纯函数)
  policy.ts       导航/外链安全策略(纯函数)
  patches.ts      profile patch 层组合 + agent-presets 注入(纯函数)
  config.ts       启动配置解析(驻留开关,纯函数)
  paths.ts        asar→unpacked 路径映射(纯函数,可测)
tests/            上述纯逻辑的单元测试
docs/             架构与兼容性契约

扩展点

  • 改窗口/托盘行为src/desktop.tssrc/window.tssrc/tray.ts,纯 Electron,不碰兼容面。
  • 换图标:替换 build/app-icon.ico 即可(窗口、托盘、EXE 三处共用)。
  • 给 Harness 加插件:编辑 ~/.dsh/profiles/web/cordis.patch.yml(官方 patch 层,本壳不拦截)。
  • 升级 Harness:改 package.json@deepseek-ai/* 的精确版本,跑 npm run check。变更若落在 src/boot.ts 使用的 API 上,见 docs/compatibility.md

与社区桌面版的关系

本仓库参考了 anywhere-labs/deepseek-harness-desktop 的「薄 Electron 宿主」思路,但刻意缩小范围:去掉插件市场、pnpm 管理、自动更新、profile 切换器等,只保留桌面体验的最小闭环,从而把安全面与维护面都压到最低。

License

MIT