前言¶
用 DSH 跑长任务时,常见三个麻烦:会话列表里分不清哪个是哪条;进程停下来等人拍板时,那个「点」散在日志或输出里;以及你不在时,例行问题要么堆着要么被自动放过。下面介绍的 dsh-watchkeeper 就是针对这三点的插件。它把会话编号、人工待答、可插拔评审这三件事收到一个 watch 循环里,由 Maravetech 维护,归在 DSH 社区插件目录的「工作流」分类下。
这是什么¶
一句话定位:dsh-watchkeeper 是一个 DSH 插件,替你守着无人值守的会话——给每个会话一个稳定编号、把需要人拍板的 decision card 集中到一个待答视图、并允许用可插拔的 judge 代答例行问题。
开源、纯 JavaScript、无构建步骤。仓库标注 Alpha,版本 0.2.0,插件 API 和配置在 1.0 前可能变化。许可证 MIT。
先做下面的事:确认你的 Node 大于等于 22.5,确认 DSH 版本落在 engines.dsh 声明的范围内;不满足时 dsh plugin add 会直接拒绝安装。
三个能力¶
可以按三件事理解它做了什么。
会话编号¶
每个会话拿到一个稳定编号,显示在会话列表该行开头。编号从 1 递增,重启后会话仍保留原编号,只要 WATCHKEEPER_HOME 下的 ledger 没丢。
待答席¶
需要人决策的卡片会收集到一个位置。你答一次,答案回送到发起那张卡片的会话。插件的卡片是包裹在 [DECISION_POINT] 与 [/DECISION_POINT] 之间的 JSON,且必须放在代码围栏外面。
看护循环与可插拔 judge¶
watch 循环里配置的 judge 可以代答会话中途的例行提问。低置信度、输出损坏、红线话题始终转给人。
插件明确区分了默认行为:没有配置 judge 就等于没有任何自动决策卡应答;配置了 fallbackEnabled 也只是处理 judge 实际跑完后一小类不确定性结果,红线情况和 judge 不可用仍转给人。回复提供方默认也是关闭的。
安装¶
插件分两部分:插件(宿主行为)和 skill(agent 指令)。skill 只是解释插件,不装插件的话它不会做任何事。
插件¶
DSH 自己的插件命令已经转发到 profile 目录的 pnpm,并把插件注册为该 profile 的一个 bundle,所以不需要手工改 cordis.patch.yml。下面这行从 GitHub 安装并固定到 tag:
dsh plugin --profile <your-profile> add github:Maravetech/dsh-watchkeeper#v0.2.0
要在本地克隆开发时,克隆后按目录添加:
git clone https://github.com/Maravetech/dsh-watchkeeper.git
dsh plugin --profile <your-profile> add "file:$PWD/dsh-watchkeeper"
或者从 releases 下载 tarball,再 file: 安装:
dsh plugin --profile <your-profile> add ./dsh-watchkeeper-0.2.0.tgz
需要完全固定到某个 commit,可用 github:Maravetech/dsh-watchkeeper#<commit-sha> 代替 tag。插件不依赖构建产物,所以不需要额外的 allowBuilds 项。
卸载:
dsh plugin --profile <your-profile> remove dsh-watchkeeper
装完完全重启 DSH。
skill¶
插件已经带 skill,做一条符号链接放到 DSH 的 skills 目录:
ln -s "$DSH_PROFILE_DIR/node_modules/dsh-watchkeeper/skills/dsh-watchkeeper" "$DSH_HOME/skills/dsh-watchkeeper"
想给 Claude Code、Codex 等其他 agent 只装 skill,可以用 skills.sh 的 CLI(Node 22.20+):
npx skills add Maravetech/dsh-watchkeeper --skill dsh-watchkeeper -g
验证¶
先查健康端点确认插件加载正常:
curl -s "$DSH_WEB_URL/watchkeeper/health" | python3 -m json.tool
没有设 DSH_WEB_URL 时,用应用 URL 里的端口,例如 http://127.0.0.1:62630/watchkeeper/health。
配置¶
配置走环境变量。最重要的三个:
WATCHKEEPER_HOME # 默认 ~/.dsh-watchkeeper,存放状态、编号 ledger 和 SQLite 库
WATCHKEEPER_JUDGE_CMD # judge 命令;不设则所有提问都转给人
WATCHKEEPER_CONTROL_TOKEN # watch 控制 POST 路由的独立 bearer token;不设则这些路由不可用
还有回复提供方的二进制:WATCHKEEPER_CODEX_BIN、WATCHKEEPER_AGY_BIN、WATCHKEEPER_CUSTOM_CMD。完整的变量表、judge 契约、provider 命令见仓库 docs/configuration.md。
用 HTTP 控制接口时,写路由需要 WATCHKEEPER_CONTROL_TOKEN,否则返回 403;web host 必须使用字面量 loopback 地址。
典型用法:一张 decision card¶
卡片最小形态如下。要点是把 JSON 放在 [DECISION_POINT] 与 [/DECISION_POINT] 之间,且在代码围栏外:
{
"audience": "human",
"requires_user_response": true,
"human_review": [
{
"question_id": "q-1",
"question": "Ship with the current cover image or wait for the new one?",
"type": "卡点",
"reason": "The new image is not approved yet.",
"manual_reason": "必要信息",
"blocking_scope": "Publishing is blocked until this is answered.",
"attempts": ["Checked the asset folder; the new image is still missing."],
"background": "The current image is usable but older.",
"recommendation": "Ship with the current image.",
"options": ["Ship with the current image", "Wait for the new image"],
"state": "needs_user",
"audience": "human",
"requires_user_response": true,
"agent_can_resolve": false,
"already_resolved": false
}
]
}
字段规则、选项写法和常见错误在 docs/decision-cards.md。
出错时从哪查¶
先看健康端点,再看落盘状态,最后读插件日志:
curl -s "$DSH_WEB_URL/watchkeeper/health" | python3 -m json.tool
ls "$WATCHKEEPER_HOME"
ls "$WATCHKEEPER_HOME/state"
tail -n 50 "$WATCHKEEPER_HOME/probe.log"
如果卡片没出现,通常是卡片被放进了代码围栏、缺少 [DECISION_POINT] 包裹,或者缺了必需字段。
适用场景与注意¶
适合这类人:用 DSH 跑长任务或需要人值班的会话,希望会话有可追溯编号、决策点集中到一处,并且把例行问题交给可替换的 judge、把关键问题留给自己。
两点要先说清。其一,插件作为该 profile 的 bundle 在 DSH 进程内运行,等于以当前 DSH 进程的权限执行;装之前建议把源码读一遍(仓库是纯 JS、无构建步骤,可以直接读 index.js、lib/ 和 cordis.patch.yml),并确认许可证。其二,它面向的是无人值守场景,自动化程度由 judge 和 provider 配置决定;默认是「没有人就没有自动决策」,所以先按默认值跑,再逐步放开。
小结¶
dsh-watchkeeper 解决的是无人值守时的三件小事:会话可编号、决策点有去处、例行问题可代答、关键问题必停给人。源码与文档在 GitHub:https://github.com/Maravetech/dsh-watchkeeper,社区目录页:https://www.skillhub.cn/plugins/Maravetech/dsh-watchkeeper。