← 返回列表
需源码安装
DeepSeek Harness 桌面应用
暂不能直接安装(需源码编译或环境不满足):仓库缺少 package.json,无法用 dsh 插件安装命令安装。 · 最近上游提交 2026/9/17 · 已提供中文文档
DeepSeek Harness 的原生 Windows 桌面应用:启动 harness 服务器、打开你的项目,并在关闭窗口时停止服务器。
综合分
29.5
GitHub 分
29.5
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add desanv01/deepseek-harness-desktop-app仓库缺少 package.json,无法用 dsh 插件安装命令安装,改用 GitHub 源安装
信任档位:已验证本站已于 1 天前真实安装成功
- 是什么
- dsh 原生插件 · desktop
- 装得上吗
- 本站已真实安装成功(非静态推断)
- 安全吗
- 本站尚未对该插件做风险分级(暂未覆盖,不等同于无风险)
- 还在维护吗
- 活跃:最近一次提交在 9 天前
档位由下列信号合成:本站实装验证(真实安装,当前最高到 L4)· 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。下方各区块是它的证据明细。 验证判据与等级说明 →
🟢实装验证通过· 2026/9/25
由本站实装验证器在真实 dsh 环境安装成功,非静态推断。
数据截至 2026/9/21(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
安装兼容性检查需源码安装
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包deepseek-harness-desktop-app(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✗入口文件缺少入口声明
仓库缺少 package.json,无法用 dsh 插件安装命令安装
验证方式:npm registry 存在性 + package.json 静态校验 · 最后验证 2026/9/22 08:28:02
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
由 DeepSeek 最新模型翻译生成DeepSeek Harness 桌面应用
一个用于 DeepSeek Harness 的原生 Windows 桌面应用——启动时启动 harness 服务器,直接打开你的项目,并在关闭窗口时关闭服务器。
MIT
Windows
.NET
C%23
WebView2
Status
DeepSeek Harness 通常以 dsh web 的形式在终端中运行,并在浏览器标签页中打开。此应用省去了这一步:一个可执行文件即可启动 harness,在其内嵌的 WebView2 窗口中渲染其界面,并端到端地管理服务器生命周期。无需终端,无需浏览器配置文件,无需手动启动或停止。
项目状态: 这是一个可用的基线版本,已在 Windows 11 上针对 @deepseek-ai/dsh 0.1.2-rc.1 构建并验证。启动、附加和关闭路径均已测试。带签名的自更新尚未实现。参见当前状态。
截图
原生窗口内的 DeepSeek Harness UI,窗口图标和标题栏主题与页面相匹配。
DeepSeek Harness 原生窗口
窗口外观跟随渲染页面——深色页面,深色标题栏。
DeepSeek Harness 原生窗口,深色外观
为什么会有这个项目
手动运行 harness 意味着要打开终端、切换到项目目录、输入命令、复制带令牌的 URL,还要记得之后停止服务器。这对每次会话都是摩擦,而且很容易留下一个占用端口的孤立服务器。
此应用将这一系列操作变成双击,并让服务器的生命周期与窗口的生命周期一致:
- 无需终端,也无需记住命令;
- 窗口打开的是你选择的项目,而不是一个通用仪表盘;
- 端口由操作系统选择,因此不会发生冲突;
- 关闭窗口会停止服务器,应用崩溃时也是如此。
目标是成为一个可靠的本地 harness 桌面外壳——而不是一个硬加上窗口的启动脚本。
功能
- 无终端启动——以隐藏子进程方式启动 dsh web --no-open。永远不会显示控制台窗口。
- 快速启动——CLI 以低成本方式探测(0.2 秒),而不是在每次启动前用完整的 dsh web --help(7–8 秒)进行验证;深度检查仅在出现故障时作为诊断运行。内嵌浏览器在服务器启动期间预热,两次更新检查等待首次绘制,并且在启用 keep-alive 的情况下,后续启动会在几秒内附加到正在运行的服务器,而不是重新启动。
- 运行器持续运行 — 默认情况下,服务器的生命周期长于窗口,因此关闭并重新打开应用是附加到现有进程,而不是重新启动。托盘中的“停止服务器并退出”和 --stop 会结束它,而 --no-keep-alive 会恢复“关闭窗口即停止服务器”的行为。
- 记住你的项目 — 所选的文件夹、主目录和端口会保存到 settings.json。之后的启动无需任何标志即可打开同一个项目;首次启动时会显示一个包含最近项目的选择器。
- 打开你的项目 — --project 会成为服务器的工作目录,这正是限定运行器工作区范围的方式。窗口标题会显示项目名称。
- 由操作系统分配端口 — 以 --port 0 启动,并从运行器打印的就绪行中读取真实地址,因此不会发生端口冲突。
- 验证端点 — 在显示之前,确认所服务的根文档包含 DSH 引导全局变量,因此绝不会嵌入无关的本地服务。
- 保证关闭 — 子进程被分配到一个带有 kill-on-close 的 Windows 作业对象。当应用退出、崩溃或被强制终止时,服务器及其后代进程会被操作系统终止。
- 每个主目录一个服务器 — 以 DSH_HOME 为键的命名互斥量意味着第二次启动会将焦点交给正在运行的窗口,而不是在同一组会话文件上启动第二个写入者。
- 托盘图标 — 在整个窗口生命周期内都存在:将窗口隐藏到托盘、将其恢复、打开项目文件夹或日志目录、查看已安装的运行器版本、检查是否有更新的运行器,以及停止服务器。
- 普通窗口行为 — 最小化会像任何其他窗口一样最小化到任务栏;隐藏到托盘是明确的托盘菜单操作,而关闭窗口仍会停止服务器。
- 感知运行器版本 — 启动时会读取一次 npm 的 latest 和 alpha dist-tags,并在托盘中显示结果。该检查是只读的;安装是一次有意的点击操作,会在窗口重启前验证 CLI。
- 无论 npm 将运行器放在哪里都能找到它 — CLI 的定位方式与 shell 定位它的方式相同:读取 PATH 上的 dsh shim 以获取它运行的入口点,遵循包自身 package.json 的 bin,并通过 npm prefix -g 找到 PATH 之外的全局前缀。因此,自定义 npm 前缀、pnpm 风格的存储或包布局变化仍然可以解析。
- 修复损坏的运行器安装 — 中断的 npm install -g 会留下包目录,但缺少 CLI 所需的文件。应用会明确说明这一点,而不是声称运行器未安装,并提供安装它的选项;--update 会不经询问地执行相同操作,而 --repair-harness 会从脚本中执行。在 npm 触碰一个可用的安装之前,应用会将其移到一旁,如果结果未通过验证就将其放回,因此更新失败绝不会让你失去一个可用的运行器。
- 感知更新 — 启动时它还会向 GitHub 询问此应用是否有更新的构建版本,将结果缓存六小时,并在存在新版本时进行通知:托盘通知、托盘菜单中的一行、harness 页面内的一个胶囊标签,以及窗口标题中的版本号。检测仅读取发布元数据。
- 应用内更新 — Updates 区域位于 harness UI 内部,这正是此 harness 期望扩展所在的位置。一个捆绑的 DSH 插件将其注册到侧边栏(紧邻 Settings)以及 Settings 本身,并通过一个带版本的页面桥接(window.__dshDesktop)与应用通信。应用保留页面绝不能持有的东西:下载、校验和验证、暂存替换以及重启。原生更新窗口仍作为后备方案,并作为从托盘进入的快捷方式。
- 插件以两种方式分发 — 可执行文件自带该插件,并将其安装到应用所拥有的 home 中,无需包管理器,也无需网络;同一个包也发布到 npm,因此 dsh plugin add dsh-plugin-desktop-updates 可以像任何其他 DSH 插件一样将其安装到任意 home 中。启动时会保留比捆绑版本更新的已安装副本,因此 npm 路径不会在下次启动时被撤销;--install-plugin 会有意恢复捆绑副本。
- 插件管理 — 同一区域可安装、切换和移除 harness 插件:我们的和第三方的,可通过 npm 名称、git 规格或本地文件夹。pnpm 由构建携带(从可执行文件中提取,或在构建未附带时用 npm 获取),因此 dsh plugin add 可在从未安装过 pnpm 的机器上运行。启用/禁用通过配置文件的补丁层进行,因此可以在不卸载插件的情况下将其从树中移除。
- 安全模式 — harness 无法加载的插件会中止整个配置文件。应用读取加载器自身的消息,禁用有问题的插件,并再次启动一次,因此一个坏插件只会带来一条通知,而不是一个永远打不开的窗口。--safe-mode 仅使用基础捆绑包启动。
- 暂存,绝不原地替换 — 正在运行的可执行文件在运行时绝不会被覆盖。下载在替换前经过验证,先前的构建会保留为 .old,直到新构建稳定运行,校验和不匹配会直接丢弃下载内容。
- 有界日志 — desktop.log 在 4 MB 时轮转,旧服务器日志在启动时被清理。
- 专用数据 home — 应用默认使用自己的 DSH_HOME,绝不触碰你未指向的 harness home。
- 可选更新 — --update 在锁保护下运行 npm install -g @deepseek-ai/dsh@latest,并在启动前验证 CLI。没有该标志时,启动绝不会改变一个正常工作的安装。
- 主题感知窗口 — 标题栏和边框跟随渲染页面的背景,窗口图标跟随 Windows 主题。
工作原理
flowchart LR
Start[Launch] --> Resolve{Project resolved?}
Resolve -->|no| Picker[Project picker]
Resolve -->|yes| Lock{Home lock}
Picker --> Lock
Lock -->|owner| Spawn[node dsh web --port 0]
Lock -->|busy| Focus[Bring the running window forward]
Spawn --> Job[Windows job object]
Spawn --> Ready[Read ready line]
Ready --> Verify[Verify DSH bootstrap marker]
Verify --> Window[WebView2 window on the project]
Window -->|window closed or app killed| Job
Job --> Stop[Server terminated]
启动序列
1. 应用加载 settings.json 并解析项目:先看 --project,然后是记住的文件夹,最后是带最近列表的交互式选择器。
2. 它解析 node 和全局 @deepseek-ai/dsh 入口,然后验证 CLI 能否加载。
3. 它获取每个 home 的互斥锁。如果另一个实例拥有该 home,它会通知那个窗口置前并退出。
4. 它以项目为工作目录,并使用选定的 DSH_HOME,启动 dsh web --no-open --host 127.0.0.1 --port 0。
5. 在消费任何输出之前,子进程会被分配到一个关闭即杀的任务对象中。
6. 应用读取子进程的 stdout 以获取就绪行——dsh web: http://127.0.0.1:/?token=——其中同时包含端口和访问令牌。
7. 它探测该已认证 URL,并要求根文档中存在 DSH 引导标记。
8. WebView2 窗口在该 URL 上打开。租约(PID、启动时间、端口、URL、项目)会被持久化以供其他实例使用,解析出的选择会保存到 settings.json。
9. 关闭时,应用会杀掉它启动的那个确切子进程,释放任务句柄,并移除租约。
要求
| 要求 | 备注 |
|---|---|
| Windows 10/11 x64 | Windows 11 22H2 或更高版本可启用完整的标题栏主题化 |
| WebView2 Runtime | Windows 11 和大多数 Windows 10 机器上已预装;如果缺失,窗口会显示官方安装链接 |
| Node.js | 测试框架本身需要 |
| @deepseek-ai/dsh | 全局安装:npm install -g @deepseek-ai/dsh |
| .NET 8 SDK | 仅用于从源码构建;发布的便携版构建会捆绑运行时 |
快速开始
运行已发布的构建
1. 从 Releases 下载 DeepSeekHarness-win-x64-.zip。
2. 解压到任意位置并运行 DeepSeekHarness.exe。
3. 首次启动会显示项目选择器;选择要打开的文件夹。该选择会被记住。
4. 几秒钟后,窗口会在该项目上打开。
关闭窗口即可停止服务器。
从源码构建
git clone https://github.com/desanv01/deepseek-harness-desktop-app.git
cd deepseek-harness-desktop-app
framework-dependent dev build -> dist\ (needs the .NET 8 runtime)
.\build.ps1
self-contained single-file exe -> release\ (no .NET needed on the target)
.\build_portable.ps1
build_portable.ps1 是 build.ps1 -SingleFile 的薄别名。两者都接受 -RestoreSource,用于从文件夹或源还原包,而不是从机器配置的 NuGet 源还原——这对断网或气隙机器很有用:
.\build.ps1 -SingleFile -RestoreSource C:\offline-nuget # 存放 .nupkg 文件的文件夹
.\build.ps1 -Portable -RestoreSource https://my-feed/v3/index.json
文件夹缺失时会以退出代码 2 和一条清晰的消息退出,而不是抛出 NuGet 堆栈跟踪。
在 Visual Studio 中打开 DeepSeekHarness.sln,如果你更喜欢使用“发布”对话框,请使用 PortableFolder 或 PortableSingleFile 发布配置文件。
冒烟测试
dotnet build -c Release -r win-x64 # 或 .\build.ps1
.\tools\smoke-test.ps1 # 测试 .\dist\DeepSeekHarness.exe
tools\smoke-test.ps1 是一个针对应用中依赖本机环境部分的行为测试套件:它会构建一次性的测试夹具——一个带有 shim 和包的伪造 npm 全局前缀,以及一个可以成功、失败或留下半写入包的伪造 npm——然后断言应用报告了什么以及它对安装做了什么。它不需要网络、不需要真实的 harness 安装,也不需要真实的 npm,CI 会在每次推送时运行它。
tools\client-plugin-smoke.mjs 使用一个最小化的 React 和一个伪造的 shell 来渲染更新插件的浏览器端部分:它加载真实的 client.js,检查插件是否注册了两个插槽,并断言各组件产生的内容——侧边栏条目、带实时状态的设置部分、插件管理器的控件,以及桌面应用未连接时显示的消息。伪造的 shell 强制执行真实 shell 所执行的规则——两个插槽都是列表,而没有 id 的列表条目会被拒绝——并在插件应用之后声明侧边栏插槽,这正是真实声明发生的时间。这就是在 WebView2 无法启动的情况下验证 UI 的方式;行为测试套件将其作为最后一个场景运行。
tools\boot-graph-probe.mjs 弥合了“插件已安装”和“插件在页面中运行”之间的差距。它获取正在运行的 dsh web 就绪行的 URL 和令牌,生成浏览器会话,从所提供的页面中读取 window.__DSH_BOOT__,获取启动图所公布的插件包,并检查浏览器将要运行的源代码是否携带了它所需的模块 id、标记和插槽 id。行为测试套件的最后一个场景会在一个夹具主目录上启动真实服务器并运行它,因此加载器从未发出的插件或返回 404 的包路由会在 CI 中失败,而不是在窗口中失败。
发布插件
该插件随可执行文件分发,也发布在 npm 上。仓库中的副本是 private: true——它携带应用自身的文件,从检出目录中意外执行 npm publish 绝不能将其推送出去——因此发布时会先暂存它的一个副本:
node tools\stage-plugin-package.mjs plugins\dsh-plugin-desktop-updates plugin-out
cd plugin-out; npm publish --access public
.github/workflows/publish-plugin.yml 正是按需执行这一操作。在 plugins\dsh-plugin-desktop-updates\package.json 中提升版本号,合并后,用相同的版本号运行该工作流:它会拒绝清单中未声明的版本,以及已经发布过的版本。它需要一个 NPM_TOKEN 仓库密钥(一个 npm 自动化令牌),并在缺少该密钥时明确提示。
发布一个版本
DeepSeekHarness.csproj 中的 是 yyyy.MM.dd 形式的发布日期,而发布标签是 v。更新程序将两者作为日期进行比较,因此它们必须一致——当不一致时,工作流会拒绝发布。
1. 将 设置为今天的日期,然后
git commit -am "Release 2026.09.15"
git push origin main
2. 打标签;标签才是发布的关键
git tag v2026.09.15
git push origin v2026.09.15
随后,.github/workflows/release.yml 会从该标签构建自包含的单文件 exe,为 exe 和 zip 写入 SHA256SUMS,并创建包含全部三个资产的 GitHub 发布。.github/workflows/ci.yml 会构建每次推送和拉取请求,检查版本是否为日期,并对已发布的 exe 的标志和退出码进行冒烟测试。两者都运行在 windows-latest 上,且不需要仓库密钥。
更新程序会下载 exe,并根据同一发布中的 SHA256SUMS 对其进行校验,因此校验和资产并非可选:没有该资产的发布仍然可以安装,但只有在应用告知你无法验证之后才行。
命令行参考
DeepSeekHarness.exe 正常启动(自有服务器,由操作系统选择端口)
DeepSeekHarness.exe --project C:\work\my-repo 在窗口中打开该工作区
DeepSeekHarness.exe --dsh-home C:\dsh-home 使用指定的 harness 主目录
DeepSeekHarness.exe --port 8080 固定端口,而不是让操作系统选择
DeepSeekHarness.exe --update 先更新全局 dsh(需主动选择,也可修复损坏的安装)
DeepSeekHarness.exe --repair-harness 安装或修复全局 @deepseek-ai/dsh,然后退出
DeepSeekHarness.exe --dsh-cli 使用此 harness 入口点,而不是搜索一个
DeepSeekHarness.exe --self-test 输出环境报告并退出
DeepSeekHarness.exe --check-harness 报告已安装与已发布的 harness 版本
DeepSeekHarness.exe --check-updates 报告应用 + harness 的更新状态(退出码 10 = 有可用更新)
DeepSeekHarness.exe --updates 启动时打开更新窗口
DeepSeekHarness.exe --keep-alive 让 harness 的生命周期长于窗口(默认)
DeepSeekHarness.exe --no-keep-alive 关闭窗口即停止服务器
DeepSeekHarness.exe --safe-mode 仅使用基础包启动
DeepSeekHarness.exe --install-plugin 将捆绑的更新插件安装到主目录,然后退出
DeepSeekHarness.exe --plugin-list 列出此 home 运行的插件
DeepSeekHarness.exe --add-plugin 安装插件(npm 名称、git 规格或本地文件夹)
DeepSeekHarness.exe --remove-plugin 移除一个
DeepSeekHarness.exe --enable-plugin 启用一个(用 --disable-plugin 关闭)
DeepSeekHarness.exe --bridge-selftest 在没有浏览器的情况下演练页面桥接协议
DeepSeekHarness.exe --install-update 下载 + 验证 + 暂存最新版本,然后退出
DeepSeekHarness.exe --install-update --apply-now ... 并移交给更新助手(重启应用)
DeepSeekHarness.exe --no-update-check 启动时不向发布源询问任何内容
DeepSeekHarness.exe --update-feed 从此处读取发布源,而不是 GitHub API
DeepSeekHarness.exe --stop 停止此应用启动的服务器
DeepSeekHarness.exe --no-window 无头启动测试:启动、验证、停止
| 标志 | 默认值 | 含义 |
|---|---|---|
| --project | 记住的项目,否则弹出选择器 | 受管服务器的工作目录:窗口打开的工作区 |
| --dsh-home | 记住的 home,否则 %LOCALAPPDATA%\DeepSeekHarness\home | 受管服务器的 DSH_HOME;一个服务器拥有一个 home |
| --port | 0(操作系统选择一个空闲端口) | 固定监听端口;无论如何,真实端口都从就绪行读取 |
| --keep-alive | 开启 | 受管服务器的生命周期长于窗口;下次启动会附加到它 |
| --no-keep-alive | 关闭 | 关闭窗口会停止服务器,与 keep-alive 之前一样 |
| --safe-mode | 关闭 | 仅使用基础捆绑包启动,将添加的插件搁置一旁 |
| --install-plugin | 关闭 | 将捆绑的更新插件安装到选定的 home 并退出 |
| --plugin-list | 关闭 | 打印此 home 运行的捆绑包,包括版本和状态 |
| --add-plugin | — | 通过应用执行 dsh plugin add:注册表名称、git 规格或本地文件夹 |
| --remove-plugin | — | 从配置文件中移除一个插件 |
| --enable-plugin / --disable-plugin | — | 通过配置文件的补丁层切换一个插件,同时保持其安装状态 |
| --bridge-selftest | 关闭 | 检查页面桥接协议(解析、分发、回复、事件)并退出 |
| --address | 127.0.0.1 | 受管服务器的绑定地址 |
| --ready-timeout | 240 | 等待服务器就绪行的时长 |
| --update | 关闭 | 在启动前运行 npm install -g @deepseek-ai/dsh@latest;还会安装或修复缺失、安装不完整的 CLI |
| --no-update | 开启 | 显式别名,保持更新关闭 |
| --repair-harness | 关闭 | 安装或修复全局 @deepseek-ai/dsh,然后退出(0 可用,1 仍损坏,10 缺少 node 或 npm) |
| --dsh-cli | 自动检测 | 要使用的 Harness 入口点;用于搜索无法看到的安装 |
| --no-window | 关闭 | 无 UI 的自有模式启动测试 |
| --self-test | 关闭 | 打印环境报告并退出 |
| --check-harness | 关闭 | 打印已安装与已发布的 harness 版本并退出(0 为最新,10 有可用更新) |
| --check-updates | 关闭 | 打印桌面应用和 harness 的更新状态并退出(0 为最新,10 有可用更新,1 无可检查项) |
| --updates | 关闭 | 应用窗口启动后立即打开更新窗口 |
| --install-update | 关闭 | 无窗口下载、验证并暂存最新版本,然后退出(0 已暂存,1 失败) |
| --apply-now | 关闭 | 与 --install-update 配合使用:移交给更新助手,而不是在暂存后停止 |
| --no-update-check | 关闭 | 本次启动从不请求发布源,托盘仍可按需检查 |
| --update-feed | GitHub API | 从此 URL 或 JSON 文件读取发布源;本地路径可在无网络的情况下驱动更新流程 |
| --stop | 关闭 | 停止所选 home 的托管服务器(未找到时退出码为 1) |
命令行标志始终优先于 settings.json;命令行中未指定的任何内容都会回退到已记住的值。
退出码:0 成功,1 运行时错误或无可停止项,2 参数无效,10–14 工具链问题,21/22 服务器启动或验证失败,30 端点被占用,40 home 被另一实例占用。
各项内容的位置
| 内容 | 位置 |
|---|---|
| 会话、设置、存储 | DSH_HOME — 默认为 %LOCALAPPDATA%\DeepSeekHarness\home |
| 应用设置 | %LOCALAPPDATA%\DeepSeekHarness\settings.json — 上次项目、home、端口、最近项目 |
| 应用日志 | %LOCALAPPDATA%\DeepSeekHarness\logs\(desktop.log 以及轮转后的 desktop.log.1,唯一的 server-.out/err.log,唯一的 npm-update-.log) |
| 服务器租约 | %LOCALAPPDATA%\DeepSeekHarness\instance-.json — PID、启动时间、端口、URL;正常停止时删除 |
| 已暂存的更新 | %LOCALAPPDATA%\DeepSeekHarness\updates\\ — 已验证的下载内容、pending.json、应用助手以及 apply-.log |
| 缓存的更新检查 | %LOCALAPPDATA%\DeepSeekHarness\update-check.json — 上次发布结果,六小时内复用 |
| WebView2 本地状态 | %LOCALAPPDATA%\DeepSeekHarness\webview2\ — 可安全删除 |
| 构建产物 | dist\ 和 release\(已被 git 忽略) |
删除 settings.json 只会恢复首次运行的选择器;它不保存任何凭据。
设置 DSH_DESKTOP_HOME 可将应用拥有的所有内容——设置、日志、租约和 WebView2 配置文件——重定位到一个目录下,而不是 %LOCALAPPDATA%。这使应用可便携(将其放在 exe 旁边的 USB 存储设备上),并为测试提供可运行的临时根目录:
powershell
$env:DSH_DESKTOP_HOME = "D:\portable\DeepSeekHarness"
.\DeepSeekHarness.exe
--self-test 会报告当前使用的是哪个根目录。该变量只影响应用自身的文件:测试框架主目录仍由 --dsh-home / 记住的设置来选择。
项目结构
text
src/DeepSeekHarness/
├── Program.cs # 入口点、DPI 感知、日志清理、错误处理
├── Options.cs # CLI 解析、验证、设置优先级
├── Settings.cs # settings.json:上次项目、主目录、端口、最近项目
├── Orchestrator.cs # 项目解析、启动、焦点交接、窗口生命周期
├── ProjectPickerForm.cs # 首次运行 / 最近项目选择器
├── ServerManager.cs # 启动 dsh、解析就绪行、租约、停止
├── JobObject.cs # Win32 作业对象(关闭时终止)
├── SingleInstance.cs # 将所属窗口带到前台的焦点事件
├── Proc.cs # 子进程运行/启动/终止、输出排空
├── ManagedLock.cs # 按主目录命名的互斥体
├── NetProbe.cs # 端点身份探测(DSH 引导标记)
├── Tools.cs # node/npm/dsh 发现与 CLI 验证
├── HarnessUpdate.cs # npm dist-tag 检查:已安装与已发布的 harness
├── AppInfo.cs # 此构建的版本、发布仓库和资产命名
├── AppUpdate.cs # GitHub 发布检查、版本比较、缓存结果
├── UpdateHttp.cs # 更新传输:进程内 TLS、Node 回退、file:// 源
├── UpdateInstaller.cs # 下载、SHA-256 校验、分阶段应用和辅助程序
├── UpdatesForm.cs # 更新窗口:桌面应用、harness、关于
├── Updater.cs # 可选的串行化 npm 更新
├── AppPaths.cs # %LOCALAPPDATA% 布局、主目录键、日志清理
├── MainForm.cs # WebView2 窗口、主题测量、托盘交接、桥接宿主
├── DesktopBridge.cs # window.__dshDesktop:带版本的页面桥接及其协议
├── DesktopPlugin.cs # 捆绑的 harness 插件:解压、安装、保持最新
├── DesktopPluginCli.cs # --install-plugin
├── HarnessProfile.cs # 主目录运行的配置文件:捆绑栈和补丁层
├── PluginManager.cs # 添加/移除/启用/禁用,及其携带的 pnpm 运行时
├── PluginCli.cs # --plugin-list / --add-plugin / --remove-plugin / --enable-plugin
├── SafeMode.cs # 从 harness 无法加载的插件中恢复
├── MarkdownView.cs # 渲染到更新窗口中的发布说明
├── TrayIcon.cs # 托盘图标及其菜单
├── SplashForm.cs # 带实时状态的启动闪屏
├── Theme.cs # 共享调色板和嵌入图稿
├── NativeTheme.cs # DWM 深色模式和标题栏颜色
├── SelfTest.cs # --self-test 报告
├── Log.cs # 轮转、永不抛出的文件 + 控制台日志记录器
└── Ui.cs # 消息框错误界面
assets/ # 官方 DeepSeek 图稿(由 tools\update-icons.ps1 重新生成)
assets/pnpm/ # pnpm 运行时,由 build.ps1 获取并嵌入(已被 git 忽略)
plugins/ # 此应用随附的 harness 插件
dsh-plugin-desktop-updates/ # 更新 UI:侧边栏条目 + 设置部分
screenshots/ # README 图片
build.ps1 # 开发 / 便携文件夹 / 单文件构建
build_portable.ps1 # 一个自包含 exe + zip
tools/smoke-test.ps1 # 行为测试套件:CLI 发现、修复、安装安全性
tools/client-plugin-smoke.mjs # 以无头方式渲染更新插件的浏览器部分
tools/boot-graph-probe.mjs # 读取运行中服务器的启动图及其提供的插件包
tools/update-icons.ps1 # 重新生成嵌入的 DeepSeek 图稿
故障排除
- 窗口长时间显示“Starting …” — 运行 DeepSeekHarness.exe --self-test,调高 --ready-timeout,并查看最新的 server-.out.log。
- WebView2 failed to initialize — 缺少 WebView2 运行时;窗口会显示官方安装链接。
- “Could not start the embedded browser” — 该消息带有运行时的 HRESULT 以及传给它的数据文件夹,并且 desktop.log 中有同一行内容以及内部异常链。0x8000FFFF 表示运行时拒绝启动,通常是缺少运行时,或者账户无法写入临时文件夹。0x80080005(“Server execution failed”)意味着浏览器进程完全无法启动——拒绝进程访问的受限环境会产生此错误,而运行时自身的崩溃处理程序会说明原因(crashpad: OpenProcess: Access is denied);没有任何 Chromium 标志能绕过这一点,因此应用必须运行在浏览器可以启动的地方。--self-test 会打印此机器报告的运行时版本。
- @deepseek-ai/dsh is not installed globally — 未找到任何看起来像 harness 的内容。应用会提议安装它;从脚本中,DeepSeekHarness.exe --repair-harness 或 --update 也能做到同样的事,并且两者都会打印它们查找的位置。
- @deepseek-ai/dsh is installed but incomplete — 包目录存在,但缺少 CLI 所需的文件,这正是 npm install -g 被中断后留下的结果。对话框会指出缺失的文件;接受安装(或 --repair-harness)即可修复。在可用的 CLI 上安装会保留一份副本,直到替换版本通过验证,因此这不会让你陷入困境。
- dsh 在终端中可用,但应用找不到它 — 应用会读取 PATH 上的 dsh shim、包的 package.json bin、%APPDATA%\npm 以及 npm prefix -g。如果你的安装位置不在这些位置中的任何一个,--dsh-cli 可直接指定它;--self-test 会打印搜索过程。
- “Another instance owns this home” — 第二个窗口已经在为同一个 DSH_HOME 提供服务。正常启动只会将该窗口带到前台;此消息意味着所有者仍存活,但其服务器没有响应,因此请关闭它(或运行 --stop)然后重试。
- 每次启动都会出现项目选择器 — settings.json 无法写入(检查 %LOCALAPPDATA%\DeepSeekHarness 的权限),或者记住的文件夹已被移动或删除。请重新选择项目以重新记录它。
- 侧边栏中缺少“检查更新”条目 — harness shell 会静默拒绝槽位注册:它会丢弃该条目,而页面看起来一切正常。插件会记录它注册了什么以及什么被拒绝了,应用在每次页面加载后都会记录该标记,Updates 部分也会重复它。在 desktop.log 中搜索 updates plugin in the page: — 非空的 failed 列表会指出槽位名称以及 shell 给出的原因。该条目带有 id: 'desktop-updates',因为 sidebar.footer.action 是一个列表槽位,而 shell 要求条目具有 id。
- 端口已被占用 — 只有在你用 --port 固定一个端口时才可能发生;默认的 --port 0 不会冲突。
- 服务器在崩溃后仍然存活 — 作业对象通常会阻止这种情况;如果确实发生了,DeepSeekHarness.exe --stop 只会停止 PID 和进程启动时间仍然匹配的那个租约。
当前状态
已在 Windows 11 x64 上使用 .NET 8、WebView2 153.0.4234.32 和 @deepseek-ai/dsh 0.1.5-rc.1 验证:
- dotnet build -c Release — 构建干净;
- 无头启动(--no-window)— 由操作系统分配端口,解析到就绪行,验证端点,停止服务器;
- 使用 --project 启动 GUI — 写入包含项目、主目录、端口和最近列表的设置;
- 不带任何标志的第二次启动 — 从设置中解析项目,将正在运行的窗口带到前台,并在不启动第二个服务器的情况下退出;
- 强制终止应用 — 托管服务器在几秒内消失;
- --stop、无效的 --port、未知标志、缺少 --project — 退出代码正确;
- 针对实时仓库的更新检查 — 即使匿名 API 限制已耗尽,重定向端点也会报告最新标签,并且当存在更新的构建时 --check-updates 退出码为 10,当正在运行的构建是最新时退出码为 0;
- 针对本地发布夹具的更新安装 — 下载、SHA256SUMS 验证、分阶段应用、重启;被篡改的校验和会被拒绝并丢弃下载;立即退出的构建会回滚到上一个构建;
- 注入的更新提示 — 针对假 DOM 进行了测试(一个元素,点击时提交,隐藏,在缺少 document.body 时仍能存活);
- harness CLI 处理 — tools\smoke-test.ps1 覆盖了通过 shim 和通过 package.json 的发现、将半安装的包报告为不完整、--repair-harness 安装缺失的 CLI、安装失败时恢复上一个 CLI,以及安装成功时替换它;
- 插件流水线——同一套测试套件会把捆绑插件安装到一个全新的 home 中,添加一个本地插件,通过补丁层将其关闭再打开,拒绝关闭基础捆绑包,将其移除,并启动一个插件在导入时抛出异常的 home,在禁用该插件的情况下恢复;它还会在启动时将较新的插件保留在原位,并在执行 --install-plugin 时恢复捆绑副本(53 项断言,无网络);
- 页面桥接——--bridge-selftest,22 项检查,涵盖解析、分发、回复、参数解码、事件形状以及插件标记,在 WebView2 无法启动的环境中运行;
- 所服务的插件——在一个 fixture home 上启动真实的 dsh web,并询问它提供什么服务:启动图会列出插件行,bundle 路由返回 200,所服务的源码携带模块 id、标记以及侧边栏条目所需的 slot id(10 项检查,属于同一套测试套件);npm 路径也以相同方式走通,从打包的 tarball 经由 --add-plugin 到服务器随后所服务的图;
- 启动——在同一台机器上测量:之前到窗口就绪需要 25.5 秒,之后为 14.6 秒(仅预检阶段就从 10 秒降至 1 秒);
- keep-alive——服务器在窗口关闭后仍然存活,下一次启动会接管它(相同的 pid),并且 --stop 会将其结束;
- --stop、无效的 --port、未知标志、缺失的 --update-feed 文件——正确的退出码(2),--check-updates 按文档所述以 10/0 退出。
已知限制:
- 应用无法附加到并非由它启动的 dsh web 服务器,因为外部服务器从不发布其 token。它会报告冲突,而不是进行猜测。
- 每个 home 一个窗口:两个项目需要两个 home(--dsh-home),而不是在一个服务器上开两个窗口。
- 更新下载通过校验和验证,而不是通过签名验证。SHA256SUMS 与二进制文件来自同一个发布版本,因此它能捕获损坏或被篡改的下载,但无法捕获被入侵的发布版本。Authenticode 签名以及在应用时进行 WinVerifyTrust 是剩余的步骤。
- 目前还没有自动化单元测试套件;CI 会构建、检查版本方案并对命令行进行冒烟测试,而上述手动检查是人工运行的。
- UI 本身在没有浏览器的情况下进行验证:插件的组件以无头方式渲染,所服务的 bundle 从实时服务器读取,但没有任何检查会在 WebView2 中驱动真实点击。在运行时无法启动的机器上,除窗口之外的一切都会运行。
路线图
- [x] 无终端启动,使用隐藏的子进程
- [x] 项目范围的窗口
- [x] 由操作系统分配端口并发现就绪行
- [x] 显示前验证端点
- [x] Job 对象关闭保证
- [x] 每个 home 一个服务器并支持附加
- [x] 持久化设置和项目选择器
- [x] 日志轮转和保留限制
- [x] 单实例窗口,重新启动时聚焦
- [x] 托盘图标和“打开日志”菜单
- [x] Harness 版本显示,并提供可选的应内更新
- [x] 桌面应用自身的更新检查,带应用内提醒和缓存答案
- [x] 已验证自更新:下载、SHA-256 校验、分阶段应用、回滚、重启
- [ ] 发布版本的 Authenticode 签名,在替换前进行验证
- [ ] 针对选项、租约验证和端点探测的单元测试
- [ ] GitHub Actions 构建和发布工作流
剩余事项的详细游戏计划——设计、验收标准、风险和里程碑——见 ROADMAP.md。
安全
- 该应用仅与回环测试服务器通信;测试数据保存在 DSH_HOME 下的本地文件中。
- 测试访问令牌通过 URL 传递给嵌入式浏览器,且绝不会被应用记录到日志中。
- 该应用不执行任何遥测。其出站请求包括可选的 npm 更新、npm dist-tag 读取以及 GitHub 发布检查——所有这些都可以通过 --no-update-check 禁用(npm 更新通过 --update 保持选择加入)。
- 更新检测读取公开的发布元数据。 未经明确操作,不会下载或替换任何内容,并且托盘菜单、更新窗口和 --no-update-check 都可以让应用保持安静。
- 下载内容经过验证。 除非桌面应用更新的 SHA-256 与发布版本的 SHA256SUMS 匹配,否则会被拒绝;不匹配时会删除下载内容,而在没有已发布校验和的情况下安装任何内容都需要明确确认并说明这一点。SHA256SUMS 与二进制文件来自同一位置,因此它能检测传输过程中的损坏和篡改,但不能检测发布版本本身被入侵——Authenticode 签名是剩余的步骤(见 ROADMAP.md)。
- 正在运行的可执行文件绝不会被就地替换。 一个独立的辅助程序会等待应用退出,在新构建启动之前保留旧构建,并在新构建失败时恢复旧构建。
- --update 会修改全局 @deepseek-ai/dsh 安装;请谨慎使用。
- 请通过 GitHub 的私密安全咨询流程报告敏感问题,而不是公开 issue。
贡献
保持更改聚焦,并说明用户可见的影响。错误报告最有用的内容包括复现步骤、所使用的确切标志、相关的 server-.out.log 摘录以及 --self-test 输出。
许可证和署名
根据 MIT License 授权。
本项目是 ZeroHackz/deepseek-harness-windows-native 的衍生作品;原始 MIT 声明已保留。此处的生命周期模型围绕操作系统分配的端口、经过验证的就绪行、按 home 归属以及关闭时终止的作业对象进行了重建。
DeepSeek Harness 本身由 DeepSeek 开发。此应用是一个独立包装器:它与 DeepSeek 无关联,也未获得其认可,DeepSeek 徽标仅用于标识所包装的应用程序。
一个可靠的本地 DeepSeek Harness 桌面外壳:双击、工作、关闭。*