🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

崩溃守护与自动恢复 ddtcorex/dsh-maestro-core

DeepSeek Harnessv0.12.0
ddtcorex7 天前有提交已提供中文文档扫描:高危

DSH Web 韧性守护程序 —— 阶段 1 守护与报告 + 阶段 3 自动恢复与自动重载 ——…

31.4/100
综合分
2
GitHub 星标
390
npm 周下载
—/5
用户评分

数据截至 2026/10/29 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add @ddtcorex/dsh-maestro-core
npm 源 · @ddtcorex/dsh-maestro-core 的发布者账号已校验与本仓库一致

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · market
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.2 下真实安装成功(非静态推断);本次验证针对插件 v0.13.0,当前版本为 v0.12.0
L5 · 运行时冒烟等级说明 →
数据截至 2026/10/28·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 7 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安装兼容性检查✓ 自动检查通过
展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包@ddtcorex/dsh-maestro-core @ 0.12.0
✓Node 引擎要求 ^22.19.0 || >=24.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/13 09:40:50

🔴 安全扫描发现高危能力自动 · 静态分析源码
v2.7.0
🔴 扫描:高危尚无人工评估

静态扫描发现安装期即执行代码,或命令参数由运行时变量拼接(参数来源无法静态判定,从严处理)。

命令参数由运行时变量拼接读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
扫描于 2026/11/4(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
涉及外部主机:api.telegram.org

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-llm@deepseek-ai/dsh-tools
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 自动检测崩溃
  • 回滚至LKG
  • 崩溃上报

DSH Web 守护进程,自动检测崩溃、回滚到 LKG 并上报

v0.14.02026-10-28
· 变更 · 破坏性变更:systemd 模板改为运行打包好的 dsh 运行时。scripts/install-systemd.sh 现在安装的 dsh-web.service 用 node "$DSH_BIN" web --no-open 启动,其中 DSH_BIN=~/.local/share/dsh/current/bin/dsh,WorkingDirectory=~/.local/share/dsh,不再通过 tsx 启动 deepseek-harness 源码检出。运行安装脚本前,先把 @deepseek-ai/dsh 安装到 ~/.local/share/dsh/ 下并链接 current。supervisor 单元传入同样的 DSH_BIN。工作目录里没有 .env,否则 dsh 会把它当作项目环境层加载。 · restart-dsh-web.sh 不再需要 --repo:systemd 托管的单元不需要源码检出,没有 systemd 时该脚本直接启动 DSH_BIN。--repo / DSH_REPO 保留为源码启动的兜底方式。 · 修复 · 所有启动 dsh web 的路径在设置了 DSH_BIN 时都走 DSH_BIN(resolveDshLaunch):dsh_web_restart / dsh_web_dryboot 门禁、dsh_web_gc 孤儿指纹、daemon nohup 兜底和 debug-agent 试启动。此前它们总是启动源码检出,因此在打包环境里,门禁校验的是主机并不运行的代码。未设置 DSH_BIN 时,源码启动方式不变。 · 变更内容 · fix(supervisor):从打包运行时启动并重启 dsh · chore(release):0.14.0 完整变更日志:
v0.13.02026-10-21
· 已移除 · 最后已知良好快照和崩溃回滚都没了。守护进程不再写入 ~/.dsh/.supervisor/lkg/ 快照,崩溃时也不再恢复文件——启动失败会通过崩溃报告(reports/report-.md)暴露,不再自动恢复。健康轮询、崩溃重启、Telegram 通知、会话自动恢复和调试智能体照常运行。dsh_web_restart 校验现在一律试启动,因为没有快照基线可比对。 · 变更内容 · feat(supervisor):移除 LKG 快照和崩溃回滚 · chore(release):0.13.0 完整变更日志:
v0.12.12026-10-20
· 已移除 · 守卫不再把 maestro_read_file 和 maestro_write_file 列为文件工具。单体架构退役后,没有插件再注册这两个名字;通用的 read_file、write_file、fs_read 和 fs_write 仍保留覆盖。 · 变更内容 · docs(core):修复 rules-audit 发现的问题 · chore:跟进 maestro-reviewer 重命名 · test(config):从 meta 根目录读取 maestro-reviewer · test(core):从 dsh-maestro-review 读取审查客户端 · refactor(guard):移除已退役的 maestro 文件工具名 · chore(release):0.12.1 完整变更日志:
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。

README

由 DeepSeek 最新模型翻译生成
dsh-maestro-core DSH Web 韧性守护程序 —— 阶段 1 守护与报告 + 阶段 3 自动恢复与自动重载 —— 连同设置存储、Maestro 设置卡片、工具守卫,以及原先拆成四个独立包的 harness 间同步引擎。 它运行在 pnpm → sh → node 进程树之外(systemd 守护进程),进程树崩溃时仍能存活;同时以宿主+客户端 Cordis 插件的形式运行在 dsh web 之内,负责自动恢复中断的会话,并在重启后自动重载浏览器。 - 守护进程: 每 3s 轮询 :3080,崩溃后重启(debounce 60s,flock 锁),写出 report-<ts>.md(健康状态 + git diff + 日志尾部),并通过 Telegram 通知(宽松发送,绝不阻塞)。
展开完整文档(README 剩余 1 节)
dsh-maestro-core

DSH Web 韧性守护程序 —— 阶段 1 守护与报告 + 阶段 3 自动恢复与自动重载 —— 连同设置存储、Maestro 设置卡片、工具守卫,以及原先拆成四个独立包的 harness 间同步引擎。

它运行在 pnpm → sh → node 进程树之外(systemd 守护进程),进程树崩溃时仍能存活;同时以宿主+客户端 Cordis 插件的形式运行在 dsh web 之内,负责自动恢复中断的会话,并在重启后自动重载浏览器。

- 守护进程: 每 3s 轮询 :3080,崩溃后重启(debounce 60s,flock 锁),写出 report-<ts>.md(健康状态 + git diff + 日志尾部),并通过 Telegram 通知(宽松发送,绝不阻塞)。
- 宿主插件: 启动 8s 后执行 runAutoResume() —— 在 autoResumeWithin(默认 5m)内,用 findInterrupted(尾部 100 条)+ findDanglingOpenTurns(全量扫描近期会话)找出中断会话 → 从 request/context 恢复出 agents.resume({resumeSessionId, agentOptions: {provider,model}}) → followup('continue')。回环 RPC POST /dsh-maestro-supervisor-resume/{scan,resume}(可从回环访问;connection.isLoopback 会报告这一点)供守护进程使用(resumeViaRpc)。
- 客户端插件: 混合式自动重载 —— 在 offline/WebSocket close/visibilitychange 时每秒轮询 fetch HEAD / → 返回 200 → location.reload()。通过 dsh.client 以 window.__ModuleLoader__.load bundle 的形式在 /plugins/@ddtcorex/dsh-maestro-core/client.js 提供。

模块

一个包,四行宿主模块和一个客户端 bundle。

| 模块 | 源码 | 行 id | 通道 | 作用 |
| Supervisor | src/host/.ts | maestro-supervisor | /dsh-maestro-supervisor-resume(可从回环访问) | 崩溃轮询、崩溃后重启、自动恢复、自动重载 |
| Store | src/host/store/ | — | — | 带命名空间的 settings.json,其他模块都读写它 |
| Config | src/host/config/ | maestro-config | /dsh-maestro-config | 基于存储的 maestroConfig 服务,为 Maestro 设置卡片提供数据 |
| Guard | src/host/guard/ | dsh-maestro-guard | /dsh-maestro-guard | 规则分类、审批闸门及其日志 |
| Sync | src/host/sync/ | dsh-maestro-sync | /dsh-maestro-sync | 备份、恢复、保留期 GC 和双机同步 |

被并入模块的行 name 是本包的子路径(@ddtcorex/dsh-maestro-core/lib/<module>/index.js),这也是 exports["./lib/"] 存在的原因:exports 映射解析不了的行名会在启动时被静默跳过。

存储也可以单独发布(@ddtcorex/dsh-maestro-core/store),并用 scripts/vendor-store.mjs 内联到使用方,该脚本会写出一个带正文哈希、可自校验的文件。

已注册工具

用 ctx.tools.register 注册的宿主工具:

| 工具 | 模块 | 作用 |
| dsh_web_restart | supervisor | 安排一次受监督的 dsh web 重启(需经同意) |
| dsh_web_restart_status | supervisor | 报告最近一次重启请求的状态 |
| dsh_web_dryboot | supervisor | 在临时端口上做 dry-boot,使用隔离的 DSH_HOME |
| dsh_web_gc | supervisor | 先预览,再清理已验证的 dry-boot 孤儿进程 |
| maestro_session_health | supervisor | 会话日志健康扫描(重新编码或隔离) |
| maestro_resume_tool_health | supervisor | 恢复会话的工具视图健康检查 |
| maestro_repair_session_preset | supervisor | 重新关联未加入任何预设的智能体 |
| maestro_guard_status、maestro_guard_stats、maestro_full_scan | guard | 防护状态、计数器和全量规则扫描 |
| maestro_sync_status、maestro_sync_check_machines、maestro_sync_preview、maestro_sync_apply、maestro_sync_bidirectional_preview、maestro_sync_bidirectional_apply、maestro_sync_tunnel_restore | sync | 双机同步,先预览 |
| maestro_backup_preview、maestro_backup_apply、maestro_backup_gc_preview、maestro_backup_gc_apply、maestro_restore_preview、maestro_restore_apply | sync | 备份、保留期 GC 和恢复,先预览 |

环境要求

- Node.js ^22.19.0 || >=24.0.0 和 pnpm 11+。默认使用 Node 20 的 shell 会报 No such built-in module: node:sqlite;运行 dsh 或 pnpm 之前,先把 Node 22 的 bin 放到 PATH 最前面。
- DSH 0.1.x 或 0.2.x(peer 范围 <0.3.0-0)。

安装

一个包,一条命令:

dsh plugin --profile web add @ddtcorex/dsh-maestro-core

包自带 cordis.patch.yml,会自动应用。其中有一条 connection 条目声明了 webServer,DSH 0.2.x 需要它才能让 rpc.handle 注册通道。不要把它复制进配置档补丁,也不要手动添加这些行(id 重复会让加载器崩溃)。安装后重启 dsh web。

想拿到确切的版本,而不是包管理器解析出来的版本,就锁定版本:dsh plugin --profile web add @ddtcorex/dsh-maestro-core@<version>。

用 link: 从本地检出安装?每次 git pull 之后,运行 pnpm install && pnpm build(lib/ 已被 gitignore),然后重启 dsh web。

在工作区检出里,改用构建加链接:

pnpm --dir packages/dsh-maestro-core install
pnpm --dir packages/dsh-maestro-core build # tsc host + tsc client + esbuild bundle -> lib/ + lib/client.js
pnpm --dir packages/dsh-maestro-core verify # tsc --noEmit host + client
pnpm --dir packages/dsh-maestro-core test # vitest run
test -f packages/dsh-maestro-core/lib/index.js
test -f packages/dsh-maestro-core/lib/client.js
link:() the checkout into ~/.dsh/profiles/web/package.json, then
pnpm --dir ~/.dsh/profiles/web install

改动任何 src/ 之后都必须运行 pnpm build;lib/ 是 gitignore 的构建产物。客户端需要两步 tsc 加上 build-client.mjs 打包——只跑 tsc 会让 lib/client.js 变成裸 ES 模块,dsh web 会报 exports no "./client" bundle。
包内声明了 dsh.client(platform: web,inject: ["@deepseek-ai/dsh-client-connection", "@deepseek-ai/dsh-client-ui-slots"]),浏览器端会自动加载,不需要额外加 dsh.client 标志。

预检(必做): 把包加进运行中配置档的 bundles 之前,dry-boot 必须通过:

DSH_HOME=$(mktemp -d) "$DSH_BIN" web --port 0 &
wait for "dsh web: http://127.0.0.1:<port>" and curl 200, then kill
This catches load-time failures (missing lib/index.js, stale build, bad cordis.patch.yml)
that no in-code try/catch can catch. See dsh-safe-restart skill.

2026-08-27 的 dsh web 故障就是这一类失败(缺 lib/index.js)。参见 AGENTS.md 的 Conventions。

Systemd 守护进程(可选,用于在代码树之外检测崩溃)

bash packages/dsh-maestro-core/scripts/install-systemd.sh
systemctl --user daemon-reload
systemctl --user enable --now dsh-web-supervisor
systemctl --user status dsh-web-supervisor
journalctl --user -u dsh-web-supervisor -f

模板里 Environment=TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID 是注释掉的。想接 Telegram,就用 systemctl --user edit dsh-web-supervisor 取消注释;否则只写日志。

不用 systemd 直接跑(前台,调试用):

node packages/dsh-maestro-core/lib/index.js daemon # poll every 3s
node packages/dsh-maestro-core/lib/index.js status
node packages/dsh-maestro-core/lib/index.js resume --within 5m # list interrupted sessions

配置

autoResumeWithin 写成 number 时单位是分钟(例如 5 → 5 分钟)。字符串支持 30s/5m/1h。优先级从高到低:

1. Cordis 配置(cordis.patch.yml 的 config: 或 apply(ctx, config))—— 针对单次安装显式指定。
2. 环境变量 DSH_SUPERVISOR_AUTO_RESUME / DSH_SUPERVISOR_RESUME_WITHIN(环境变量里裸写 5 按 5m 处理,方便使用)。
3. Supervisor 配置 ~/.dsh/.supervisor/config.json(autoResumeEnabled、autoResumeWithin)。
4. Maestro 设置 ~/.dsh/dsh-maestro-config/settings.json(domains.supervisor.)。
5. 默认值: true / 5。

| 键 | 类型 | 默认值 | 环境变量 | 文件 | 说明 |
| autoResumeEnabled | boolean | true | DSH_SUPERVISOR_AUTO_RESUME(1/true/yes/on/enabled 对 0/false/no/…) | config.json: autoResumeEnabled、settings.json: domains.supervisor.autoResumeEnabled | false → 只通知 |
| autoResumeWithin | number(分钟)或 string(5m) | 5 | DSH_SUPERVISOR_RESUME_WITHIN | config.json: autoResumeWithin、settings.json: domains.supervisor.autoResumeWithin | findInterrupted/findDangling 的时间窗口(mtime + event.time) |

~/.dsh/.supervisor/config.json 示例:

{
"autoResumeWithin": 5,
"autoResumeEnabled": true
}

命令行

node packages/dsh-maestro-core/lib/index.js --help
node packages/dsh-maestro-core/lib/index.js status
node packages/dsh-maestro-core/lib/index.js daemon # poll 3s, debounce 60s
node packages/dsh-maestro-core/lib/index.js resume [--within <dur>] # list interrupted sessions, e.g. 5m, 30s, 1h
node packages/dsh-maestro-core/lib/index.js boot-guard acquire|release --pid <pid> # boot.lock + boot-boundary, used by the safe-restart script

命令行没有 logs 和 rollback 命令:回滚在守护进程内部执行,报告是文件,放在 ~/.dsh/.supervisor/reports/ 下。

RPC(可从回环地址访问,connection.isLoopback) bash

Scan (findInterrupted only, tail 100)

curl -s http://127.0.0.1:3080/dsh-maestro-supervisor-resume/scan -X POST \
-H 'content-type: application/json' \
-d '{"type":"client-request","rpcId":"r1","method":"scan","payload":{"withinMs":300000}}'

→ {"type":"server-response","rpcId":"r1","result":{"ok":true,"value":{"scanned":425,"interrupted":[]}}}

Resume (re-attaches agent + followup continue, recovers provider/model)

curl -s http://127.0.0.1:3080/dsh-maestro-supervisor-resume/resume -X POST \
-H 'content-type: application/json' \
-d '{"type":"client-request","rpcId":"r2","method":"resume","payload":{"ids":["--example-project--/session-abc"]}}'

→ {"type":"server-response","rpcId":"r2","result":{"ok":true,"value":{"resumed":["--example-project--/session-abc"]}}}

or {"ok":false,"error":{"code":"bad-request","message":"resume requires at least one session id"}}

守护进程调用 resumeViaRpc()(supervisor.ts),把同样的信封 POST 到 http://127.0.0.1:3080/dsh-maestro-supervisor-resume/resume,用 fetch 发送,并校验 server-response + rpcId + result.ok。

自动恢复细节

- 时机: apply() 在启动后设置 setTimeout 8000,然后执行 runAutoResume()——只有刚启动完、dsh web 是唯一所有者时才安全(此时发现的未结束轮次不可能属于仍在运行的生成)。resumeInterrupted 还会检查 agents.get(sessionId),如果会话已经活着就跳过。
- 做什么: findInterrupted(tail 100,查找 time 落在窗口内、reason.kind === 'interrupted' 的 turn/end)+ findDanglingOpenTurns(全量扫描近期会话,查找 time 落在窗口内、没有匹配 turn/end 的 turn/start)→ merged = Set([...interrupted, ...dangling]) → 对每个 id 执行 resumeInterrupted。
- 怎么做: agents.get(sessionId) 如果活着 → followup('continue');否则 sessionPersistence.load(sessionId) → 找到带 provider/model 的 request/context → agents.resume({resumeSessionId, agentOptions}) → followup('continue')。如果 load 失败,仍然恢复,只是不带 agentOptions(降级)。返回 string[] resumed,并记录 sent continue trigger。
- 子代理: findDangling 对近期会话做全量日志扫描(mtime 落在窗口内,1-2 个文件),不用 tail。原因是子代理 b6487e33 唯一的 turn/start 在 seq 6,位于 1906 行日志的最开头,tail -100 会漏掉。findInterrupted 仍用 tail 100(中断的 closer 总在尾部)。mtime 预筛选让全量扫描的开销可控(此前没有预筛选时,425 个会话要 5.5s)。

自动重载细节(混合方案)

- 客户端(src/client/auto-reload.ts,lib/client.js 经 window.__ModuleLoader__.load 加载):ctx.effect 挂接 WebSocket(改写 window.WebSocket,捕获同源 DSH ws 的 close)、offline/online、visibilitychange → 断线时 setInterval(fetch HEAD / 1s) → 返回 200 → location.reload()(只执行一次,由 reloading 守卫)。加载时也会检查 HEAD /,以防页面在断线期间被打开。
- 宿主(supervisor.ts 的 pollHealth 3s + notify,plugin.ts 的 runAutoResume):健康检查 + 重启 + 通知是宿主这一半;配合客户端轮询,手动重启、supervisor 重启、systemd 重启都能覆盖,不用按 F5。不需要额外的宿主推送通道——客户端轮询是主路径,宿主健康检查是辅助;window.__ModuleLoader__ bundle 由 ClientModuleRegistry 在 /plugins/@ddtcorex/dsh-maestro-core/client.js 提供(dsh.client + exports["./client"])。

验证 bash

Build & unit

pnpm --dir packages/dsh-maestro-core verify # host + client
pnpm --dir packages/dsh-maestro-core test # vitest run
test -f packages/dsh-maestro-core/lib/index.js
test -f packages/dsh-maestro-core/lib/client.js
curl -s http://127.0.0.1:3080/plugins/@ddtcorex/dsh-maestro-core/client.js | grep -c "window.location.reload" # 2

Live

curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3080/ # 200
curl -s http://127.0.0.1:3080/dsh-maestro-supervisor-resume/scan -X POST -H 'content-type: application/json' -d '{"type":"client-request","rpcId":"t","method":"scan","payload":{"withinMs":300000}}' | head -c 200
node --input-type=module -e "import {findDanglingOpenTurns} from './packages/dsh-maestro-core/lib/resume.js'; console.log(await findDanglingOpenTurns(undefined,{withinMs:5601000}))"

Create a real dangling: "$DSH_BIN" --profile headless "Run bash synchronously sleep 60" & sleep 4; kill $!; node -e "...findDangling..." # should be 1

After restart, it should have turn/end interrupted → continue → turn2

故障排查

| 现象 | 原因 | 修复 |
| Cannot find package '.../dsh-maestro-core/index.js' | 没跑 pnpm build,或 lib/ 是旧产物 | pnpm --dir packages/dsh-maestro-core build && pnpm --dir ~/.dsh/profiles/web install |
| exports no "./client" bundle / client bundle not found | 缺 lib/client.js 或 exports["./client"] | pnpm build(会跑 tsc + tsc -p tsconfig.client.json + node scripts/build-client.mjs),检查 package.json 的 exports 和 dsh.client,test -f lib/client.js,curl .../client.js |
| dsh web 固定端口报 EADDRINUSE | 上一个 dsh web 仍占着监听树::3080(LAN 代理)、:3081(公网代理)、:3082(裸 webserver);:3000 未绑定 | ss -tlnp | grep -E ':308[012]' → 拿到 pid,把重启交给人工处理,或用 dsh_web_restart;绝不要自己杀掉活跃会话的进程,也绝不要 pkill -f "dsh web",它会杀掉发起调用的 shell。 |
| uses .jsonl but backend is zstd | 手写了 session.jsonl,但后端是 zstd | 用 zstd -c plain.jsonl > session.jsonl.zstd 或 JsonlSessionPersistence API。绝不要手写相反的编码——listArtifacts 在启动时会检查每个项目目录,一个多余文件就会阻塞整个 dsh web。 |
| first frame is not exactly one header line | zstd 缺少 type: session 头 | 按 encodeMaterialization 的写法,用 toHeaderLine + compressZstdFrame(header) + compressZstdFrame(body)。 |
| findDangling 返回 0,但子代理仍未关闭 | 尾部窗口太小(63b7719 之前) | 已修复:findDangling 现在会全量扫描近期会话(mtime 在窗口内)。findInterrupted 仍只扫尾部 100 行。 |
| resumed: [] 或 RESUME FAILED | agents.resume 失败(没有持久化,或缺少 provider/model) | 检查 session.jsonl.zstd 是否存在,以及 zstd -d -c ... \| head -n 1 是否为合法头。带 provider/model 的 request/context 会被恢复——若缺失,仍会在没有 agentOptions 的情况下恢复。 |
| RESUME SKIPPED | autoResumeWithin 窗口内没有会话 | 把 autoResumeWithin 调大到 10/"10m",检查 config.json 和 DSH_SUPERVISOR_RESUME_WITHIN,用 withinMs: 60601000 验证。 |
| 重启后页面不刷新 | lib/client.js 未提供,或浏览器缓存 | curl .../client.js | grep -c "window.location.reload" → 2,强制刷新 Ctrl+Shift+R,在控制台检查 window.__ModuleLoader__。客户端在 offline/WS close 时每秒轮询一次 HEAD /。 |
| 发现 dangling,但 agents.get 显示仍存活 | 会话在当前进程里仍存活(不是崩溃) | 只有在刚启动、dsh web 是唯一占用者时,findDangling 才安全。resumeInterrupted 在 agents.get 存活时会跳过——这是对的,等下次启动。 |

已知问题

- 手写 session.jsonl 与 zstd 冲突: ~/.dsh/sessions/ 下只要有一个编码相反的多余文件,每次启动都会阻塞整个 workspace 的 listArtifacts(encodingMismatch)。见「故障排查」。
- 尾部扫描与全量扫描: 63b7719 之前,b6487e33 子代理会被漏掉,因为它唯一的 turn/start 位于 1906 行日志最开头的 seq 6。已修复,但如果你新增扫描变体,请复用带 mtime 预过滤的 readSessionAllLines。
- 端口映射: :3080 是 LAN 代理(PIN 登录),:3081 是公网代理,:3082 是裸 dsh web webserver;:3000 未绑定。用 ss -tlnp 查看;绝不要 pkill -f "dsh web"。
- 客户端打包: lib/client.js 必须由 scripts/build-client.mjs 生成 window.__ModuleLoader__.load 包装,不能直接写 export。新增客户端文件放到 src/client/ 下,并确认 tsconfig.client.json 已包含这些文件,然后执行 pnpm build。
- 配置优先级: cordis.patch.yml 的 config: > 环境变量(DSH_SUPERVISOR_RESUME_WITHIN 裸写 5 → 5m)> config.json > settings.json > 默认值。参见 plugin.ts 和 supervisor.ts 中的 getAutoResumeEnabled() 与 getResumeWithinMs()。

开发 sh
pnpm --dir packages/dsh-maestro-core verify
pnpm --dir packages/dsh-maestro-core test
pnpm --dir packages/dsh-maestro-core build

改动守护进程后:DSH_HOME=$(mktemp -d) "$DSH_BIN" web --port 0 + 破坏 settings.json → 断言 report + rollback。

Telegram

默认宽松:notifier.ts 先尝试 import('@ddtcorex/dsh-maestro-notifier'),再读 TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID 环境变量,最后走 console.log。启用方式:systemctl --user edit dsh-web-supervisor → 取消注释 Environment=TELEGRAM_ → daemon-reload + restart。

硬模式(可选):package.json 加 "@ddtcorex/dsh-maestro-notifier": "workspace:^0.1.0" + pnpm-workspace.yaml 的 packages: ["../dsh-maestro-notifier"] → pnpm install 完成链接。

另见

- 规范:<workspace-root>/docs/specs/2026-09-13-supervisor-restart-resilience-design.md
- 技能:skills/dsh-safe-restart/(restart-dsh-web.sh,含 dry_boot_and_verify() 和 --auto)
- 客户端打包:dsh-maestro-mobile(scripts/build-client.mjs 模式)
预览分享卡片长什么样 ↓ddtcorex/dsh-maestro-core
分享 · DeepSeek Harness Hub
ddtcorex/dsh-maestro-core

DSH Web 韧性守护程序 —— 阶段 1 守护与报告 + 阶段 3 自动恢复与自动重载 ——…

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部