# deepseek-harness-desktop

> 为 dsh Web GUI 增加完整 SSH 运维能力：主机管理、持久连接池、命令执行、Web 终端、SFTP 文件传输、本地端口转发、集群并发执行，以及 6 个共享主机配置的 Agent 工具。

## 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-ssh
```

## Wiki

## 一句话定位
为 dsh Web GUI 加入一套完整的 SSH 运维能力：在 Web 端集中管理多台远程主机（增删改查、搜索、连接测试、一键导入 `~/.ssh/config`），在 host 进程内复用持久 ssh2 连接池执行命令、跑 Web 终端、SFTP 传文件、开本地端口转发隧道，并能在多台主机上并发跑同一条命令；同时为 Agent 提供 6 个工具调用同一份主机配置。

## 核心能力
- 主机增删改查、搜索、连接测试；支持密钥 / 密码认证、passphrase 密钥、ProxyJump 多级跳板机
- 一键导入 `~/.ssh/config`：解析 Host / HostName / User / Port / IdentityFile / ProxyJump 等字段，已有别名自动跳过
- 持久 ssh2 连接池：每台主机复用一条长连接（不每次重连），空闲 30 分钟自动断开，断线自动重连（最多 3 次）
- 命令执行：单主机 exec 带超时（默认 60s，可覆盖）、stdout/stderr 分离、单次输出 2MB 截断保护；集群并发执行（默认并发 8，可按 alias/环境/标签过滤）
- Web 终端（xterm.js + WebSocket PTY，背压自动暂停/恢复）、SFTP 文件传输（上传走 NDJSON 进度流，下载返回二进制流）、本地端口转发隧道（仅 127.0.0.1 监听，访问远程数据库 / 内网服务）、Linux 主机实时监控（CPU / 内存 / 磁盘 / 负载 / 进程 / systemd 异常，3 秒刷新）
- Agent 工具 `ssh_list` / `ssh_exec` / `ssh_upload` / `ssh_download` / `ssh_tunnel` / `ssh_cluster`，GUI 与 Agent 共享同一份主机配置

## 技术实现
- **语言**: TypeScript
- **关键依赖**: ssh2（Node 端 SSH 客户端）、@xterm/xterm + @xterm/addon-fit（浏览器终端）、ws（WebSocket 升级以承载 PTY）、@deepseek-ai/dsh-tools（Agent 工具定义）
- **架构模式**: 双半区 cordis 插件——host 半区（`src/index.ts`）启动 SshEngine、注册 /api/dsh-ssh/* 路由与 WebSocket 终端、注册 6 个 Agent 工具、注入系统提示词；client 半区（`src/client/index.ts`）通过 DOM 注侧边栏入口 + 挂载 React 面板（六个标签页）。通过 `cordis.patch.yml` 在 web profile 注入 `id: ssh` 的 bundle 行，仅修改 DSH 服务发现，不改 DSH 源码。
- **入口文件**: `packages/dsh-ssh/src/index.ts`（host 半区），`packages/dsh-ssh/src/client/index.ts`（browser 半区）

## 适用场景
当用户在 dsh Web GUI 里需要同时管多台远程服务器时，这个插件能把 SSH 主机配置、远程命令、Web 终端、文件传输、端口转发全部集中到浏览器里，配合 Agent 工具让 AI 也能在同一份主机配置上做远程操作。典型场景：运维同学一次性导入已有 `~/.ssh/config`，在浏览器里就能跨多台机器完成服务状态巡检、批量脚本下发、文件分发、内网数据库端口转发。

## 前置依赖与兼容性
| 依赖 | 最低版本 | 说明 |
|---|---|---|
| Node.js | ^22.19.0 \|\| >=24.0.0 | 来自 package.json engines 字段 |
| DSH（官方 SDK） | 通过 devDependencies 锁到 ^0.1.0-rc.7 | package.json 未声明 dsh.engines，需 DSH 0.1.0-rc.7+ 才能解析所有运行时注入 |
| React | ^18.2.0（peerDependencies） | 浏览器半区面板运行环境 |
| 平台 | 跨平台 | host 半区跑 Node.js；client 半区跑浏览器；ssh2 是纯 JS 库，无原生模块限制 |
| 原生模块 | 无 | 运行时无原生 Node 模块；ssh2 是纯 JS 的 SSH 客户端，不引入 native 绑定 |

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

## 配置项
| 配置 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| `enabled` | 开关 | 总开关：关闭后所有路由、Agent 工具、系统提示词声明全部停止挂载 | true |
| `announceToAgent` | 开关 | 是否在系统提示词里向 Agent 声明本插件的能力与限制；关闭后 Agent 看不到 SSH 工具 | true |
| 主机别名 | 字符串 | openpanel/侧边栏/Agent 都按这个别名调用，规则：字母开头的字母/数字/点/中划线/下划线 | 用户在 GUI 中配置 |
| `~/.ssh/config` 导入 | 一次性操作 | 在主机管理页一键导入；已有别名自动跳过 | — |

> 引擎自身还有 8 个运行时常量（空闲超时 30 分钟、连接超时 15s、keepalive 15s、最大输出 2MB、exec 默认超时 60s、集群默认并发 8、SFTP 并发 8、keepalive 失败 3 次断开），这些是 host 内部硬编码，不暴露给用户设置。

## 常见问题
**Q: 在局域网里别人能访问我的 SSH 控制台吗？**

A: 不能。所有 `/api/dsh-ssh/*` 路由都做了 loopback 校验（socket 必须是 127/8 或 ::1，再加同源 Host/Origin 头校验），LAN 邻居直接访问会被拒绝；本地端口转发隧道也只监听 127.0.0.1，不会暴露到外网。

**Q: 密码是怎么保存的？会被别人看到吗？**

A: 以明文存于 `~/.dsh/dsh-ssh.json`（文件权限 0600、目录 0700，原子写入），与 ssh-skill 在 ssh-config 注释里写密码同一信任模型。设计上不做额外加密，理由是加密反而引入新密钥管理负担；用户应保证本机账户安全。

**Q: Agent 会不会跑去我没配置的主机上执行命令？**

A: 不会。Agent 只能操作 GUI 已配置或从 `~/.ssh/config` 导入的主机别名；别名未配置时工具调用直接报错，不会臆造主机——这一点在系统提示词里被显式声明。

**Q: 远程命令超时或者输出很大怎么办？**

A: exec 默认超时 60 秒（可覆盖），超时后会向远端 stream 发送 KILL 并强制收尾；单次 stdout/stderr 累计超过 2MB 会自动截断并标记 `[output truncated]`，避免一条命令挤出几 GB 把进程撑爆。

**Q: 跳板机和集群执行怎么用？**

A: 主机配置里填 `proxyJump` 数组（**每一跳必须是本插件已配置的主机别名**），引擎会按顺序 `forwardOut` 链式连接。集群执行在「集群」标签或 `ssh_cluster` 工具里按 alias / 环境 / 标签过滤，标签用 ALL 语义全匹配，默认并发 8 可调整。

**Q: 卸载插件会清掉我配置的主机吗？**

A: 不会自动删除。`~/.dsh/dsh-ssh.json` 是用户数据文件，插件装卸只影响引擎、路由、Agent 工具的挂载与注销；想清干净需手动删除或重命名该文件。

## 上手难度
进阶 — 配置主机、密钥、跳板机要懂 SSH 基础；GUI 内的主机管理、终端、文件传输都很直接，但是 Agent 工具与系统提示词的协作模型需要花点时间理解。

## 已知问题与限制
- 上传文件的远程目标路径必须是绝对路径（相对路径会在上传入口直接报错）。
- 下载暂不支持整个目录（逐文件下载）；上传支持目录递归（walk 本地目录逐文件传）。
- exec 断线自动重连（最多 3 次）可能重放非幂等命令，长任务（部署、数据库迁移）使用前请确认幂等性。
- ProxyJump 跳板机的每一跳必须是本插件已配置的主机别名，不能直接写 IP / 域名。
- 断点续传（resume）暂未实现。
- Agent 工具的 `ssh_upload` / `ssh_download` 路径是宿主机器本地路径（不经 bash 沙箱），与 ssh-skill 相同的语义，注意该权限面。
- exec / cluster 的远程输出原样返回（不脱敏），命令如 `env` 可能把远端环境中的密钥带回对话记录。

---

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-ssh)
Wiki generated by AI (model: `MiniMax-M3`)
