DeepSeek Harness Hub
← 返回列表

huyang218/dsh-desktop

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
需源码安装

DeepSeek Harnessdsh的桌面应用:负责安装与更新运行时、持有服务进程及其存储,并把 Web UI…

暂不能直接安装(需源码编译或环境不满足):仓库 package.json 标记 private,未发布到 npm,需从源码安装。 · 最近上游提交 2026/8/26 · 已提供中文文档

DeepSeek Harness (dsh) 的非官方 macOS/Windows 桌面应用:管理运行时、监管服务器,并将 Web UI 放入真正的窗口中。

综合分
35.8
GitHub 分
35.8
用户评分
★ Stars
2
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add huyang218/dsh-desktop
仓库 package.json 标记 private,未发布到 npm,需从源码安装,改用 GitHub 源安装
数据截至 2026/9/19(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

npm 包dsh-desktop @ 0.2.0
Node 引擎要求 >=22 · 基线 Node 22.19 满足
dsh CLI 依赖未声明 dsh 版本约束
入口文件main/exports/bin 已声明

仓库 package.json 标记 private,未发布到 npm,需从源码安装

验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/19 03:09:47

用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

dsh Desktop

Release
License: MIT
Platform

DeepSeek Harness(dsh)的桌面应用:负责安装与更新运行时、持有服务进程及其存储,并把 Web UI 收进窗口。

非官方项目,与 DeepSeek 无隶属关系,也未获其背书。dsh 由其作者以 npm 包
形式发布,本项目只是它的外壳;两者独立迭代,应用不会把 dsh 的副本并入自己的
源码树。

仓库名为 dsh-desktop,打包出的应用名为 DeepSeek Harness(见商标)。

兄弟项目:dsh-android 把同一套运行时装进手机;dsh-plugins 是一批可以直接用这里的插件管理器装进来的插件。见相关项目。

下载

安装包挂在每个 release 下。目标机器不需要预装任何东西——安装包自带 Node 运行时,dsh 在首次启动时装。

| 平台 | 文件 |
|---|---|
| macOS(Apple Silicon) | DeepSeek Harness--arm64.dmg |
| macOS(Intel) | DeepSeek Harness--x64.dmg |
| Windows 10(1803+)/ 11 | DeepSeek Harness Setup .exe |

macOS 构建为 ad-hoc 签名、未公证,首次启动需在「系统设置 → 隐私与安全性」里放行。对话需要 DeepSeek API Key,首次启动时在 Web UI 里填。

长什么样

插件市场 — DSH Market 的目录收进窗口,可搜索,本地缓存可离线浏览,已验证的条目一键安装。

插件管理 — 用 npm 包名、GitHub 链接、本地路径或 zip 安装;已装的可更新、停用、配置、卸载。

一处代理,两条网络 — 窗口自身的请求走 Chromium,npm、pnpm 和 dsh 服务走环境变量。设一次,两条都配上,分开测。

性能浮标 — 此刻这套东西正在花多少资源,整个进程组一起算。CPU 是真实速率,不是 ps 报的那个生命周期平均值。

为什么需要它

npx dsh web 本身就能跑。它留给你的是周边的一切:运行时装在哪、怎么升级、端口被占了用哪个、退出应用后子进程还在不在、DSH_HOME 指向何处、服务挂了谁负责拉起。这些由本应用接管。

它做什么

| | |
|---|---|
| 双槽位更新 | 运行时由 npm 装进 runtime/slot-a 或 slot-b,current.json 指向活跃槽。更新先装进闲置槽,起一个探针服务做启动自检,通过后才切换指针——升级失败不会动到正在用的版本。旧版本仍留在另一个槽位里,菜单里一步即可回退,不必联网、不必重装。 |
| 更新通道 | dsh 的新版本先发到 npm 的 next 标签,latest 要过些时候才跟上——于是一个明明已经发布的版本,对只盯着 latest 的人来说是不存在的。稳定版跟随 latest,预览版跟随 next;检查更新本就只发一次请求,两个标签一并读回,所以在稳定版上「已是最新」时也能顺带说出预览版有更新的版本,而不是把这件事留成一个谜。若通道指向的版本比已装的更旧,会如实说明这是往回切,启动自检与另一个槽位的回退对它同样有效。 |
| 应用自更新 | 与 GitHub Release 上的版本号对照,分两种更新。热更新:新版本若只改了外壳代码(JS 与页面),只下几百 KB 的包放进数据目录,重启即生效——/Applications 里的应用包不动,签名不变,系统隐私授权也不会因此失效。整包更新:改到 Electron 或内置运行时的版本走安装包,应用负责下载并打开它。启动后静默检查一次,菜单里也可随时手动检查。 |
| 进程归属 | 服务随窗口启动,占用随机空闲端口,应答 HTTP 200 后才加载页面。它运行在独立的进程组(POSIX)或进程树(Windows)中,应用退出时整树终止,不留孤儿。 |
| 进程守护 | 非计划退出——包括 OOM abort 这种以信号而非退出码到达的情况——会自动重启,退避 1s/3s/8s。连续三次失败才弹窗,而不是无限重试。稳定运行满一分钟即重置预算,所以偶发崩溃永远有完整的三次机会。 |
| 启动可恢复 | 服务未在就绪时限内应答时提供重试,而不是直接结束应用:磁盘繁忙时它通常只是慢,并没有坏。若刚做过插件操作,弹窗会直接指认那个插件,并给出「卸载/停用它并重启」——装坏一个插件不该需要用户自己去猜。 |
| 把文件发给对话 | 三个入口通向同一件事:macOS 上从访达「打开方式」选它、或把文件拖到程序坞图标;Windows 上加进右键「发送到」菜单(设置里一键开关);两个平台都支持直接把文件拖进窗口。文件路径会写进聊天输入框——dsh 是带文件系统工具的 agent,路径才是它能动手的东西,也不受文件大小限制。写入前会读回校验,写不进去(比如还没选工作区)就退回复制到剪贴板并提示粘贴,功能不会哑掉。拖拽先让页面自己处理,页面接手了就不插手。 |
| 常驻行为 | 它是个常驻服务,只是恰好带了个窗口:可设开机自启、启动后直接留在托盘不弹窗,窗口尺寸与位置也会记住(保存的矩形若落在已拔掉的显示器上会被丢弃,免得窗口开在看不见的地方)。 |
| 存储 | DSH_HOME 指向应用数据目录内部,profiles、会话与设置全部归应用管理。菜单可直接打开数据目录与日志,也可导出数据快照与从快照恢复——运行时能双槽回退、外壳能热更新回退、插件能停用,唯独会话没有退路,快照就是那条退路。恢复前会先校验压缩包确实是数据目录的快照,被替换的目录改名保留而不是删除。 |
| 代理设置 | 应用有两条互不相干的网络:窗口自身的请求走 Chromium,而 npm(装运行时)、pnpm(装插件)、以及真正调用模型 API 的 dsh 服务进程读的是环境变量。GUI 应用从启动台打开时两者都拿不到——终端里 export 的代理它看不见,系统代理开关又常常是关的。菜单「设置 → 代理…」一次配好两条,并能分别测通。 |
| 内置工具链 | 打包版自带 Node 运行时,目标机器无需预装任何东西。源码运行时回退为在本机查找 Node ≥ 22(PATH、nvm、Homebrew、%ProgramFiles%),这也顺带绕开了 GUI 应用不继承 shell PATH 的问题。这个继承问题的影响面更广:dsh 要在 PATH 上找装插件用的 pnpm,以及可委派的 Claude Code 与 Codex CLI,而 macOS 上双击启动的应用拿到的只有 /usr/bin:/bin:/usr/sbin:/sbin。所以每次运行会问一次用户自己的 shell 它的 PATH 是什么——这覆盖的是用户实际在用的版本管理器和安装位置,而不是我们想得到的那几种——再把答案追加进去;万一 shell 问不到,后面还垫着常见的包管理器目录。 |
| 插件管理 | 在窗口里安装、更新、卸载 dsh 插件:npm 包名、GitHub 网页链接(含插件集合仓库里指向某个子包的 …/tree/main/packages/xxx 链接,例如 dsh-plugins)、github: spec、本地绝对路径,或直接选一个 zip 安装包——zip 会解压到 /dsh-home/plugins/ 后按本地路径安装。已装插件会在后台按 npm 配置的注册表(尊重镜像)查一次新版本,有则标出。插件可随时停用/启用而不必卸载——停用写的是 loader 条目上的 disabled: true(运行时自带的机制),而不是 profile 的 bundle 列表,因为那个列表会被 dsh plugin 每次操作时按已安装状态重新对账。插件若导出配置 schema,会自动生成表单;填写的值写入 profile 的 plugin-config.json,并与停用状态一起镜像进 cordis.patch.yml 中带标记的托管块。 |
| 性能浮标 | 菜单里开关的小号置顶窗口,显示此刻 harness 的开销:CPU、常驻内存、线程数,以及进程组里有几个进程。速率是真的速率——ps 的 CPU 是进程生命周期的平均值,对一个从周二起就没退出的服务来说那是关于过去的数字,所以这里采两次累计 CPU 时间除以两次之间的墙上时间。按整个进程组统计,因为 dsh 会调 pnpm、会委托别的 CLI,那些同样是开销。只在显示时采样。 |
| 插件市场 | 独立窗口(菜单「插件 → 插件市场…」):读取 DSH Market 的目录,可搜索、看星标与描述,一键安装。目录在本地缓存(6 小时内不再联网,可手动刷新),离线也能浏览。只有市场已核验、且从 npm 分发的条目提供一键安装;git 来源的条目只给出仓库链接,需要自行在「已安装」页手动安装。换源见数据位置中的 marketCatalogUrl。 |
| 浏览器侧栏 | agent 刚写好的页面以前会丢给 Safari —— 和产生它的会话不在同一个应用里。现在它在聊天旁边的面板里打开,agent 还能操作它:导航、快照、点击、输入、读控制台和网络请求。同一套动词同时是命令行(dsh-browser)和 agent 工具(mcp__browser__),全部通向壳持有的同一个 socket,所以 agent 能跑的任何东西 —— bash、脚本、插件 —— 摸到的都是同一个浏览器。 |
| 小程序模拟器 | 驱动本机安装的微信开发者工具(其协议不允许打包分发,所以应用找到并驱动用户自己那份 —— 或在「模拟设备 → 模拟器位置」里指定的那份)。agent 以工具形式拿到模拟器(mcp__miniapp__,命令行是 dsh-miniapp):打开项目、把页面读成带实时文案和几何的 ref、点击、输入,以及浏览器够不到的 —— 直接读写页面 data、直接调 wx. API,想看的状态可以直接进入而不用一路点过去。应用自己启动的开发者工具在退出时被请退;用户本来就开着的只是借用,原样归还。 |
| 手机模拟器 | Google 的 Android 模拟器,经 adb 驱动:启动虚拟设备、把屏幕从实时无障碍树读成 ref、点击、输入、滑动、装 APK、读 logcat(mcp__phone__,命令行是 dsh-phone)。每次动作前都重读屏幕、按身份重新找到目标再触碰 —— 滚动过的列表点的是它现在的位置,已经不在的目标报告"不在了"而不是往旧坐标上按。没有 SDK 的机器会得到下载提议(约 2.1GB,可断点续传、可观测、可取消),前提是同意 Google 的条款 —— 应用绝不代替用户同意。第三方模拟器(MuMu、雷电、夜神…)和真机可以指名接入;不指名时,应用自己只会选虚拟设备。iOS 模拟器可以列出和启动,但 Apple 不提供注入输入的途径,所以只能看、不能驱动。 |

从源码运行

npm install
npm start

首次启动会从 npm 安装 @deepseek-ai/dsh@latest(需要网络,耗时几分钟)。数据与日志见数据位置。

macOS 上,npm start 首次运行会用已安装的 Electron 在 node_modules/.cache/dsh-desktop-dev 生成一个品牌化开发 App,随后每次只同步当前 src/、assets/ 并重新做 ad-hoc 签名。这样菜单栏、程序坞与窗口都显示 DeepSeek Harness,同时运行的仍是当前源码;这个步骤不会再次下载 Electron。若要直接使用原始 Electron.app 排查宿主问题,可运行 npm run start:electron,此时菜单栏显示 Electron 是预期行为。

这个开发 App 有自己的 bundle identifier,macOS 不必在它和已安装版之间做选择;但数据目录是共用的——这正是它的用处,平时就是拿真实会话来调试的。由此有一点需要知道:两者同一时间只能跑一个,而现在它们外观完全一致,所以当 npm start 发现已安装版正在运行时,会打印一条说明并以非零码退出,而不是悄悄把那个窗口拉到前面。先退出它再启动。源码运行下应用更新也是关闭的——它下载的 shell 源码启动方式并不会去用——运行时更新仍然可用。

如果 npm install 卡在下载 Electron

electron 包的 postinstall 会从 GitHub Releases 拉取约 100MB 的运行时,这一步不走 npm registry——只改 registry 不解决问题。当网络无法访问 GitHub 或被重置时(表现为 node_modules/electron 下的 RequestError: read ECONNRESET),把两个下载器都指向镜像。

Windows(cmd,须与后续命令在同一个窗口):

set ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
set ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/

macOS / Linux:

export ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/
export ELECTRON_BUILDER_BINARIES_MIRROR=https://npmmirror.com/mirrors/electron-builder-binaries/

要持久生效,把同名键以小写写进 .npmrc(electron_mirror=…),npm 会把它传给生命周期脚本。注意 npm config set electron_mirror … 会被 npm 9 及以上版本拒绝——它校验键名,而这些并非 npm 自身的选项。

第二个变量在打包阶段才起作用:electron-builder 同样会从 GitHub 下载它自己的辅助二进制(NSIS、winCodeSign),只设第一个的话,你会在 npm run dist:win 时撞上同样的失败。

安装失败会留下写了一半的 node_modules;Windows 上 npm 清理时报 EPERM: operation not permitted, rmdir,意味着有进程正占用这些文件(杀毒软件、编辑器、资源管理器)。关掉占用方,删除 node_modules,重新安装。

打包

打包是对打包机的快照。每个 dist 脚本都会先执行 npm run seed,在项目根目录生成两个归档:

- seed.tar —— 本机数据目录中当前安装的 dsh 运行时
- node-runtime.tgz —— 本机的 Node 二进制与 npm,使装好的应用无需预装 Node

由此有两条约束。打包前必须先跑一次应用,否则没有运行时可快照,构建会以 No active local dsh runtime 中止。以及每个平台的包必须在该平台上打——在 macOS 上打出的 Windows 安装包里装的是 macOS 的 Node 二进制。要交叉编译,只能放弃离线种子、改为按目标平台下载 Node。

第一条约束可以在构建机上放宽:node scripts/prepare-seed.mjs --bootstrap(或设 DSH_SEED_BOOTSTRAP=1,它能穿过 npm 的 pre 钩子)会在没有运行时的机器上先装一份再快照——CI 走的就是这条。第二条绕不开,所以有了下面的 Actions。

GitHub Actions

.github/workflows/build.yml 在三台机器上各打一份:macOS Apple Silicon(macos-14)、macOS Intel(macos-15-intel)与 Windows(windows-latest)。触发方式是手动运行,或推一个 v 标签。

三行,因为打包会快照宿主机:Intel 版的 dmg 必须在 Intel runner 上打。原先承担这件事的 macos-13 已经下架,macos-15-intel 接替了它,且属于标准 runner,公开仓库免费。两行 mac 的差别只在落到哪台宿主机上——electron-builder 按宿主机架构决定产物。

推标签时,产物直接传到对应的 Release(用 runner 自带的 gh,不引入第三方 action)。手动运行默认不上传安装包:免费账户的 artifact 存储只有 500MB,而一个 dmg 就 200MB 出头,三个平台会直接撑满;需要产物时在运行对话框里勾选 upload,用完记得删。

工作流里 setup-node 固定的 Node 版本不只是构建工具——npm run seed 会把它的二进制和 npm 打进应用,所以那就是打包版实际运行 dsh 用的 Node。

签名方面与本机打包一致:macOS 仍是 ad-hoc、Windows 未签名。工作流末尾留了一段注释,说明拿到 Apple Developer ID 之后要加哪些 secrets——除了过 Gatekeeper,更实际的收益是 macOS 把隐私授权(比如「文稿」目录)绑定在代码签名上,而 ad-hoc 签名每次构建都变,等于每次更新都悄悄吊销用户已经给过的授权;Developer ID 签名跨构建稳定,这个毛病随之消失。

macOS

npm install
npm start          # 先跑一次,让 dsh 运行时装好
npm run dist       # dist/mac-arm64/DeepSeek Harness.app
npm run dist:mac   # dist/DeepSeek Harness--arm64.dmg

构建由 scripts/adhoc-sign.cjs(afterPack 钩子)做 ad-hoc 签名,未做公证。缺少这一步的话,被改名的 Electron 二进制会带着失效的旧签名,Gatekeeper 会把带隔离属性的副本报成"已损坏",而不是给出正常的"未识别开发者"提示。

Windows

环境要求:Windows 10 1803 及以上(System32 中要有 tar.exe)、Node.js ≥ 22、Git。

git clone https://github.com/huyang218/dsh-desktop.git
cd dsh-desktop
npm install
npm start          # 先跑一次,让 dsh 运行时装进 %APPDATA%
npm run dist:win   # NSIS 安装包
npm run dist       # 或:仅生成免安装目录

产物:

dist\
├── dsh-desktop Setup .exe   NSIS 安装包
└── win-unpacked\                  免安装目录(npm run dist)

安装包为当前用户安装、允许选择安装目录(oneClick: false、perMachine: false),因此不需要管理员权限。它未做代码签名:首次运行 SmartScreen 会告警,直到该可执行文件积累足够信誉,或你在 build.win.certificateFile 配置签名证书。

这里同样必须先执行 npm start。跳过会在 predist 阶段失败,报 No active local dsh runtime under %APPDATA%\dsh-desktop\runtime。

安装后请验证平台支持一节列出的三件事,尤其是退出应用后不留孤儿 node 进程。

新增功能在 Windows 上的几点差异,已在实现里处理:热更新包解压到数据目录内的临时目录再改名启用,不经系统临时目录——跨盘符改名会以 EXDEV 失败;zip 安装包里若含 Windows 无法安全落盘的条目名(带 : 会写成另一个文件的数据流、CON/LPT1 等设备名、结尾的点或空格会被静默吃掉),解压会直接拒绝;「开机时启动」写的是当前用户的启动项,openAsHidden 是 macOS 专有的,Windows 上由应用自己的「启动后留在托盘」设置决定。整包更新下载的是 .exe 安装包,安装前需要先退出应用。

菜单

| 项 | 作用 |
|---|---|
| 插件 → 插件市场… | 浏览目录、搜索、一键安装 |
| 插件 → 插件管理… | 安装、更新、配置、卸载已安装的插件 |
| 设置 → 代理… | 配置网络代理,一次同时作用于窗口请求与所有子进程 |
| 设置 → 运行时更新通道 | 稳定版或预览版:检查运行时更新时跟随哪个 npm 标签,默认稳定版 |
| 检查应用更新 | 与 Release 对照;能热更新就热更新,否则下载安装包 |
| 检查运行时更新 | 在所选通道上做 dsh 运行时的双槽位更新,自检通过后询问是否重启 |
| 回退到 dsh <版本> | 切回另一个槽位里的上一个版本;另一槽位为空或同版本时不出现 |
| 设置 → 开机时启动 / 启动后留在托盘 | 常驻行为的两个开关 |
| 重启服务 | 停掉当前服务进程树,以同一版本重新启动 |
| 打开数据目录 / 打开日志 | |

数据位置

| 平台 | 路径 |
|---|---|
| macOS | ~/Library/Application Support/dsh-desktop/ |
| Windows | %APPDATA%\dsh-desktop\ |

dsh-desktop/
├── runtime/            已安装的 dsh:slot-a | slot-b、current.json
├── node-runtime/       内置 Node(仅打包版)
├── dsh-home/           DSH_HOME:profiles、会话、设置
│   └── plugins/        zip 安装的插件解压于此(profile 以 link: 指向)
├── shell/              热更新下来的外壳:current.json 指向正在用的那份
├── updates/            整包更新下载的安装包
├── market-catalog.json 插件市场目录缓存,删掉只会多刷新一次
├── settings.json       语言、插件市场源等外壳设置
└── dsh-desktop.log     应用与服务日志

settings.json 里可选的键:

| 键 | 作用 |
|---|---|
| locale | 界面语言,菜单里切换时写入 |
| startHidden | 启动后不弹窗,直接留在托盘 |
| windowBounds / windowMaximized | 窗口尺寸、位置与最大化状态,退出时记住 |
| proxy | { mode, url, bypass },mode 为 system(默认)/direct/manual。在「设置 → 代理…」里改;localhost、127.0.0.1、::1 恒定直连,不必写进 bypass。 |
| marketCatalogUrl | 插件市场目录地址,默认 https://dshplugin.market/plugins.json。换成自建或其他目录(例如 https://awesome-dsh-plugin.com/plugins.json)即可,改完在市场页点「刷新」。 |
| devtoolsPath | 微信开发者工具的位置,不想让应用去猜时用。在「模拟设备 → 模拟器位置」里设置,保存前会先检查。 |
| androidSdk | 手机模拟器使用的 Android SDK。同一菜单里设置,同样先检查;优先于 ANDROID_HOME。 |
| browserTools / miniappTools / phoneTools | 任一设为 false,对应的一套就不再进入 agent 的工具。三种能力各自独立,可以逐个拒绝。 |

应用更新

版本号来自 package.json,线上版本来自本仓库 Release 的最新 tag。每个 tag 构建除了 dmg 与安装包,还会发布两个小文件:

- shell-.zip —— 外壳自身的代码(src/ 与 assets/,不含 Electron 与运行时),约 170KB
- shell-update.json —— { version, electron, sha256, asset }

应用据此决定走哪条路:清单里的 Electron 大版本与正在运行的一致,就是热更新;否则说明这次改动落在应用包里(Electron 本身、内置 Node、运行时种子),只能走整包更新。

热更新落在 /shell//,由 src/boot.js 在启动时选择加载哪一份:

/shell/
├── current.json     { version, confirmed, attempts }
└── 0.1.2/           src/、assets/、shell.json

规则与 dsh 运行时的双槽位一致,只是换成了启动应用的代码本身:新包在证明自己能启动之前只有两次机会,加载即抛错、清单缺失、Electron 大版本不符、目录不见了——任何一种情况都回退到安装包里的那份并丢弃下载。换句话说,热更新最坏的结果不会差于用户当初装的版本,因为那份始终原封不动躺在原地。包在窗口与服务都起来后被标记为已确认(boot.js 另有一分钟兜底),之后不再计次。

下载的包按 shell-update.json 里的 SHA-256 校验,不匹配直接丢弃;信任根与下载安装包时相同,即 GitHub 的 TLS。

整包更新只负责把安装包下下来并在访达/资源管理器中打开,替换由平台自己的安装流程完成——应用在运行时替换自己,是同时失去两个版本的经典方式。

平台支持

| | 状态 |
|---|---|
| macOS(Apple Silicon) | 已完整验证 |
| Windows(10 1803 及以上) | 已完整验证:NSIS 安装包、首次启动、干净退出 |
| Linux | 未尝试 |

dsh 本身是跨平台的(无 os 限制,且自带 pwsh 与 Windows ACL 沙箱后端),所以平台工作全部集中在本壳。每一处 POSIX 假设都有对应的 Windows 实现:进程树终止用 taskkill /T 而非负 PID,tar 按名字调用,Node 查找取 node.exe 并搜索 %ProgramFiles%\nodejs 与 nvm-windows,托盘使用真实图标而非 macOS 模板图,数据目录经 %APPDATA% 解析。

进程树终止是唯一只能靠真机确认的部分,现已确认:杀进程组与 taskkill /T 是两种不同机制,做错的表现是应用看起来正常退出、却留下孤儿 dsh 进程——这种问题在代码审查里看不出来。改动退出逻辑后值得重新验一次;退出应用后,下面这条命令应无输出:

Get-Process node -ErrorAction SilentlyContinue | Where-Object { $_.Path -like 'dsh-desktop*' }

品牌封装

给应用命名的所有东西都来自 assets/brand.json:

{
"name": "DeepSeek Harness",
"appId": "io.github.huyang218.dsh-desktop",
"dataDir": "dsh-desktop",
"legacyDataDir": "dsh-shell",
"updateRepo": "huyang218/dsh-desktop",
"icons": { "mac": "assets/icon.icns", "win": "assets/icon-1024.png" }
}

改这一个文件,再跑同样的 dist 脚本,安装包、Bundle 标识符、程序坞与窗口名称、托盘提示、启动画面、数据目录与日志全都跟着走。electron-builder.config.cjs 读的是同一份文档,所以构建那一半不需要另一套配置。

有两个字段的分量比看上去重。

updateRepo 是这个构建的更新来源。品牌版若仍指向别人的 Release,第一次热更新就会把自己变回那个项目的名字和图标——几百 KB 的包悄悄把改名撤销。不填则完全不检查更新,这是「未配置」唯一安全的读法;菜单里会如实说明,而不是报错。

dataDir 是平台应用数据根目录下的目录名。给品牌一个自己的,品牌版与原版才能并存安装,彼此看不到对方的配置、会话与运行时。它必须是一个纯目录名,带路径分隔符的值会被直接拒绝而不是「清洗」成相近的东西——这一个字符串决定了应用写下的每一个字节落在哪里。legacyDataDir 用于迁移改名前的旧目录,只属于确实有过旧名字的品牌;新品牌没有历史可迁,继承别人的会把不属于它的数据接管过来。

打包出的应用会带上品牌指定的名称与图标。这不构成任何授权,见商标。

已知边界

- dsh 处于 rc 阶段。本应用依赖的契约刻意最小化:dsh web --port N,以及根路径返回 HTTP 200 即视为就绪。上游变更导致异常时,优先检查这两点。
- 本地端口对本机任意进程可见(dsh 目前无鉴权 token)。随机端口只是收窄窗口,并未关闭它。
- 对话依赖 DEEPSEEK_API_KEY,可在 dsh Web UI 的设置中配置,或在启动前导出到环境变量。
- macOS 构建为 ad-hoc 签名且未公证:首次打开需在「系统设置 → 隐私与安全性」中放行。
- macOS 的受保护目录(文稿、桌面、下载、外置卷)对本应用是隔离的:插件若以本地路径安装在这些位置,读取时会得到 EPERM。插件管理器会在报错后附上处置步骤。授权是绑定代码签名的,而 ad-hoc 签名每次重装都会变,所以更新应用后需要重新授权;用 zip 安装可以把插件放进应用数据目录,完全避开这一层。

相关项目

| 项目 | 是什么 |
| --- | --- |
| DeepSeek Harness | 本应用负责安装、更新与运行的那个运行时,也就是 dsh 本身 |
| dsh-plugins | dsh 的插件仓库:模型可调用的能力、围绕 harness 的运行时包装,以及 Web 客户端扩展。在「插件 → 插件管理…」里按 npm 包名或指向某个子包的链接即可装入 |
| dsh-android | 同一件事在手机上的版本:一个 Android 应用,把 dsh 的 host 与 client 都跑在设备本身,不连服务器,也不需要另一台开着的电脑。尚早——旁加载 apk |

dsh-plugins 与 dsh-android 与本应用出自同一作者;和本项目一样,都是非官方项目,与 DeepSeek 无隶属关系。

参与贡献

欢迎提交 issue 与 PR。

改动如果触及进程生命周期(启动、守护、退出),请在真实机器上验证"退出应用后不留孤儿进程"。这类缺陷在代码审查中不可见,单元测试也复现不出来。

贡献者

- Hu Yang(@huyang218,guxinglei218@qq.com)—— 作者、维护者

许可

以 MIT 许可证发布。

打包产物会再分发下列组件,各自遵循其原许可,声明随包保留:

| 组件 | 许可 | 包内位置 |
|---|---|---|
| DeepSeek Harness(@deepseek-ai/dsh 及插件) | MIT | Resources/runtime-seed.tar |
| Node.js | MIT | Resources/node-runtime.tgz → LICENSE-node |
| npm | Artistic-2.0 | 同一归档 → lib/node_modules/npm/LICENSE |
| Electron | MIT | 应用框架 |

商标

"DeepSeek" 是其所有者的商标。本项目为非官方项目,与其无隶属关系,也未获背书。 打包出的应用沿用 DeepSeek Harness 名称与鲸鱼图标,用以指明它所承载的上游软件;这些标识的权利属于其所有者,不在本项目的 MIT 授权范围内。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

同作者(huyang218)的其他插件

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群