Skip to main content
Glama
README.md
# zcode-ssh

SSH 主机注册表 + 远程操作,做成 ZCode 插件。移植自 [pi-ssh](https://github.com/KrystalQAQ/pi-ssh),引擎源自 [dsh-ssh](https://github.com/zhu1090093659/dsh-web/tree/dev/packages/dsh-ssh)(Apache-2.0,版权署名保留:© zhu1090093659 / linxin666)。

## 功能

**7 个 MCP 工具**(server id `ssh`,模型可直接调用):

| 工具 | 说明 |
|---|---|
| `ssh_list` | 列出已配置主机(alias/host/user/auth/env/tags),支持模糊查询 |
| `ssh_exec` | 在远端执行命令(超时控制、stdout/stderr 分离、2MB 截断保护、取消传播) |
| `ssh_upload` | SFTP 上传(本机 → 远端) |
| `ssh_download` | SFTP 下载(远端 → 本机) |
| `ssh_tunnel` | 本地端口转发隧道(start/list/stop/stop-all,只听 127.0.0.1) |
| `ssh_cluster` | 多机并发执行(按 alias/environment/tags 筛选,默认并发 8) |
| `ssh_manage` | 主机注册表增删改查 + `~/.ssh/config` 导入 + 连通性测试 |

前 6 个是 agent 操作工具(对注册表只读);`ssh_manage` 承接原 pi 版 `/ssh` 的管理能力,由人工在对话中确认后驱动。

**1 个命令** `/ssh`:

```
/ssh                       菜单
/ssh list                  主机表
/ssh import                从 ~/.ssh/config 一键导入
/ssh add [alias]           添加主机
/ssh edit <alias>          编辑主机
/ssh remove <alias>        删除主机(同时断开连接与隧道)
/ssh test [alias]          测连接(缺省测全部)
/ssh tunnel [list|stop <id>|stop-all [alias]]   隧道管理
```

ZCode 的命令是提示词而非交互对话框,因此 `/ssh` 会引导 agent 调用对应工具,并在写操作前与你确认字段。

**引擎能力**(与 pi-ssh / dsh-ssh 一致):

- 每 alias 持久连接池:30 分钟空闲断开、断线自动重连(最多 3 次)
- key / password / ssh-agent(SSH_AUTH_SOCK / Pageant / 显式 socket)认证,支持加密 key
- ProxyJump 多级跳板(插件内 alias 或 `[user@]host[:port]` 地址)
- OpenSSH ProxyCommand(%h/%p/%r/%n 展开)
- `~/.ssh/config` 导入:Host/HostName/User/Port/IdentityFile/IdentityAgent/ProxyJump/ProxyCommand/Include;wildcard、Match、已存在 alias 跳过并给出原因

## 安装

插件从本地市场安装(`.zcode-plugin/plugin.json` 声明 MCP server,`node ${CLAUDE_PLUGIN_ROOT}/dist/server.cjs` 启动)。`dist/server.cjs` 已随插件打包,装好即用,不需要 `npm install`;运行需要机器上有 `node`(≥ 20)。

## 数据与安全

- 主机配置:`~/.zcode/ssh/hosts.json`(可用 `$ZCODE_SSH_HOME` 覆盖),原子写入,目录 0700 / 文件 0600
- 密码与 key 口令明文存于该文件(与 ssh 生态惯例一致的信任模型;不写日志)
- agent 认证只存 socket 路径,不接触私钥材料
- 隧道只监听 127.0.0.1
- 模型拿不到 ProxyCommand 原文(只报告"该主机配置了 proxy-command"布尔值)——命令可能内嵌堡垒机凭据
- 删除主机或修改连接字段会立即断开该 alias 的连接池与隧道
- `ssh_upload`/`ssh_download` 在本机读写任意本地路径(宿主进程权限,非沙箱)

## 布局

```
.zcode-plugin/plugin.json  ZCode 插件清单(commands + mcpServers)
mcp/server.ts              7 个 MCP 工具(原 pi 的 tools.ts + /ssh 管理逻辑)
commands/ssh.md            /ssh 命令(提示词驱动 ssh_manage)
src/engine.ts              引擎门面
src/store.ts               主机存储(原子 JSON + ~/.ssh/config 导入)
src/ssh-config.ts          ssh_config 解析器
src/home.ts                数据目录(~/.zcode/ssh)
src/protocol.ts            类型契约
src/engine/                connection-pool / proxy-command / sftp / tunnel / cluster
dist/server.cjs            esbuild 单文件产物(安装后直接运行)
build.mjs                  构建脚本(stub 掉 ssh2 可选原生绑定)
smoke/engine-smoke.mjs     引擎集成冒烟测试(内嵌 ssh2 服务端,17 项)
smoke/mcp-smoke.mjs        MCP 协议测试(真实 stdio 握手 + tools/call,15 项)
```

## 开发

```sh
npm install
npm run typecheck      # tsc --noEmit
npm run build          # 打 dist/server.cjs
npm run smoke          # 引擎 17 项
npm run smoke:mcp      # MCP 协议 15 项(需先 build)
```

## 已知限制(继承 pi-ssh)

- 上传/下载均为单文件(agent 工具不遍历目录):上传目标必须是绝对路径,下载不支持整目录
- exec 断线重放可能对非幂等命令重复执行
- ProxyJump 与 ProxyCommand 不能同主机混用;仅首跳可用 ProxyCommand
- 断点续传未实现
- 交互式 PTY 终端未移植(pi 版同样未移植)

## License

Apache-2.0。引擎代码源自 dsh-ssh(Apache-2.0)经 pi-ssh 移植,修改记录见 `NOTICE`。