Web application bundle for the desktop version of DeepSeek Harness.
ⓘ This plugin is a sub-package of the WJZ-P/deepseek-harness-desktop monorepo — stars and activity count the whole repository.
- Language
- TypeScript
- License
- MIT
- Branch
- main
Install
$ dsh plugin --profile web add @deepseek-ai/dsh-web-appRun the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial
Install via your agent
Install the DeepSeek Harness plugin WJZ-P/deepseek-harness-desktop/harness/packages/bundle/web-app for me: review the repository at https://github.com/WJZ-P/deepseek-harness-desktop first, then run the install command and verify the plugin loads successfully.
Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.
一句话定位
这是 DSH 的"浏览器表层"profile bundle:把 dsh-base 之上的 Web 界面(HTTP 服务 + 前端 dist + 浏览器侧插件名单 + 命令行参数 + 模型可见的 web-surface 提示词)一次性组装起来,让 dsh --profile web 一条命令就能在浏览器里跑出完整的 Harness GUI。
核心能力
- 启动 Web GUI:安装后用
dsh --profile web启动一个监听本地端口的 HTTP 服务,把前端 dist 通过frontend-static兜底席位喂给浏览器 - 解析命令行参数:自带 commander 命令,支持
--host/--port/ 可重复的--trusted-host与--help - 拼装浏览器插件名单:在 patch 里一次性挂载约 30 个客户端插件(布局、侧栏、对话、工具、规划、子代理、技能、模型选择、目标、轨迹、主题、设置等)以及它们的 node 端宿主行
- 暴露 /api 信任栅栏:把 LAN IPv4 字面量与
--trusted-host参数拼成 trustedHosts 列表,交给浏览器 fetch/SSE 客户端作为反 DNS-rebinding 边界 - 注册模型可见的 Web 上下文:向系统提示词注入
harness:source和app:web-surface两段,并向受管 bash 环境注入DSH_WEB_URL变量,让模型知道"this page 指的是这个 GUI" - 打印就绪 URL:boot 完成后在控制台打印
dsh web: http://127.0.0.1:<port>(必要时附带 LAN 地址) - 关闭 agent 平面的工具行:把 base 里默认挂在 host 平面的工具(bash、文件、子代理、工作流等)整体关掉,让每个 session 通过 agent-preset 自己挂,避免重复注册
技术实现
- 语言: TypeScript(ESM,
"type": "module") - 关键依赖:
commander(命令行解析)、@deepseek-ai/cordis(插件运行时)、@deepseek-ai/schemastery(config schema 校验)、@deepseek-ai/dsh-app-boot(注册 harness-source 提示词段) - 架构模式: Cordis profile bundle —— 包根目录
cordis.patch.yml在package.json#dsh.bundle.patch声明,作为dsh --profile web的 patch 层叠加在dsh-base之上;运行时由一个 function 插件(src/index.ts,导出name/inject/Config/apply,无默认导出)和一个命令解析插件(src/startup.ts,导出webStartup服务)组成 - 入口文件:
src/index.ts(web-runtime 粘合插件)、src/startup.ts(命令行 provider)、cordis.patch.yml(patch 层)、src/invariant.ts(invariant companion)
适用场景
本 bundle 是给"想用浏览器而不是终端交互 DSH"的人准备的:装上之后 dsh --profile web 一行命令就能在 127.0.0.1 启起一个完整的 Harness GUI,适合团队 demo、内网共享、或在桌面端长跑一个持久会话的场景。它和 dsh-headless 互斥——headless 是一次性 CLI 任务模式,本 bundle 是带 Web 表层的常驻模式,两者都基于同一个 dsh-base。
前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DSH | 0.1.0-rc.5+ | 本 bundle 版本 0.1.0-rc.5;必须叠加在 dsh-base 之上,不能单独挂载 |
| Node.js | >=22.19.0 或 >=24.0.0 | 来自仓库根 package.json#engines(Harness 整体要求) |
| 平台 | 跨平台 | 本 bundle 未声明平台限制;Windows 上需注意 dsh-base 里 bash 栈是 disabled、pwsh 栈启用 |
| 原生模块 | 无 | 本 bundle 自身不引入原生模块;底层 sqlite 走 :memory:,不依赖本地库 |
启动前必须先构建前端 dist,否则激活时会以 "frontend dist not built; run pnpm run build from the repository root first" 报错。
安装方式
dsh plugin --profile web add github:WJZ-P/deepseek-harness-desktop/harness/packages/bundle/web-app
配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
printUrl | 布尔 | 启动就绪后是否在控制台打印 dsh web: http://... URL 行(附带 LAN 地址),用于脚本与监控判定服务可用 | true |
surfaceContext | 布尔 | 是否向系统提示词注入 app:web-surface 段(说明"this page 指的是这个 GUI")以及向受管 bash 环境注入 DSH_WEB_URL 变量 | true |
trustedHosts | 字符串数组 | 浏览器 /api 信任栅栏接受的额外 Host 或 host:port 字面量(防 DNS rebinding),按命令行 --trusted-host 出现顺序累加 | [] |
--host <host>(CLI) | 字符串 | webserver 绑定地址;写 0.0.0.0 会被 CLI 主动拒绝 | 127.0.0.1 |
--port <port>(CLI) | 数字 | webserver 监听端口;写 0 让 OS 分配空闲端口;非数字会报 usage 错误 | 3080 |
--trusted-host <authority...>(CLI) | 字符串数组 | 重复追加信任栅栏接受的主机字面量(host 或 host:port),最终并入 trustedHosts 配置 | 无 |
DSH_TOOLS_MODE(环境变量) | native | code | both | 临时开关:把整个 dsh 进程切换到 Code Mode;待 Web UI 上线"按会话选工具展示"后会移除 | 未设置(沿用 schema 默认 native) |
常见问题
Q: 启动时怎么指定端口和绑定地址?
A: 用命令行参数 --port 和 --host,例如 dsh --profile web --port 8080;不指定时使用 schema 默认(127.0.0.1:3080)。
Q: 启动报 "frontend dist not built" 怎么办?
A: 在仓库根目录先跑 pnpm run build 编出前端 dist;本 bundle 直接 require.resolve('@deepseek-ai/dsh-web-frontend/dist/index.html'),找不到就报错并提示这条命令,没有从源码临时服务的兜底。
Q: 局域网里别的设备怎么访问这个 GUI?
A: 当前 CLI 主动拒绝 --host 0.0.0.0,因为会把远程代码执行暴露到网络(见 src/startup.ts:69-71)。需要内网访问建议在 127.0.0.1 上跑本 bundle,外面套反向代理并把代理用的主机名通过 --trusted-host 加入信任栅栏。
Q: --trusted-host 是做什么的?什么时候必须加?
A: 它把额外的 Host / host:port 加入浏览器到 /api 的信任栅栏,防 DNS rebinding。当浏览器用非 127.0.0.1 的 Host header 访问(比如反向代理、自定义 hostname、端口映射)时必须配置;可重复,按书写顺序追加。
Q: 控制台打印的 dsh web: http://127.0.0.1:3080 后面的 LAN 地址是怎么来的?
A: 当且仅当 webserver bind 到 0.0.0.0 时,bundle 会在 boot 那一刻用 node:os 的 networkInterfaces() 采样一次非内部 IPv4 字面量,挑第一个拼到 URL 行后面。但 --host 0.0.0.0 当前被 CLI 拒绝,所以这条分支在默认配置下走不到。
Q: 模型在 bash 工具里看到的 DSH_WEB_URL 是什么?
A: 这是 bundle 在 surfaceContext=true 时向受管 shell 环境注册的变量,存当前会话对应的 GUI 本地 URL,让 bash 工具知道"this page 指的是这个 GUI"。关掉 surfaceContext 之后模型既看不到 app:web-surface 提示词段,也读不到这个变量。
Q: 怎么关掉启动时打印的 URL 行?
A: 在你的 cordis.patch.yml 里把 web-runtime row 的 printUrl 设为 false,或在非交互脚本里直接覆盖该 row。这是给"批处理 + 健康检查"用的关停开关,URL 仍然可以从 webServer 服务读到。
Q: 怎么从 profile 移除这个 bundle?
A: 在 profile 的 dsh.profile.bundles 列表里删掉 web-app 条目即可。注意 dsh-base 假设 web-app 在其之上叠加,单独拆掉 web-app 会让 base 里 host 平面的 agent 工具回到默认状态(bash / 文件 / 子代理等会重新挂到 host),需要的话用你自己的 patch 把它们显式 disabled。
上手难度
入门 — 命令就是 dsh --profile web,最多再加一个 --port;安装后只需确保 pnpm run build 已跑过一次前端 dist,剩下的事 patch 全包办了。
已知问题与限制
- 前端 dist 必须先构建:激活时通过
require.resolve拿 dist,找不到会立即报错并提示pnpm run build from the repository root first;没有从源码临时服务的兜底(README Known Limitations) - LAN 地址是 boot 期快照:bundle 在
apply时采样一次networkInterfaces();启动后网卡变化不会重新公告,打印的 LAN URL 始终等于 boot 期信任栅栏(README Known Limitations) - HMR 当前禁用:
cordis.patch.yml:21-23的 TODO 标注"Re-enable shared HMR for Web after its reload lifecycle is tested",目前hmrrow 处于disabled: true,改客户端插件不会触发无刷新热更新 DSH_TOOLS_MODE是临时整进程开关:cordis.patch.yml:38-42的注释明确写"TEMPORARY workaround",用于在 Web UI 尚未提供"按会话选工具展示"能力前通过环境变量强制 Code Mode;待 UI 上线后移除--host 0.0.0.0被主动拒绝:源码注释说"intentionally not supported yet for safety: it would expose remote code execution to the network",内网/局域网暴露请走反向代理 +--trusted-host
🐋 DeepSeek Harness Desktop
把完整 DeepSeek Harness 装进轻巧的 Tauri 桌面壳。
不捆绑 Chromium,不另造业务内核,解压即可使用 ฅ( ̳• ·̫ • ̳ฅ)
下载最新版本 · 架构说明 · Harness 上游记录
📦 下载与使用
前往 GitHub Releases,选择与你的平台对应的文件:
| 平台 | 发行格式 | 使用方式 |
|---|---|---|
| Windows x64 | Portable ZIP | 解压后双击 DeepSeek Harness.exe |
| Linux x64 | AppImage | 添加执行权限后直接运行 |
| Debian / Ubuntu x64 | DEB | 使用系统包管理器安装 |
| macOS Apple Silicon | DMG | 适用于 M 系列芯片 |
| macOS Intel | DMG | 适用于 Intel 芯片 |
[!TIP] 资源就在身边啦 (。•̀ᴗ-)✧ Windows portable ZIP 内已经放入展开后的
runtime/harness/。把整个 ZIP 解压一次后,应用会直接读取 EXE 旁边的运行时,不再二次解压,也不会复制一份到 AppData;源码入口、前端资源与生产依赖都能在当前文件夹中直接找到。
Windows 便携版无需另外安装 Node.js,也无需准备 Harness 源码目录。请保持 DeepSeek Harness.exe 与 runtime/ 在同一个目录中。
[!NOTE] 当前发行包没有商业代码签名或 Apple notarization。Windows SmartScreen 或 macOS“隐私与安全”可能要求用户额外确认。
✨ 为什么是这个桌面端
| 特性 | 实现 |
|---|---|
| 🪶 轻量 | 使用系统 WebView;Windows 是 WebView2,macOS 是 WKWebView,Linux 是 WebKitGTK,不随应用捆绑 Chromium。 |
| 🧩 能力完整 | 继续使用 Harness 的 Agent、会话、工具、插件、Typert RPC 与 Cordis profile,没有第二套业务内核。 |
| 📦 真正便携 | 各平台发行包内置匹配平台的 Node.js 与完整生产运行时,用户不需要手动配置开发环境。 |
| 🐋 启动有反馈 | 启动页按“读取便携运行时 → 启动本地服务 → 载入工作区”展示真实阶段,不用再等待 AppData 解压。 |
| 🎨 原生体验 | 32px 自绘标题栏、深浅主题同步、优雅的鲸鱼加载动画,并抑制后台控制台闪窗。 |
| 🖼️ 拖入附件 | 图片继续走 Harness 原生预览与历史画廊;其他文件由独立、可安装的 DSH 插件提供拖放、输入卡片、历史卡片与下载。 |
| 🔍 源码完整 | harness/ 由本仓库直接跟踪,不是 Git 子模块;普通 clone 就能获得完整源码。 |
一句话概括:Tauri 负责把窗口做得轻巧漂亮,Harness 继续负责真正的工作。 ₍^. .^₎⟆
🚀 快速开始
环境要求
- Node.js
^22.19.0 || >=24.0.0 - pnpm
- Rust stable toolchain
- Windows:Microsoft C++ Build Tools 与 WebView2
- macOS:Xcode Command Line Tools
- Linux:WebKitGTK 4.1、Ayatana AppIndicator、RSVG 与 XDO 开发包
克隆并运行
git clone https://github.com/WJZ-P/deepseek-harness-desktop.git
cd deepseek-harness-desktop
pnpm install
pnpm tauri dev
harness/ 已直接包含在仓库中,无需初始化 Git submodule。两个通用插件是独立仓库,桌面项目通过 external-plugins.json 锁定其提交,并在首次开发运行时自动准备到已忽略的 plugins/ 工作区。Tauri 的 beforeDevCommand 会依次:
- 校验 Harness 关键源码;
- 根据
harness/pnpm-lock.yaml准备依赖; - 在产物缺失或落后时构建 Harness CLI 与 Web UI;
- 获取、安装并构建锁定版本的外部插件;
- 启动 Vite,再由 Tauri 启动 Harness Host。
也可以提前执行:
pnpm run harness:prepare
pnpm run plugin:sync
Vite 开发地址固定为 http://localhost:821,HMR 使用端口 822。Harness Host 使用操作系统分配的随机回环端口,避免与其他开发软件冲突。
如果 Node.js 不在 GUI 进程可见的 PATH 中,可以用 DSH_DESKTOP_NODE 指定绝对路径;DEEPSEEK_HARNESS_ROOT 可临时指向其他 Harness checkout。
🗂️ 仓库结构
deepseek-harness-desktop/
├─ desktop-plugins/ # 仅由桌面封装携带的 Cordis 集成
├─ docs/assets/ # README Banner 等项目图片
├─ external-plugins.json # 外部插件仓库与提交锁
├─ harness/ # 本仓库直接跟踪的完整 DeepSeek Harness 源码
├─ plugins/ # 本地外部插件 checkout;整个目录由父仓库忽略
├─ scripts/ # Harness 准备、发行构建与验证脚本
├─ src/ # 桌面外壳、自绘标题栏与启动/错误页
├─ src-tauri/ # Rust 窗口、便携运行时定位与进程监督器
├─ app-icon.svg # 应用图标源文件
└─ package.json
上游地址、导入提交与许可证记录见 HARNESS_UPSTREAM.md。
🧩 低侵入插件边界
桌面专属桥与桌面预装的通用插件都没有继续散落进 harness/ 业务包,而是通过启动时的 Cordis --patch 覆盖层装入。可复用插件各自拥有独立仓库、锁文件、CI 与发布边界;桌面仓库只记录来源和精确提交:
desktop-bridge:在 Host 返回 HTML 时注入深浅主题同步桥,并为显式file://开发挂载保留dsh.client兼容适配;桌面预装的标准插件会同时进入运行时的包解析面,并以各自package.json包名挂载,因此插件清单展示稳定名称、浏览器 bundle 使用 Harness 官方/plugins发现链路,公开插件无需携带 Tauri 分支;dsh-attachment:标准 DSH bundle,同时声明dsh.bundle与 Webdsh.client,既可由桌面封装携带,也可通过dsh plugin --profile web add dsh-attachment从 npm 安装到原生 DSH;它沿用 Harness 已有的图片拖放/粘贴链路,只接管普通文件与文件夹。拖入一个文件夹只生成一个附件卡片,并以完整目录树的形式复制到工作区;同时提供流式上传/下载、输入区附件卡片与持久历史卡片。插件本身不设置文件数量或单文件字节上限,也不额外占用输入栏按钮;dsh-model-capability:标准 DSH bundle;在新增或编辑 pi-ai 模型时提供 Input Modalities 选择,可明确声明继承默认值、文本、图片或文本加图片,并可通过dsh plugin --profile web add dsh-model-capability从 npm 独立安装到原生 DSH;- 普通文件会保存到 Harness 数据目录,并在消息真正进入模型步骤前复制到工作区
.deepseek-harness/attachments/,模型拿到的是可直接读取的工作区路径; harness/内只保留通用的 输入附件栏 slot 与 模型行字段 slot;浏览器 bundle 直接使用 Harness 官方dsh.client发现链路,具体 UI、存储和消息关联逻辑留在独立插件仓库与desktop-plugins/。以后同步上游时,冲突面依旧很小喵~
🧭 架构
flowchart LR
A["Tauri desktop process"] -->|"spawn and supervise"| B["Harness CLI / lib/bin.js"]
B --> C["Cordis web profile"]
C --> D["Host API and session log"]
C --> E["Harness client plugin graph"]
H["Desktop Cordis plugins"] -->|"runtime --patch"| C
H -->|"standard dsh.client bundle"| E
A -->|"mount after readiness"| F["Persistent desktop shell"]
E --> G["Harness iframe"]
F --> G
G -->|"HTTP POST and WebSocket"| C
- 开发模式直接从
harness/apps/cli/lib/bin.js启动。 - 发行模式直接从应用资源目录的
runtime/harness/执行lib/bin.js web --patch <desktop-overlay> --host 127.0.0.1 --port 0,不创建 AppData 运行时副本。 - Rust 进程读取
dsh web:就绪行,仅接受127.0.0.1随机端口,再交给桌面 WebView 加载。 - WebView 继续复用现有 Host fence、
/api传输和两条 WebSocket 下行流。 - 关闭窗口或应用时,桌面层会回收整个 Node 子进程树。
- 启动页跟随系统深浅主题;Harness 载入后,通过受控主题桥实时跟随应用内 Appearance 设置。
更完整的设计说明见 ARCHITECTURE.md。
🛠️ 常用命令
| 命令 | 用途 |
|---|---|
pnpm tauri dev | 启动 Harness 与 Tauri 开发环境 |
pnpm run harness:prepare | 校验、安装并按需构建 Harness |
pnpm run plugin:sync | 按 external-plugins.json 准备外部插件 checkout 与依赖 |
pnpm run plugin:test | 构建并测试桌面桥及锁定版本的外部插件 |
pnpm run check | 校验 Harness 源码完整性、TypeScript 与 Rust |
pnpm run build:frontend | 只构建桌面启动外壳,不生成原生发行包 |
pnpm run build | 构建当前平台的完整自包含发行包 |
pnpm run test:release | 在 Windows 上真实启动并冒烟测试 portable ZIP |
pnpm run verify:release-artifacts | 校验平台产物及 SHA-256 |
🏗️ 构建发行包
请在目标操作系统的原生环境中运行:
pnpm install
pnpm run build
pnpm run verify:release-artifacts
构建流程会依次准备 Harness、同步并构建锁定提交的外部插件、生成并校验生产依赖闭包、内置当前平台 Node.js、执行随机回环端口 HTTP 冒烟,再把展开后的生产运行时作为 Tauri resource 编译并打包。Windows portable ZIP 中会保留可直接浏览的 runtime/harness/ 原始目录结构。
| 平台 | Release 资产命名 |
|---|---|
| Windows x64 | DeepSeek-Harness-Desktop-<version>-windows-x64-portable.zip |
| Linux x64 | DeepSeek-Harness-Desktop-<version>-linux-x64.AppImage、.deb |
| macOS Apple Silicon | DeepSeek-Harness-Desktop-<version>-macos-arm64.dmg |
| macOS Intel | DeepSeek-Harness-Desktop-<version>-macos-x64.dmg |
每个资产都会附带独立的 .sha256 文件。Linux 与 macOS 的 Node/Harness 目录作为 Tauri resource 放入原生包;Windows 则使用无需安装的 portable ZIP,并从 EXE 相邻目录直接启动运行时。
Windows 的完整便携版冒烟测试会确认展开目录直启、没有新增 AppData 运行时副本、内置 Node、主题桥、附件浏览器插件、随机回环 HTTP、WebView 连接与进程树回收:
pnpm run test:release
🤖 GitHub Actions 发布
.github/workflows/release.yml 会在推送 v* tag 时并行使用 Windows x64、Ubuntu 22.04 x64、macOS arm64 与 macOS Intel runner。
流水线会先验证 tag、package.json、Tauri 配置和 Cargo 版本一致,再构建并验证所有平台产物;只有矩阵任务全部成功后,publish job 才会一次性更新 GitHub Release。
- Release 显示名称直接使用 tag,例如
v1.0.1; - 已存在的同名 Release 会覆盖旧资产;
- 构建不需要额外密钥,发布权限来自仓库的
GITHUB_TOKEN; - 单个平台构建最长运行 90 分钟。
正式版本确认可用后,再创建与应用版本一致的 v* tag。稳稳发布,一次成功 (๑•̀ㅂ•́)و✧
🌱 更新 Harness
harness/ 是从明确上游提交导入的源码快照。更新时应整体导入一个确认过的上游提交,并在同一改动中更新 HARNESS_UPSTREAM.md 的提交号。
harness/ 保持普通 Git 文件;node_modules/、Harness 的 lib/ / dist/、desktop-plugins/*/lib/ 以及整个本地 plugins/ 工作区都在忽略范围内。公共插件的变更应提交到各自仓库,再同步更新 external-plugins.json 的提交锁。
更新后至少运行:
pnpm run harness:prepare
pnpm run build:frontend
cargo test --manifest-path src-tauri/Cargo.toml
cargo check --manifest-path src-tauri/Cargo.toml
pnpm run build
pnpm run test:release
提交或推送前,还可以单独确认关键 Harness 文件确实由 desktop 仓库跟踪:
pnpm run harness:verify-source
该检查会拒绝 160000 gitlink、缺失的关键源文件或明显不完整的源码树;pnpm run check 也会自动执行它。
🎨 主题与图标
- 图标源文件:
app-icon.svg - Tauri 平台图标:
src-tauri/icons/ - 浅色鲸鱼:
src/assets/whale-icon-light.svg - 深色鲸鱼:
src/assets/whale-icon-dark.svg
深色鲸鱼使用 --dsw-alias-label-primary,回退值为 #F9FAFB / rgb(249, 250, 251)。更新图标源文件后可以重新生成平台图标:
pnpm tauri icon app-icon.svg
📄 源码与分发边界
- 源码仓库保留完整
harness/,供审计、本地开发与二次构建; - Release 资产携带从仓库源码生成的展开式生产运行时,而不是开发依赖树;Windows 用户可以直接浏览 EXE 旁边的
runtime/harness/; - Windows 使用 portable ZIP,Linux 提供 AppImage 与 DEB,macOS 提供 ad-hoc 签名的 DMG;
- 桌面层与 Harness 上游的许可信息分别见
LICENSE和HARNESS_UPSTREAM.md。
🤝 社区支持
本项目支持 Linux Do 社区。欢迎大家前往社区交流技术、分享经验,一起友善地探索更多有趣的可能~ (。•̀ᴗ-)✧
愿这只小鲸鱼轻轻巧巧,也能把事情认真做好~
ʚ(。˃ ᵕ ˂ )ɞ
Read the usage guide →
Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.
Listing badge
[](https://deepseek-plugin.org/plugins/WJZ-P/deepseek-harness-desktop/harness/packages/bundle/web-app)Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.