Bundle
dsh-gui-trash
Desktop (Electron) GUI daemon for DeepSeek Harness: a Cordis host plugin plus a command-line launcher wrapping the existing dsh web UI.
- Source
- Kimoiran
- stars
- 1 stars
- License
- MIT
- Updated
- Updated yesterday
Readme
# dsh-gui-trash
一个笨蛋用dsh自己做了个GUi,其实按理来讲就是electron套壳
**你不能指望一个笨蛋能写出什么好东西**
但是考虑到我取名都叫trash了,我写得多烂你都不应该骂我,~~难道你没有心理准备吗~~
~~哦对了,应该只有Windows能用?我没在其它地方测试过~~
DeepSeek Harness 的桌面 GUI:把 `dsh web` 的界面装进一个原生窗口(Electron)
⚠️⚠️⚠️AI领域神人警告⚠️⚠️⚠️

## 快速开始
~~哦对了,其实我根本没怎么测试~~
### 0. 前提
- 装了 **Node.js ≥ 22** 和 **pnpm**。
- harness 源码放在 `dsh-gui-trash` 的**上一级目录**
- ~~如果在不往harness里装载插件的情况下使用的话是需要的~~
```
dsh
├── deepseek-harness\ ← harness(提供 WebUI)
└── dsh-gui-trash\ ← 本插件
```
### 1. 两步启动(源码,最简单)
```powershell
cd E:\dsh\dsh-gui-trash
pnpm install # ① 装依赖(首次下载 Electron,约 100MB)
pnpm dsh-gui-trash # ② 启动
```
就这两步:它会**自动**找到 `deepseek-harness` → 拉起 `dsh web` → 弹出桌面窗口。**你不需要先手动开 WebUI。**
如果想要装载到harness的话(当然我用的是源码)
```
pnpm dsh plugin --profile web add -w ..\dsh-gui-trash
挂载 + 启动
pnpm dsh web --patch ..\dsh-gui-trash\cordis.patch.yml
```
在插件里它是这个样子
(它会拉起窗口,如果不想每次都拉起的话,最好记得disable,哦是的,~~如果纯插件的话你需要先开web再开GUI~~,如果使用命令行启动或者打包成exe或许就没这个顾虑了)

### 2. 常见问题
~~其实是我猪鼻导致的一些幽默问题~~
| 现象 | 处理 |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `pnpm install` 报证书错误 / 卡在下载 Electron | 用镜像~~(什么你问我去哪找)~~ |
| 启动后窗口一直连不上 | 打开`%USERPROFILE%\.dsh\desktop\config.json`,把 `launchCommand` 改成能拉起你 harness 的命令 |
| 想彻底停掉 | 关窗口即可(它拉起的 harness 一起关);或装成插件后用`/dsh-gui-trash disable` |
| `/dsh-gui-trash` 提示"未找到 Electron" | 迁移目录/新环境后 node_modules 丢了:回`dsh-gui-trash` 目录再跑一次 `pnpm install`<br />~~这个是因为我原目录是有空格的,目前似乎不太支持~~ |
| 每次启动web端都会自动拉起GUI | 我写的大份的逻辑就是:enable就会拉起GUI,哦我的朋友~~这不是bug这是特性~~ |
| 打包 exe 报`Cannot create symbolic link` | Windows 没开开发者模式:`start ms-settings:developers` 打开"开发者模式",或改用管理员身份运行终端再 `pnpm run build:exe` |
> 想更精细地控制(在 dsh 里启停/删除、打包 exe、开机自启),看下面"三种使用方式"。
## 三种使用方式
它有三种启动方式,最终都启动**同一个 Electron 守护**(`electron/main.js`),区别只是"怎么把它拉起来":
| 方式 | 命令 | 适用场景 | 前置条件 |
| --------- | ----------------------------------------------- | ----------------------------- | ---------------------------------- |
| ① 插件 | 装进 harness,用`/dsh-gui-trash` 命令 | 想在 dsh 里统一启用/停用/删除 | `dsh plugin add` + 挂载行 |
| ② 命令行 | `pnpm dsh-gui-trash` 或 `npx dsh-gui-trash` | 开发 / 临时启动 | electron(作为依赖) |
| ③ exe | 双击`dsh-gui-trash.exe` | 双击即用 | 先在插件目录`pnpm run build:exe` |
三种方式的行为**完全一致**:Web-UI 已在运行 → 附着开窗;没在运行 → 拉起 `dsh web` 并开窗;之后每 ~3s 探活、掉线自动拉起(守护);关窗即退出;最小化到任务栏;无托盘。
---
## 方式一:作为插件装进 harness
装进 harness 后,它成为 dsh 的宿主插件,可在 dsh 内统一控制。
```sh
cd deepseek-harness
pnpm dsh plugin --profile web add -w ../dsh-gui-trash # 源码:pnpm dsh;-w 因 profile 是 pnpm workspace 根;发布后:dsh plugin --profile web add -w dsh-gui-trash
pnpm dsh web # cordis.patch.yml 由 dsh.bundle 自动应用,无需再 --patch
```
> 源码环境是 `pnpm dsh`,npm/npx 安装后才直接是 `dsh`。本包声明了 `dsh.bundle`(见 `package.json`),`add` 会把它追加进 profile 的 `dsh.profile.bundles`,`cordis.patch.yml` 随之自动生效——不再有 "declares no dsh.bundle" 警告,也无需手动 `--patch`。
>
> ⚠️ **`dsh plugin add` 的坑**:如果 `dsh-gui-trash` 路径含空格(如 `C:\Program Files\...`),命令会被 shell 劈成两段装错。务必用**无空格路径**(如 `E:\dsh\...`)。若已装坏,手动打开 `$DSH_HOME\profiles\web\package.json`,把 `dependencies` 改成 `"dsh-gui-trash": "link:E:/dsh/dsh-gui-trash"`(正斜杠),再在 profile 目录 `pnpm install`。 不过我建议最好一开始就下在没有空格的路径里,虽然不知道这是不是bug
>
> 🔄 **插件会持久保留,重启不丢**:插件被写进 profile 的 `package.json`(`dependencies` 的 `link:...` + `dsh.profile.bundles` 挂载层),关掉 `dsh web`、甚至重启电脑都不会消失;只有 `dsh plugin remove` 才会同时移除依赖和挂载层。
>
> 📦 **挂载层已自动持久**:因为声明了 `dsh.bundle`,`add` 时挂载层就写进 profile 的 `dsh.profile.bundles`,之后每次 `pnpm dsh web` 都自动带上,无需再手动 `--patch` 或编辑 `cordis.patch.yml`。
挂载后,聊天框 `/` 菜单里多出 `dsh-gui-trash` 命令:
| 操作 | 命令 |
| -------- | ------------------------------------------------------------------------------------------------------ |
| 启用 | `/dsh-gui-trash enable` |
| 停用 | `/dsh-gui-trash disable` |
| 查看状态 | `/dsh-gui-trash status` |
| 立即启动 | `/dsh-gui-trash launch`(或 `/dsh-gui-trash`) |
| 删除插件 | `dsh plugin --profile web remove dsh-gui-trash` + 移除组合行;可选删 `%USERPROFILE%\.dsh\desktop\` |
- **启用**:`enabled=true` 写入 config.json,Electron 守护被拉起。
- **停用**:`enabled=false`,守护被杀;此后 `npx dsh-gui-trash` 与 exe 都会因读到 `false` 而**拒绝启动**。
- **删除**:`dsh plugin remove` 移除包;插件 `dispose()` 杀掉它拉起的守护进程。
> 注意:插件挂载后 `enabled` 默认 `true`,所以 `dsh web` 启动时(含插件)会自动弹窗。想关掉自动弹窗,用 `/dsh-gui-trash disable`(该状态会写进 config.json 持久保存,之后重开不再自动弹)。
---
## 方式二:命令行启动
npx 与 pnpm 的区别
两者最终都启动同一个守护,区别在于"从哪找到并启动 Electron":
```sh
# 源码 / 开发态
cd dsh-gui-trash
pnpm install
pnpm dsh-gui-trash
# 安装后
npx dsh-gui-trash
```
- **`pnpm dsh-gui-trash`**:`pnpm` 是**包管理器**。这条命令执行的是 `package.json` 里 `scripts.dsh-gui-trash` 定义的脚本(内容 `electron electron/`)。它要求你当前在 `dsh-gui-trash` 源码仓库里、且已 `pnpm install`(electron 在 node_modules)。用于**源码开发/调试**。
- **`npx dsh-gui-trash`**:`npx` 是 Node 自带的**"运行某包命令"**工具。它按 `package.json` 的 `bin` 字段找到入口 `bin/dsh-gui-trash.js` 并执行;包已安装就用本地的,没有就临时下载。因为 `electron` 声明在 `dependencies`,会一并就位。用于**安装后**的场景。
一句话:**`pnpm` 走的是"仓库里的开发脚本",`npx` 走的是"包发布的命令行入口"。**
---
## 方式三:打包 exe(可选)
注:目前不保证能够正常运行,我还是建议在trash目录使用pnpm dsh-gui-trash,或者写个脚本什么的,exe目前不太稳定,后续我可能会改(如果我能想起来的话)
```sh
cd dsh-gui-trash
pnpm install
pnpm run build:exe # electron-builder → dist/dsh-gui-trash.exe
```
- **原理**:electron-builder 把 **Electron 运行时 + electron/main.js** 打成一个 portable exe。它"自包含"的只是 **Electron 运行时**(运行 GUI 窗口不需要 node/electron/pnpm);但**不含 harness**——仍需一份可用的 `dsh`(源码 checkout 或已安装的 `dsh web`)来提供实际 WebUI 与 AI 功能。exe 能做的是:没运行时替你 `spawn` 起 harness,但它自己不"是" harness。
- **价值**:双击即用;可放进 Windows 开机自启(`Win+R` → `shell:startup`,把 exe 快捷方式放进去)。
- **可选**:不打 exe 也有全部功能(方式一、二照常)。
- **代价**:exe 体积 ~100MB+(就是 Electron 运行时本身);electron-builder 首次运行要下载打包工具链,国内可用镜像 `electron_builder_binaries_mirror=https://npmmirror.com/mirrors/electron-builder-binaries/`。
- **坑**:Windows 打包报 `Cannot create symbolic link` 是没开"开发者模式"(electron-builder 解压 winCodeSign 时含 macOS 符号链接)——`start ms-settings:developers` 打开开发者模式,或用管理员终端重跑。产物在 `dist\dsh-gui-trash.exe`(portable 单文件)。
---
## 与 DeepSeek Harness 的关系(原理)
`dsh-gui-trash` 与 `dsh` 是两个平级、互不知情的进程,唯一联系是 HTTP:
- `dsh web` 照常运行,把前端界面与 `/api` 服务在 `http://127.0.0.1:<port>` 上(Electron 窗口就是一个 Chromium 浏览器,加载的正是这个地址)。
- `dsh-gui-trash` 负责:探测该端口 → 没跑就按 `launchCommand` 拉起 `dsh web` → 开窗并守护它。
所以运行只需两样:① `dsh` 可用(源码 checkout 用 `pnpm dsh web`,或 npm 安装后 PATH 有 `dsh`);② `dsh-gui-trash` 有 Electron。不需要改 harness 源码、不需要 `cordis.patch.yml`(方式二、三)、不需要 `dsh plugin add`(方式二、三)。
## 配置
`$DSH_HOME/desktop/config.json`(Windows 默认 `%USERPROFILE%\.dsh\desktop\config.json`),首次运行自动生成:
```json
{
"enabled": true,
"port": 3080,
"launchMode": "source",
"launchRoot": "不管你在哪\\deepseek-harness",
"launchCommand": "pnpm dsh web"
}
```
| 字段 | 含义 |
| ----------------- | ---------------------------------------------------------------- |
| `enabled` | 总开关,`false` 时一切 GUI 入口拒绝启动 |
| `port` | 探测/连接`dsh web` 的端口 |
| `launchMode` | `source`(源码 checkout)/ `installed`(npm 安装)/ 留空自动 |
| `launchRoot` | source 模式下 harness checkout 根目录 |
| `launchCommand` | 拉起 dsh 的命令(`pnpm dsh web` 或 `dsh web`) |
## 如何找到 harness(查找优先级)
启动时按这个顺序决定"从哪拉起 `dsh web`":
1. **默认:自动探测兄弟文件夹**。独立模式(方式二 / 三)扫描**本插件上一级目录**里带 `pnpm-workspace.yaml` 的兄弟 checkout,例如:
```
E:\dsh
├── deepseek-harness\ ← 自动找到这里
└── dsh-gui-trash\ ← 本插件
```
找到就自动写回 `config.json`(`launchMode: source` + 正确的 `launchRoot` + `pnpm dsh web`)。插件模式同理:跑在 dsh 进程里,从 `process.argv[1]` 向上找。
2. **自愈**:如果 `config.json` 里的 `launchRoot` 已经失效——搬家了、原目录只剩 `.git`、或路径带空格——下次启动会**自动重新探测并纠正**,不用手动改。
3. **都找不到 → 自己改**:harness 既不是兄弟目录、也没装成全局 `dsh`,就在 `config.json` 手写 `launchCommand` + `launchRoot`(绝对路径):
```json
{
"launchMode": "source",
"launchRoot": "D:\\wherever\\deepseek-harness",
"launchCommand": "pnpm dsh web"
}
```
手写的 `launchCommand` 优先;`launchMode` 为 `installed` 或留空时,不会用自动探测覆盖你的手写值。
## 端口约定(重要)
exe / 守护用 config.json 的 `port` 探测 `dsh web`。手动 `dsh web --port 8080` 会被判为"未运行"并另起一个 3080 实例。解决:两者端口一致。暂不支持随机端口自动发现。
~~其实是不会写~~
## 目录结构
```
dsh-gui-trash/
├── package.json # name + bin + scripts + deps(electron → dependencies)
├── lib/index.js # Cordis 宿主插件(ESM)
├── bin/dsh-gui-trash.js # npx 命令行入口(ESM)
├── electron/
│ ├── package.json # 嵌套 CJS 入口(electron-builder 用)
│ ├── main.js # Electron 守护主进程(CJS)
│ └── preload.js # 标题栏:拖拽条 + 主题上报(CJS)
├── electron-builder.yml # 可选 exe 打包
├── cordis.patch.yml # 挂进 harness 的组合行
└── README.md
```
Install
dsh plugin --profile web add github:Kimoiran/dsh-gui-trash
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-gui-trash from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.