# dsh-devops
**把服务器运维搬进 DSH Web:SSH 服务器管理 · 硬件 / 进程 / 日志监控 · AI 巡检 · Git 部署闭环**
[English](./README.md) · [中文](./README.zh.md)
[](LICENSE)
[](https://github.com/deepseek-ai/deepseek-harness)
[](#功能特性)
[](#开发与测试)
[](https://github.com/topics/dsh-plugin)
---
## 这是什么
dsh-devops 是一个 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(DSH)Web 插件。
不用离开聊天界面、不用另开终端,你在 DSH 侧栏点开「远程运维」,就能添加 SSH 服务器、
查看硬件与进程、让 AI 定时巡检日志和进程异常,并把 Git 仓库的代码部署到服务器、重启服务。
它最核心的是一个**部署闭环**:
1. **首次 AI 部署** —— 选定 Git 仓库、分支与目标服务器,AI 通过 SSH 完成环境检查、依赖安装、
构建、服务启动与健康验证;
2. **脚本固化** —— 部署成功后,把可复用的步骤沉淀为带版本管理的 `.sh` 脚本
(`候选 → 已验证 → 失效`,哈希防篡改),一次性环境操作与日常更新分开对待;
3. **一键更新** —— 后续部署在服务器上执行 `git pull --ff-only`(只快进,杜绝意外合并/变基),
固定步骤直接执行脚本、未固化步骤由 AI 兜底,失败自动修复(默认最多 2 轮)后重试。
> 巡检永远只读:AI 只分析与建议,不自行修复或重启服务。
> 这个边界由工具权限在结构上强制执行,不依赖提示词措辞。
## 界面预览
| 服务器总览 | 硬件监控 |
| --- | --- |
|  |  |
| 进程分组与 AI 巡检 | 项目服务详情 |
| --- | --- |
|  |  |
**项目运维**:多项目、多仓库、多部署目标,首次 AI 部署 / 手动更新一键触发。

## 功能特性
### 🖥 服务器管理
- 多台 SSH 服务器增删改查;**添加前强制真实登录测试**,能无人值守执行远程命令才能保存
- 首次连接核对并保存主机指纹,指纹变化即暂停连接
- 插件私有 SSH 配置,与系统 / 用户配置完全隔离;支持私钥、跳板机
- 覆盖 Linux(不设发行版白名单)与 macOS,能力不满足时如实标注「可用 / 受限 / 不可用」及原因
### 📊 监控与 AI 巡检
- **硬件**:CPU / 内存 / 磁盘使用情况,手动或定时采集(默认 60 秒)
- **进程**:无需逐个配置,全量枚举运行进程并按项目 / 服务分组;AI 逐批分析资源与状态异常,
给出具体进程与判断依据,分析覆盖率透明展示(部分分析不会伪装成正常)
- **日志**:按「项目 → 服务 → 日志文件」动态发现日志来源(如读取 Supervisor 实际生效配置),
增量读取、告警去重;AI 识别异常与告警,展示级别、摘要与可定位的原文证据
- **服务端执行**:关闭浏览器不停止巡检;DSH 重启后自动恢复巡检计划,不无限堆积补跑
### 🚀 项目部署
- 多项目、多仓库、多部署目标;SSH、Git 认证、提权分别配置、分别验证
- 首次部署由 AI 编排,部署前确定健康检查(预期进程、端口、等待时限),并动态刷新日志监控
- 后续部署:仓库 / 分支核对 → `git pull --ff-only` → 依赖更新 / 构建 → 服务重启 → 健康验证
- 未提交改动、分支不符、分叉冲突一律停止报告,绝不自动覆盖;默认不提供危险的全量回滚
- 任务全程持久化,中断后标记「中断 / 待核对」,核对远程实际状态后才能继续
### 🛡 安全设计
- 凭据(密码 / 私钥 / 口令)**AES-256-GCM 加密存储**,密钥材料与配置数据分离
- 敏感信息在展示、持久化、送入 AI 上下文前统一**脱敏**;密码不进命令、脚本与日志
- 远程命令经**白名单解析**;巡检为只读边界(工具权限实施,不靠提示词约束)
- RPC 走宿主认证通道,API 层 zod 全量校验
- **无安装期脚本**,无遥测,插件自身不持有模型 API Key
## 快速开始
### 环境要求
- DSH Web 宿主(支持 `dsh plugin` 插件机制),已验证版本见下方[兼容性](#兼容性)
- 能连到目标服务器的 SSH 客户端
- ⚠️ **保存任何凭据前,先设置 `DSH_DEVOPS_KEY_FILE`**(见下方说明)
### 安装
两条路径都是预构建的,**你不需要在本机跑任何构建**:
```sh
# 从 npm 安装(推荐:免掉构建授权)
dsh plugin --profile web add @bigbigtooth/dsh-devops
# 或从预构建 tarball 安装
dsh plugin --profile web add https://github.com/bigbigtooth/DSH-DevOps-Plugin/releases/latest/download/dsh-devops-latest.tgz
```
装完**必须重启宿主** —— 插件 bundle 在启动期加载,`plugin add` 只写 manifest:
```sh
pkill -f '\.bin/dsh --profile web'
sleep 2
nohup ~/.dsh/tooling/node_modules/.bin/dsh --profile web >> /tmp/dsh-web.log 2>&1 &
```
安装后,DSH 侧栏底部、「设置」上方会出现**远程运维**入口;点击进入独立运维面板,
点「返回会话」随时恢复聊天。
> 无头场景把 `--profile web` 换成 `--profile headless`;本插件的 UI 半侧只在
> web profile 下提供,headless 下巡检与部署照常工作。
### ⚠️ 三个必踩的坑
1. **先设密钥文件。** 不设 `DSH_DEVOPS_KEY_FILE` 时插件使用进程内内存密钥,
宿主每次启动重新生成,**已保存的凭据在重启后无法解密**:
```sh
export DSH_DEVOPS_KEY_FILE="$HOME/.dsh-devops/master.key"
```
密钥文件以 `0600` 写入。**没有找回通道 —— 密钥文件丢了凭据就没了。**
2. **同版本号重装不生效。** pnpm 对相同 `file:` 规格命中缓存,必须先 remove 再 add:
```sh
dsh plugin --profile web remove @bigbigtooth/dsh-devops
dsh plugin --profile web add @bigbigtooth/dsh-devops
```
3. **必须重启宿主。** 见上。
## 权限与副作用
完整披露见 **[SAFETY.md](./SAFETY.md)**(中文 [SAFETY.zh.md](./SAFETY.zh.md))。摘要:
| 项目 | 说明 |
| --- | --- |
| 读取的本地文件 | 仅 ``(默认 `~/.dsh-devops`)与宿主存储域 `dsh_devops`;**不读** `~/.ssh`、shell 历史 |
| 读取的远程文件 | 你添加的服务器上的硬件、进程、日志、git 工作树 |
| 网络出口 | ① 到你的服务器(SSH);② 到你配置的模型(巡检 / 部署数据)。**无遥测、无第三方端点** |
| API Key | 插件自身**不持有**任何模型 API Key,使用宿主 LLM 服务 |
| 写入行为 | 巡检只读;部署仅在你显式创建的任务内写(`git pull --ff-only`、构建、重启) |
| 会话数据 | **不读取、不外传** DSH 会话内容、凭据与工作区文件 |
| 安装期脚本 | 无 `preinstall` / `install` / `postinstall` |
## 兼容性
DSH 目前全线在 rc,且官方明确会有破坏性兼容变更。请按下表对齐:
| dsh-devops | DSH (harness) | 状态 |
| --- | --- | --- |
| 0.5.0 | 0.1.5-rc.2 | ✅ 已实测(含全量测试与实机安装) |
| 0.4.x | 0.1.5-rc.2 | ✅ 已实测 |
> 0.5.0 起包名从 `dsh-devops` 改为 `@bigbigtooth/dsh-devops` —— 因为 npm 上不带 scope
> 的同名包已被他人预留占用。0.4.x 仍可从 `v0.4.0` 的 release 资产安装。
宿主版本用 `dsh --version` 查看。`dsh-devops` 对 `@deepseek-ai/cordis` 声明的是
**正式版**范围(`^4.0.1`,两者均为 optional peer),因此不涉及预发布三元组
匹配问题;宿主换 minor 时请优先升级本插件。
## 验证安装
安装过程没有 console exporter,`ctx.logger` 只写内存缓冲,
**日志和退出码都不构成验证信号**。唯一硬证据是「层是否加载」加「真实路由是否有返回」:
```sh
# 1) 配置层在不在(应能看到 dsh-devops 这一层)
dsh --profile web --dump-config | grep -A5 'dsh-devops'
# 2) 宿主启动日志里不应有 activation 门禁失败
# 3) 启动后打开「远程运维」面板,添加一台服务器 —— 添加前的登录测试会真实
# 执行远程命令,它成功才算装通
```
## 配置
以下默认值可通过 cordis patch 层覆盖:
| 字段 | 默认 | 说明 |
| --- | --- | --- |
| `dataDir` | `~/.dsh-devops` | 私有数据目录(SSH 配置、密钥、降级存储) |
| `modelRef` | null | AI 巡检 / 部署所用模型;为空时 AI 步骤诚实报告不可用 |
| `hardwareIntervalSeconds` | 60 | 硬件巡检周期 |
| `processIntervalSeconds` / `logsIntervalSeconds` | 300 | 进程 / 日志 AI 巡检周期 |
| `retentionDays` | 30 | 普通历史保留(配置、有效脚本不清理) |
| `batchBudgetTokens` | 8000 | 单批 AI 输入预算 |
环境变量 `DSH_DEVOPS_KEY_FILE` 指定凭据主密钥文件路径(见上方坑 1)。
## 从源码安装
```sh
git clone https://github.com/bigbigtooth/DSH-DevOps-Plugin.git
cd DSH-DevOps-Plugin
pnpm install
pnpm build && pnpm pack --pack-destination dist
dsh plugin --profile web remove @bigbigtooth/dsh-devops # 同版本重装必须先 remove
dsh plugin --profile web add ./dist/bigbigtooth-dsh-devops-*.tgz
```
从 Git 安装需要你自己构建 —— git 安装不跑构建脚本。
## 开发与测试
```sh
pnpm typecheck # 严格类型(Host/Client/Tests)
pnpm test:unit # 契约/SSH/Vault/仓库/执行/采集/巡检/日志/调度/脚本…
pnpm test:contract:dsh # 真实 cordis 运行时生命周期 + 重启持久化
pnpm test:integration:ssh # 私有配置/askpass/指纹/执行/停止
pnpm test:integration:ops # 真实 git 仓库部署管线
pnpm test:e2e:web # 全链路 + 反例矩阵
pnpm test:acceptance # 产品验收可执行子集
pnpm test # 全部
```
SSH 与部署集成测试跑在进程内 fake 上,不需要真实服务器。贡献指南见
[CONTRIBUTING.zh.md](./CONTRIBUTING.zh.md)。
## 架构(Host / Client 单 bundle)
```
src/contracts/ DTO Schema、错误码、部署状态机、API 契约(双端共享)
src/host/
adapters/ 端口 + DSH/file/memory 适配(业务零 SDK 依赖)
repository/ 版本化记录、迁移备份、原子占用、requestId 幂等
vault/ AES-256-GCM 凭据封装、脱敏
ssh/ 命令白名单解析、私有配置生成、OpenSSH 传输(askpass 私有通道)
execution/ 身份化远程执行单元(意图先行、事实文件、停止核对)
probes/ 硬件/进程采集(Linux+macOS 解析器,缺字段=null 非 0)
agents/ 受限 AI 巡检(分批、覆盖率、证据服务端校验)
logs/ Supervisor 发现、读写双游标、增量读取、告警去重
scheduler/ 持久化调度(单飞合并、不补跑、抖动、AI 并发上限)
deployment/ git 预检、ff-only 更新、首部署编排、修复(≤2轮)、恢复、核对
scripts/ 候选→已验证→失效(哈希防篡改、适用性指纹)
api/ zod 全量校验的 RPC 分发(/rpc/dsh-devops 认证通道)
src/client/ slots 入口 + 大卡片页面模块(服务器/项目 + 各自详情页)+ 图表 + 状态模型
```
插件集成备忘(给二次开发者)
- patch 行不写 `config` 时插件拿到的是 `undefined`(不是 `{}`),`Config` 必须用
`.prefault({})` 兜底,否则整棵插件树启动失败。
- 宿主服务名与存储名有语法约束:服务必须经 `ctx.get(name)` 读取;
domain/表名须匹配 `^[a-z][a-z0-9_]*$`(如 `dsh-devops`→`dsh_devops`、
`inspectionRuns`→`inspection_runs`),由适配器在边界处映射。
- 卸载时多个异步 disposer 是**并发**执行的(逆注册序,但无串行完成保证)。
有顺序依赖的清理必须合并进**同一个** `ctx.effect` 返回的单个 disposer 里串行 await。
## 文档
- [产品设计(PROD)](docs/PROD.md) —— 产品目标、需求与设计默认值
- [实施计划(PLAN)](docs/PLAN.md)
- [宿主集成(INTEGRATION)](docs/INTEGRATION.md) —— 接入决策与设计要点
- [验收状态(ACCEPTANCE)](docs/ACCEPTANCE.md) —— 验收结果与兼容矩阵
- [安全与行为披露](SAFETY.md) / [安全与行为披露(中文)](SAFETY.zh.md)
- [贡献指南](CONTRIBUTING.zh.md) / [Contributing](CONTRIBUTING.md)
## License
[MIT](LICENSE)