← 返回列表
未验证
捕获插件崩溃并一键禁用,免重启恢复面板
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/17 · 已提供中文文档
综合分
27.8
GitHub 分
27.8
用户评分
—
★ Stars
1
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add Zlyraz/dsh-ballute该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-ballute(Ballute 气囊)
DeepSeek Harness 插件崩坏防护:把插件故障从「安静退位」变成 可见 · 可归因 · 可恢复。
ballute = balloon + parachute(气球伞,减速缓冲之意)。
English quickstart
dsh-ballute 是 DeepSeek Harness(DSH)的崩溃防护插件。DSH 会静默移除崩溃的插槽条目——你只会看到一个空白面板,标签页悄悄消失,错误只落在控制台里。Ballute 把它变成你能看见、能归因、能恢复的东西:
| 防线 | 作用 |
|---|---|
| L1 预检 | 静态契约检查(GET /api/ballute/v1/inspect)——在装载前捕获结构性故障 |
| L2 隔离 | 通过官方 ctx.slots.onEntryError 钩子在右下角显示崩卡(插件 · 插槽 · 错误)|
| L3 黑匣子 | 崩溃遥测 JSONL 日志 + 历史列表,重启不丢,rev 可精确定位代码版本 |
| L4 恢复 | 崩卡上一键「禁用」→ 写入补丁层 → HMR 免重启卸载 |
| L5 安全模式 | 最小 safe profile + 跨 profile 静态体检/禁用,救回坏掉的主 profile |
安装:
dsh plugin add github:Zlyraz/dsh-ballute
诚实边界:覆盖运行时插槽条目崩溃(L2 域)。装载器级故障——client apply 抛错,或 bundle 文件缺失——会在任何 UI 存在之前就杀死 client/host 启动;这些只能从 M4 安全模式救回。完整边界见下方诚实边界,包括 SlotAssemblyError 整页空白的情况。
维护:业余时间爱好维护——欢迎 issue 和 PR,但响应可能较慢。AI 协作者请先读 AGENTS.md。
能力(随里程碑生长)
| 防线 | 状态 | 说明 |
|---|---|---|
| L2 隔离 | ✅ M1 | 订阅官方 ctx.slots.onEntryError 缝隙 → 右下角崩卡(插件名 · 槽 key · 错误)|
| L4 恢复 | ✅ M1 | 崩卡「关闭插件」→ 写补丁层 disabled: true → HMR 免重启卸载 |
| L1 预检 | ✅ M2 | GET /api/ballute/v1/inspect 静态契约体检(装载前发现结构故障)|
| L3 观测 | ✅ M3 | 崩溃遥测 JSONL 黑匣子 + 历史列表(重启不丢,rev 号可对时)|
| L5 兜底 | ✅ M4 | 安全模式:safe 最小 profile + 跨 profile 静态体检/禁用恢复坏 profile |
诚实边界:M1-M3 只覆盖 L2 域(运行时条目崩溃)。装载器自身故障域分两级——client apply 抛错炸 client boot(host 还活着);bundle 文件缺失(load 档)炸 host 进程本身(curl 都不通)。两者都进不了 UI,只能靠 M4 安全模式从外部救(复现:装验收假人 crash-test-dummy 后开 ?dummyCrash=apply,或把 fixtures/fault-load 真实装进 profile)。
另一个崩卡管不到的缝隙(实测过):插槽组装错误会穿透错误边界卸载整树。DSH 的 SlotErrorBoundary 只吃普通渲染错误(条目退位 → 面板空白);SlotAssemblyError 家族(locale face 未就绪 / 缺 hookContext / session binding provider 外渲染,见 @deepseek-ai/dsh-client-web-react)会被重新抛出,前端无顶层兜底 → React 卸载整棵树 → 整页纯色无内容,偶发于 AI 子代理打开(session-aware 插槽重组装竞态)。此时 Ballute UI 一起没了,取证看 console 的未捕获 SlotAssemblyError,刷新即恢复;根治需官方加顶层错误页(已列入 issue 素材)。
安全模式(L5 兜底)
官方 CLI 暂无 --safe-boot 旗标(已探测,issue 草稿见 docs/issue-safe-boot.md),所以安全模式靠自建一个最小 profile:官方 bundle + 仅 dsh-ballute。主 profile 的 UI 坏死时,用它起一个能打开的实例,从外部救回坏 profile。
一次性搭建——在 $DSH_HOME/profiles/safe/ 下放四个文件:
package.json:
{
"name": "dsh-profile-safe",
"private": true,json
"dependencies": {
"dsh-ballute": "github:Zlyraz/dsh-ballute"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"dsh-ballute"
]
}
}
}
cordis.yml(空树即可,插件树由补丁层组装):
yaml
[]
cordis.patch.yml(保持空数组,别加别的插件进来):
yaml
[]
pnpm-workspace.yaml:
yaml
packages:
- .
nodeLinker: hoisted
autoInstallPeers: false
然后在该目录 pnpm install。
用法:先停掉坏死的实例——注意 host 进程还活着时会照常响应探测,看起来“没死”,别被骗,确认端口释放后再起:
dsh --profile safe
profile 名为 safe 时 Ballute 自动进入安全模式:tab 顶部多出恢复区,列出目标 profile(默认 web)的全部第三方插件(包名 @版本 #rowId),每行可「体检」(静态 8 项)可「禁用」(写目标 profile 的用户补丁层,下次启动生效)。救完用正常方式重启主 profile 即可。
跨 profile API(safe 实例上):
- GET /v1/state 多返回 safeMode: true + recover: { target: "web", modules: [...] }
- GET /v1/inspect?module=&profile=web — 静态体检目标 profile 里的插件
- POST /v1/disable { "module": ..., "profile": "web" } — 跨 profile 禁用(runtimeEffect: "next-boot");守卫照常(基础设施/ballute 自身/名字格式全拦)
API(仅限本机同源)
- GET /api/ballute/v1/state — 自检状态 + 可体检的第三方模块清单
- GET /api/ballute/v1/inspect?module= — 体检已装插件(8 项检查:bundle 注册 id=包名 / exports.apply / exports.name / inject 服务键 / host 半边 / 补丁 name 守卫…)
- GET /api/ballute/v1/inspect?fixture= — 体检自带夹具:fault-load / fault-apply / fault-mismatch / fault-no-name
- POST /api/ballute/v1/disable { "module": "" } — 写用户补丁层停用(保护名单拦截基础设施行)
- POST /api/ballute/v1/crash — 崩溃遥测上报(client 自动调用):{ registrant, slotKey, entryId, message, stack, abdicated, at, count, rev } → 追加到 $DSH_HOME/ballute/crash-log.jsonl
- GET /api/ballute/v1/crashes?limit=20&plugin= — 崩溃历史(最新在前,每请求重读磁盘;超 600 条自动压实到最近 500)
黑匣子事件格式(schemaVersion: 1,字段版本化,供可视化插件等第三方消费):
json
{ "schemaVersion": 1, "at": 1786814000000, "receivedAt": 1786815667828,
"registrant": "crash-test-dummy", "slotKey": "shell.overlay", "entryId": null,
"message": "受控 render 崩溃…", "stack": "Error: …", "abdicated": true,
"count": 1, "rev": "a436f2444edf" }
rev = 崩溃时启动图内容哈希(window.__DSH_BOOT__.rev),可定位「哪个代码版本崩的」;abdicated: false 表示 chain 型(只上报不摘除)。
安装
dsh plugin add github:Zlyraz/dsh-ballute
维护状态:业余维护,响应可能较慢——欢迎 issue/PR,不承诺时效(AI 协作入口见 AGENTS.md)。
与 dsh-workshop 的配合
两个插件写同一份 cordis.patch.yml,不会互相踩——补丁写入工艺(原子写、串行队列、基础设施保护名单)本来就复用自 workshop。日常增删插件走 workshop;装完新插件可以用 ballute 体检一遍,真崩了就崩卡一键关闭,救不回来再进安全模式。
开发
dev profile 试装工作流(先隔离验证,再扶正)
1. 装进一次性 dev profile(与日常 web profile 隔离,炸了不影响主环境):
dsh plugin --profile dev add /path/to/dsh-ballute
2. 起独立实例验证(不同端口避免冲突;具体旗标以 dsh web --help 为准):
dsh web --profile dev --port 3081
打开 http://127.0.0.1:3081,检查:设置→插件 出现 Ballute tab;再装验收假人 crash-test-dummy 跑一遍崩卡流程。
3. 扶正:验过后再装进日常 profile:
dsh plugin --profile web add /path/to/dsh-ballute
4. 手动 link 方式(开发期改代码即生效,推荐):在 profiles/web/package.json 的 dependencies 加 "dsh-ballute": "link:/abs/path/to/dsh-ballute",dsh.profile.bundles 数组加 "dsh-ballute",然后 profile 目录内 pnpm install,重启 dsh web。
自测
curl 'http://127.0.0.1:3080/api/ballute/v1/inspect?fixture=fault-mismatch'
curl 'http://127.0.0.1:3080/api/ballute/v1/inspect?module=crash-test-dummy'
第二条需要先装验收假人:dsh plugin add github:Zlyraz/crash-test-dummy。
四个夹具各含一种契约违例(缺 client 文件 / 缺 exports.apply / 注册 id≠包名 / 缺 exports.name),体检应逐一报出且归因正确。
踩过的坑
- client bundle 一定要导出 name(= 包名)。cordis 的 fiber 名取自 exports.name,缺了的话崩溃归因会落到内部 fiber 上(面板里只会看到 x6 这种名字,看不出是谁崩的)。
- 手写 bundle 的话,__ModuleLoader__.load({ id }) 的 id 必须等于包名。
- cordis.patch.yml 初始是 [],直接追加会得到非法结构,先剥掉空数组再写;写入走原子写 + 串行队列。
许可
MIT(见 LICENSE)扫码进群