Bundle
dsh-plugin-safety
DSH 插件健康告警:预检失败自动禁用后页面持久弹窗;出现不可用插件告警即自动创建 headless 修复会话,叉掉前刷新/重开页面告警都在
- Source
- Seryta
- License
- MIT
- Updated
- Updated 23 days ago
Readme
# dsh-plugin-safety — 插件健康告警
DSH 插件故障防控的最后两环:
1. **预检 + 自动禁用**:`scripts/check-profile-plugins.py` 在 dsh-web 启动前预检
profile 中每个未禁用的插件入口;import 失败的坏插件自动写入
`disabled: true`(bundle 则移除 bundle),并落盘告警。
2. **持久告警 + 自动修复会话**:浏览器半部渲染红色告警卡片,× 掉前
刷新/重开页面都会重现;host 半部在返回告警前保证每个告警 action 都有
对应的 headless 修复会话。
## 核心不变式
> **只要出现“不可用插件已被禁用/需人工处理”的告警,就自动创建修复会话。**
> 不区分告警来源:预检脚本检出、直接写 `notice.json` 的测试/手工场景,
> 都遵守同一规则。
具体机制:
- host 半部 `GET /plugins/dsh-plugin-safety/notice` 返回告警前先检查
`fixActionIds` 是否覆盖全部 action;未覆盖就调用
`check-profile-plugins.py --ensure-fix` 补启动。
- 同一批 action 只启动一次;同一份告警新增坏插件时,只为新增 action
补启动一次。
- `Popen` 成功才写 `fixStartedAt` / `fixActionIds`;启动失败时前端如实
显示“修复会话自动创建失败”,不再假装已创建。
- 文件锁防多个 GET/预检并发重复启动。
## 组件
| 文件 | 职责 |
|---|---|
| `index.js` | host 半部:告警读写端点 + 返回前 ensure-fix |
| `client.js` | 浏览器半部:持久弹窗、× 关闭(POST 清除) |
| `scripts/check-profile-plugins.py` | 预检、自动禁用、告警落盘、修复会话启动 |
| `cordis.patch.yml` | bundle patch:把插件挂进 profile |
| `dsh.plugin.json` | DSH 插件元数据 |
零第三方依赖:host/脚本仅用 Node/Python 标准库;client 为原生 DOM。
## 告警文件
`$DSH_HOME/storages/plugin-safety/notice.json`(未设置 `DSH_HOME` 时为
`~/.dsh/storages/plugin-safety/notice.json`):
```json
{
"at": 1786799000000,
"actions": [
{
"id": "some-plugin",
"name": "some-plugin",
"kind": "patch",
"reason": "Cannot find package 'some-plugin'",
"disabledAt": 1786799000000,
"autoDisabled": true,
"profile": "/home/me/.dsh/profiles/web"
}
],
"fixStartedAt": 1786799001000,
"fixActionIds": ["some-plugin"],
"fixWorkspace": "/home/me/.dsh/plugin-maintenance",
"fixLogFile": "/home/me/.dsh/plugin-maintenance/plugin-safety-fix.log"
}
```
POST 同一端点即视为用户已叉掉告警,文件重置为
`{"at": 0, "actions": []}`;下一条新告警会重新生成。
## 安装
```sh
dsh plugin --profile web add github:Seryta/dsh-plugin-safety
```
安装后重启 dsh-web(host 半部需要进程重新 import;client.js 是静态服务,
重启前刷新页面也能拿到新逻辑)。
如果同时想要启动前预检(推荐),把随包脚本放到 `$DSH_HOME/scripts` 并
挂到 systemd `ExecStartPre`:
```sh
mkdir -p ~/.dsh/scripts
cp ~/.dsh/profiles/web/node_modules/dsh-plugin-safety/scripts/check-profile-plugins.py \
~/.dsh/scripts/check-profile-plugins.py
```
`ExecStartPre=-/home/<you>/.dsh/scripts/check-profile-plugins.py`
(`-` 前缀表示预检失败不阻断启动;脚本对能自动禁用的失败返回 0,
对无法自动禁用且需人工处理的失败返回 1)。
## 验证
```sh
npm test # host/脚本/客户端逻辑测试,全部使用假 dsh,不创建真实会话
node --check index.js
python3 -m py_compile scripts/check-profile-plugins.py
```
本仓库的测试覆盖:
- 预检发现坏插件 → 自动禁用、备份、落盘告警、启动一次修复会话;
- 重复预检不重复启动;新增坏插件只补启动一次;
- 直接写 `notice.json` → host GET 前补建修复会话,第二次 GET 不重复;
- POST 清除告警;无告警返回 `notice: null`;
- 客户端弹窗持久渲染、× 关闭、以及 `fixStartedAt` 有无时的如实文案。
## 已知边界
- 浏览器只在页面加载时 poll 一次;页面开着期间新写入的告警会在下次刷新
时出现(与“刷新/重开仍在”的持久语义一致)。
- 自动修复会话是 headless DSH 任务;它本身无法修复时会在会话内报告阻塞
原因,host 不会阻塞重试。
- `$DSH_HOME` 会被 host 与预检脚本一致尊重;systemd 预检通常不设置该
变量,因此走默认 `~/.dsh`。
## License
MIT
Install
dsh plugin --profile web add github:Seryta/dsh-plugin-safety
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-plugin-safety from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.