# deepseek-harness-desktop

> 为 DeepSeek Harness 桌面端修补若干兼容问题：取消后队列消息不发送、停止提示显示 [object Object]、部分模型的工具调用多一层 arguments 包装。

## Metadata

- Author: [@ningbainb](https://github.com/ningbainb)
- Repo: <https://github.com/ningbainb/deepseek-harness-desktop.git>
- GitHub: [ningbainb/deepseek-harness-desktop](https://github.com/ningbainb/deepseek-harness-desktop)
- Stars: 156
- Language: TypeScript
- License: [BSD-3-Clause](https://spdx.org/licenses/BSD-3-Clause.html)
- Homepage: <https://ningbainb.github.io/deepseek-harness-desktop/>
- Topics: `ai-agent`, `ai-coding-assistant`, `codex`, `deepseek`, `deepseek-harness`, `desktop-app`, `dsh`, `dsh-plugin`, `electron`, `electron-app`, `gui`, `open-source`, `plugin-system`, `plugins`, `remote-access`, `skills`, `ssh-client`, `windows`, `windows-desktop`
- Forks: 5
- Open Issues: 6
- Last push: 2026-08-20T05:29:52.000Z
- Added: 2026-08-20T00:00:00.000Z

## Install

```bash
dsh plugin --profile web add github:ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat
```

## Wiki

## 一句话定位
为 DeepSeek Harness 桌面端修补 0.1.0-rc.7 上几处特定兼容问题——取消后排队消息不再被发送、停止提示显示成 `[object Object]`、部分模型给工具调用多套一层参数包装。它通过公开 SDK 钩子工作，不修改 DSH 源码，上游修好后即可移除。

## 核心能力
- 取消当前回复后自动续推普通排队消息：监听 agent 状态进入空闲且 inbox 仍有排队项时，通过公开的 followup 钩子重新叫醒官方 agent 驱动，保留先进先出顺序，不会复制消息
- 把工具执行的 `[object Object]` 取消展示替换成中文友好提示：当 `code run failed (abort)` 走 `tools/post-execute` 钩子时，将其替换为「当前执行已停止，排队消息将继续发送」
- 修复模型工具调用的多余 `arguments` 包装：部分适配器会把工具实参再套一层 `{"arguments":{...}}`，插件在 agent loop 解析之前按 schema 严格匹配，只在外层被拒绝、内层被接受时剥掉一层
- 在桌面端隔离 profile 里维护主题/皮肤的启用与禁用状态：自动迁移旧条目、按标记段安全写入，避免与官方皮肤中心的持久化状态互相覆盖
- 在桌面端后台自动化模式下提供任务板 Host 调度器：仅当 `DSH_DESKTOP_BACKGROUND_AUTOMATION=1` 时挂载，使用官方 agent / session / workspace 接口跑调度任务，支持崩溃后恢复会话
- 通过本地回环路由控制工作区文件本地打开：限制只能打开白名单扩展名的非脚本文件，路径必须落在已注册工作区根目录下，并用 Token 验证只接受 Electron 主进程请求

## 技术实现
- **语言**: TypeScript（target ES2022, module NodeNext, type module）
- **关键依赖**: `@deepseek-ai/dsh-agent`、`@deepseek-ai/dsh-tools`、`@deepseek-ai/dsh-llm`、`@deepseek-ai/dsh-workspace`（皆 `0.1.0-rc.7`，来自 package.json:38-44）
- **架构模式**: Cordis function plugin + cordis bundle patch；`apply(ctx)` 一次性挂 4 个补丁点（agent/status 事件、tools/post-execute 中间件、llm/stream 全局钩子、桌面文件打开路由），并按 `process.env.DSH_DESKTOP_BACKGROUND_AUTOMATION` 条件挂 Host 调度器。声明 `inject = ['llm','tools','webServer','workspaceRegistry']` 保证依赖服务先就绪
- **入口文件**: `packages/dsh-desktop-compat/src/index.ts`（apply 入口；副作用按模块分布在 `recovery.ts`、`tool-call-normalization.ts`、`skin-state.ts`、`background-scheduler-runner.ts`、`workspace-file-open-route.ts`）

## 适用场景
当你使用 DeepSeek Harness Desktop 桌面客户端 0.1.0-rc.7，遇到以下任一情况时这个插件能直接修复：取消一轮对话后排在后面的消息再也没有被自动发出、取消后工具结果框里出现 `code run failed (abort): [object Object]` 这种含糊信息、或者某些模型返回的工具调用一直因为多一层 `arguments` 包装而失败。它不引入新功能，纯做缺漏修补，所以只在你看到上述症状时才有意义。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| DeepSeek Harness 桌面端宿主 | `0.1.0-rc.7` | `dependencies` 全部锁到 `0.1.0-rc.7`（package.json:38-44）；补丁清单的 `applicableVersions` 也只列此版本 |
| Node.js | `^22.19.0 \|\| >=24.0.0` | package.json:7-9 `engines.node` |
| 桌面端隔离 profile | 必需 | README 写明「DeepSeek Harness Desktop 2.0 会在隔离的 desktop profile 中自动挂载这个 bundle」，通用 Web UI profile 不会加载它 |
| `DSH_DESKTOP_WORKSPACE_FILE_OPEN_TOKEN` 环境变量 | 桌面端运行时设置 | 仅在使用原生文件打开路由时需要；Token 长度为 43 字符 base64url，由桌面端主进程随机生成并校验（src/workspace-file-open-policy.ts:14-21） |
| `DSH_DESKTOP_BACKGROUND_AUTOMATION=1` 环境变量 | 桌面端后台自动化模式启用 | 仅当用户显式打开「最小化到托盘 / 后台自动化」时由桌面端设置；不设则跳过 Task Board Host 调度器，浏览器侧调度器继续工作 |
| 平台 | macOS / Windows / Linux | 跨平台，无原生模块依赖（Node 自带 `fs`、`crypto`、`node:http`） |

## 安装方式
```bash
dsh plugin --profile web add github:ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat
```

## 配置项
本插件无需额外配置。所有行为都是「缺漏即补」，不开放用户级 schema。

| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `DSH_DESKTOP_BACKGROUND_AUTOMATION` | 环境变量（可选） | 设为 `1` 时启用 Task Board 的桌面端 Host 调度器（仅当用户在桌面端主动打开「最小化到托盘 / 后台自动化」时才设）；不设则使用浏览器侧调度器 | 未设置 |
| `DSH_DESKTOP_WORKSPACE_FILE_OPEN_TOKEN` | 环境变量（可选） | 桌面端主进程生成的 43 字符 base64url 随机串，用于工作区文件本地打开请求的 Token 校验；仅在桌面端使用 | 由桌面端主进程随机生成 |

## 常见问题
**Q: 安装命令显示往 web profile 里装，真的能用吗？**

A: 这个包的源码确实是通过 `dsh plugin ... add github:...` 走通用 NPM bundle 通道分发（cordis.patch.yml:1-5），但 README.md:29 明确写「DeepSeek Harness Desktop 2.0 会在隔离的 desktop profile 中自动挂载这个 bundle。这个包不作为通用 Web UI 插件提供」——也就是说它在桌面端才会被实际加载，web profile 只是安装载具。如果你的桌面客户端没有自动加载，请确认客户端版本是 0.1.0-rc.7+ 且启用了隔离 desktop profile。

**Q: 用了它之后我原来的「不排队、直接发送」选项还能用吗？**

A: 能。README.md:33 明确「发送仍默认进入队列，steering 消息行为不会改变」，排队行为完全维持 DSH 原状，插件只是修补取消后那一处「不该停却停了」的问题。

**Q: 工具调用多了一层包装，所有模型都能修吗？**

A: 不能保证。它只针对 `{"arguments":{...}}` 这一种单 key 包装（src/tool-call-normalization.ts:63-66）。而且「外层通过 schema、内层也通过 schema」这种二义情况会主动放弃剥壳、保持原样（src/tool-call-normalization.ts:137-142），由 DSH 自带的 schema 校验接管。其他形状的包装层一律不处理。

**Q: 它会写日志吗？日志里会泄露我的工具参数吗？**

A: 会写诊断日志，但不会写原始参数。工具调用参数恢复会在日志里输出 outcome、reason、provider、model、tool 名、call id、来源（src/tool-call-normalization.ts:339-352），但故意不包含任何工具实参。queue 恢复失败也会写 warn（src/index.ts:46-49）。

**Q: 怎么确认它真的在我桌面端生效了？**

A: 看桌面端启动日志里有没有出现 `dsh-desktop-compat:` 前缀的输出（任何补丁命中都会留痕），或者在调试环境 `pnpm --filter @linxin666/dsh-desktop-compat test` 跑包内自带 6 份 vitest 测试（tests/ 目录下）。

**Q: 上游 DSH 修了同样的问题，我需要做什么？**

A: 卸载插件即可。src/patch-registry.ts:49-86 给每个补丁都注明了 removeWhen 条件（比如「The upstream agent loop natively and deterministically resumes queued turns.」），达到条件后整个包就没存在的必要了。

**Q: Task Board 的后台调度具体能跑什么任务？**

A: 仅支持「项目制、shared-workspace 隔离、必须有 prompt」的任务（src/background-scheduler-runner.ts:114-118、216-230）。git-worktree 隔离、空 prompt、workspace 未注册或模型未配置都会被拒，但不报错——任务交给浏览器侧调度器继续找执行路径。

## 上手难度
入门 — 安装由桌面端自动完成，没有用户级配置，行为都是「缺漏修补」式；普通用户不需要理解 SDK 钩子细节，只要确认桌面客户端版本匹配、症状对应即可。开发者若想理解实现，需要熟悉 Cordis function plugin、agent/status 事件流和 LLM stream chunk 协议。

## 已知问题与限制
- 仅适配 DSH `0.1.0-rc.7`：补丁清单里每个补丁的 applicableVersions 都只列此版本（src/patch-registry.ts:49-86）；其他版本需要桌面端先用着，等补丁更新
- 工具调用参数恢复只在「外层 schema 拒绝、内层 schema 接受」时剥壳：其他情况（双通过、双不通过、未知工具、重复工具 schema）一律不动；诊断里会带 reason 标明具体原因（src/tool-call-normalization.ts:21-28、100-152）
- 上游一旦实现相同的取消续推 / 取消展示 / arguments 包装处理，本包就失去存在意义（README.md:35-37、src/patch-registry.ts 各个 removeWhen 字段）
- 后台 Host 调度器只接管 `shared-workspace` 隔离、`git-worktree` 隔离会被显式拒绝并写 fallbackReason（src/background-scheduler-runner.ts:256-258）
- 工作区文件本地打开只接受白名单扩展名，脚本类（.js、.ts、.html、.svg 等）被显式排除（src/workspace-file-open-policy.ts:28-44），路径必须在已注册工作区根目录下（src/workspace-file-open-route.ts）
- 普通 Web UI profile 不会自动加载这个 bundle，需要桌面端的隔离 desktop profile（README.md:29）

---

This document is auto-generated by [deepseek-plugin.org](https://deepseek-plugin.org). HTML page: [deepseek-harness-desktop](https://deepseek-plugin.org/plugins/ningbainb/deepseek-harness-desktop/packages/dsh-desktop-compat)
Wiki generated by AI (model: `MiniMax-M3`)
