dsh-hooks-plugin:为 DeepSeek Harness 提供 Claude Code 风格 hooks

前言

在 DeepSeek Harness(DSH)里,很多流程需要挂在具体事件上:工具调用前拦截、工具调用后记录、用户提交时补检查、会话开始或结束时写状态。若这些逻辑散落在各个脚本里,后续排查和迁移都会比较麻烦。

dsh-hooks-plugin 提供 Claude Code 风格的 hooks:在智能体 / 工具生命周期事件上运行 shell 命令,配置来自 .dsh/hooks.json

这是什么

dsh-hooks-plugin 由 KYinCode 维护,采用 MIT 许可证。它为 DSH 增加一个 hooks 入口,让开发者在项目、预设或全局层面配置事件响应命令。

核心定位如下:

在 DSH 的 agent / tool 生命周期事件上运行 shell 命令;
配置使用 .dsh/hooks.json;
JSON 结构延续 Claude Code hooks 形状。

核心功能

四层配置

hooks 配置按目录生命周期管理,支持四层来源:

全局:~/.dsh/hooks.json
预设:<preset-dir>/hooks.json
项目:<项目根>/.dsh/hooks.json
项目本地:.dsh/hooks.local.json

项目配置改动后会自动重新加载,不需要重启。

v1 接线事件

v1 实际接线以下事件:

PreToolUse
PostToolUse
PostToolUseFailure
UserPromptSubmit
SessionStart
SessionEnd
Stop
SubagentEnd

其中 PreToolUse 支持通过 stdout 输出 deny 决策。deny 时会出现官方工具失败卡片,模型会看到类似这样的内容:

Error: <reason>

hook 类型与字段

v1 实现 commandhttp 型 hook;prompt / agent 型 hook v1 不做。

hook 公共字段包括:

if
timeout
statusMessage
once

command 型可配置:

command
shell
async
asyncRewake

http 型可配置:

url
headers
allowedEnvVars

配置结构使用 matcher[] + hooks[]

{
  "<Event>": [
    {
      "matcher": "<模式>",
      "hooks": []
    }
  ]
}

子代理触发

子代理默认会触发 hooks,输入载荷会携带:

agent_id
agent_type
delegation_depth

如果需要关闭子代理触发,可以配置:

{
  "subagents": false
}

热重载与热升级

项目配置改动会自动重新加载,无需重启。

如果安装了 dsh-hot-installer,升级插件后可以免重启当场生效:

dsh plugin --profile web add dsh-hooks-plugin@<新版本>

最近记录与日志

每条 hook 记录会写入最近记录文件:

recent.jsonl

默认限 200 条,可用环境变量调整:

DSH_HOOKS_RECENT_MAX

文件日志位于:

~/.dsh/logs/dsh-hooks/dsh-hooks.log

默认超过 1 MiB 自动滚动,可用环境变量调整:

DSH_HOOKS_MAX_LOG_BYTES

最近记录接口:

GET /dsh-hooks/recent

安装与启用

npm 安装:

dsh plugin --profile web add dsh-hooks-plugin

若使用本地 tarball,可先打包,再把生成的 tarball 交给 dsh 安装:

npm pack
dsh plugin --profile web add ./<npm pack 生成的 dsh-hooks-plugin tarball>

安装后新会话自动生效;已有存活会话也会生效。进程重启后继续旧会话,会随 agent 重建自动重新接线。

插件对运行环境有 peerDependencies 要求:

{
  "peerDependencies": {
    "@deepseek-ai/cordis": "^4.0.1",
    "@deepseek-ai/dsh-shell": "^0.1.0-rc.6",
    "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.6",
    "react": "^18.2.0"
  }
}

典型用法

在工具调用前触发命令

在项目根创建:

<项目根>/.dsh/hooks.json

示例配置如下:

{
  "PreToolUse": [
    {
      "matcher": "Read|Write|Edit",
      "hooks": [
        {
          "type": "command",
          "command": "echo hook triggered",
          "timeout": 5
        }
      ]
    }
  ]
}

这条配置会在 ReadWriteEdit 工具调用前运行:

echo hook triggered

用 PreToolUse 对私有路径 deny

示例中对 Read 事件配置条件过滤:

{
  "PreToolUse": [
    {
      "matcher": "Read",
      "hooks": [
        {
          "type": "command",
          "command": "node -e \"process.stdout.write(JSON.stringify({hookSpecificOutput:{hookEventName:'PreToolUse',permissionDecision:'deny',permissionDecisionReason:'blocked'}}))\"",
          "if": "Read(*private*)",
          "timeout": 5
        }
      ]
    }
  ]
}

Read 命中 *private* 条件时,hook 通过 stdout 输出 deny 决策。PreToolUse 决策 deny 时,会出现官方工具失败卡片,模型会看到 Error: <reason>

命令 hook 的 stdin / stdout

命令 hook 从 stdin 读取单行 JSON 输入。常见字段包括:

{
  "session_id": "...",
  "cwd": "...",
  "hook_event_name": "PreToolUse",
  "tool_name": "read",
  "tool_input": {
    "path": "..."
  },
  "tool_use_id": "..."
}

如果是子代理触发,还会包含:

{
  "agent_id": "...",
  "agent_type": "...",
  "delegation_depth": 0
}

命令 hook 通过 stdout 输出 JSON 决策。hookSpecificOutput 可包含:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "blocked",
    "additionalContext": "..."
  }
}

开发验证与查看

运行测试:

node --test test/

查看文件日志:

~/.dsh/logs/dsh-hooks/dsh-hooks.log

查看最近记录:

GET /dsh-hooks/recent

安装后可以先加载自动注册技能:

skill dsh-hooks-authoring

深度配置查看安装包内文档:

docs/CONFIGURATION.md

适用场景与注意

适合以下场景:

在工具调用前做拦截或检查;
在工具调用后做审计、记录或后续动作;
在会话开始、结束、用户提交等事件上运行固定流程;
为项目、预设或全局配置不同层级的 hooks;
在 DSH 中保持 Claude Code hooks 风格的 JSON 配置体验。

需要注意:

hooks 会执行 shell 命令,会以当前 dsh 进程权限运行;
安装前应检查源码与 MIT 许可证;
配置的生命周期等于它所在目录的生命周期;
若某预设报 Cannot find package,通常需手动移除对应行或删除预设目录;
v1 不做 prompt / agent 型 hook;
parseHookConfig 会拒绝未知类型;
不做卸载生命周期、悬空行提醒、会话级配置档、PreCompact / PostCompact、设置页;
不注入 CLAUDE_PROJECT_DIR、CLAUDE_PLUGIN_ROOT 等 CC 专属环境变量;
不做 ${CLAUDE_PLUGIN_ROOT}、CLAUDE_PLUGIN_OPTION_*、CLAUDE_ENV_FILE 等机制。

DSH 内部决策直接消费 waterfall 返回值。stdout JSON 是命令 hook 表达决策的协议手段,不是按 Claude Code 输出解析。

链接

社区目录页(独立站点,不等同于 DeepSeek 或幻方的官方应用商店):

https://www.skillhub.cn/plugins/KYinCode/dsh-hooks-plugin

GitHub:

https://github.com/KYinCode/dsh-hooks-plugin
羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜