hooks-adapter:讓現有 hooks 配置在 DSH 上繼續生效的兼容層

前言

寫 hooks 是 agent 工作流裏最常見的定製手段:工具執行前攔截危險命令、任務結束時發通知、會話啓動時注入上下文。如果你在 Claude Code、Codex 或 opencode 裏寫過這類聲明,切到 DeepSeek Harness(dsh)時會遇到一個現實問題——這些配置跟着原 harness 的格式走,dsh 不能直接識別,要麼重寫一遍,要麼在幾套配置之間手動同步。

下面介紹的 hooks-adapter 處理的就是這個問題:它讀取已有的 hooks 配置文件,把各家的事件映射到 dsh 擴展點上,原有聲明不做改寫,就能在 dsh 裏繼續跑。

這是什麼

hooks-adapter(v0.1.0,MIT 許可證,作者 JohnXuXianyu22786)定位是通用的 hooks 兼容層:讀取 .claude/settings.json、.codex/hooks.json、opencode.json 的 hooks 部分,以及原生配置(~/.config/hooks-adapter/hooks.json、<project>/.dsh-hooks.json),把各 harness 的生命週期事件映射爲規範事件(如 session:start、tool:before),再綁定到 dsh 擴展點(如 agent/session-start、tools/pre-execute),並以 shell、webhook、oracle、proxy 四種 handler 執行。

幾個設計決策值得先說清楚:

  • 配置只讀、不遷移:現有 hooks 聲明保持不變。
  • 零運行時依賴:要求 Node >= 18,純 ESM + JSDoc 類型。
  • 失敗不阻塞啓動:缺失的配置文件靜默跳過;已有文件有問題時只產生診斷(diagnostics),絕不阻塞 dsh 啓動。

核心功能

配置來源與發現

插件按固定順序自動發現併合並 9 個配置文件位置(全局 / 項目 / 本地):

順序 文件 方言
1 ~/.claude/settings.json claude
2 ~/.codex/hooks.json codex
3 ~/.config/opencode/opencode.json opencode
4 ~/.config/hooks-adapter/hooks.json native
5 <project>/.claude/settings.json claude
6 <project>/.codex/hooks.json codex
7 <project>/opencode.json opencode
8 <project>/.dsh-hooks.json native
9 <project>/.claude/settings.local.json claude

合併規則:同名事件由後讀的文件追加組;disableAllHooks 遵循最具體的文件。兩個環境變量可以改變行爲:HOOKS_ADAPTER_CONFIG(同 --config)與 HOOKS_ADAPTER_HOME(同 --home)。配置文件必須是嚴格 JSON,不允許註釋。

四種 handler

配置裏的 type 字段沿用各 harness 的習慣寫法,內部歸一化爲四種 kind:

配置 type 內部 kind 行爲 默認超時
command shell 啓動 shell 進程,從 stdin 喂入 JSON 契約 600s
http webhook POST JSON 到 URL,響應體作爲 decision 600s
prompt oracle 調用 LLM 端點評估,{ok:false} 表示拒絕 30s
agent / subagent proxy 委託給子代理運行器(命令可配置) 60s

超時控制與失敗降級策略內建;validate 子命令提供友好的配置校驗。

事件映射與攔截行爲

各 harness 的事件名先映射爲規範事件,再綁定到 dsh 擴展點:

規範事件 claude codex opencode dsh 擴展點
session:start SessionStart SessionStart session.created agent/session-start
session:end SessionEnd SessionEnd session.deleted session/disposed
prompt:submit UserPromptSubmit UserPromptSubmit chat.message agent/pre-step
tool:before PreToolUse PreToolUse tool.execute.before tools/pre-execute
tool:after PostToolUse / PostToolUseFailure PostToolUse tool.execute.after tools/post-execute
turn:stop Stop Stop session.idle agent/turn-stopping
subagent:start SubagentStart SubagentStart tool.execute.before.subagent subagent/start
subagent:end SubagentStop SubagentStop tool.execute.after.subagent subagent/end
notice Notification Notification notification manual / stdio
compact:before PreCompact — experimental.session.compacting manual / stdio

行爲上的關鍵點:

  • PreToolUse 是攔截點:handler 退出碼 2,或返回 JSON decision: "block",會阻止工具調用(或轉爲人工確認)。
  • PostToolUse / PostToolUseFailure(互斥觸發)可拒絕寫回作爲結果反饋,或附加上下文。
  • UserPromptSubmit / SessionStart / Stop / SubagentStart / SubagentStop / SessionEnd 可注入上下文、拒絕提示、強制模型繼續。
  • Notification 與 PreCompact(opencode 方言對應 compact:before)僅支持 manual / stdio 觸發。

三種集成模式

  1. dsh 插件(Cordis apply):推薦方式,裝完自動生效。
  2. stdio JSON-lines 協議:任意 host 可接入。
  3. 一次性 CLI:validate、run、dump、list。

安裝與啓用

從 GitHub 倉庫安裝:

dsh plugin --profile demo add github:JohnXuXianyu22786/hooks-adapter

這個包是一個 dsh bundle(dsh.bundle.patch → cordis.patch.yml),添加後會插入插件樹。之後啓動 dsh:

dsh --profile demo

插件會自動發現項目目錄和用戶目錄下的 hooks 配置。也可以從本地 checkout 目錄安裝:

dsh plugin --profile demo add ./hooks-adapter
dsh --profile demo

卸載用:

dsh plugin --profile demo remove hooks-adapter

典型用法

沿用現有 hooks 聲明

假設你在 .claude/settings.json 裏已經有這樣的聲明:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "guard.sh", "timeout": 10 }
        ]
      }
    ],
    "Stop": [
      { "hooks": [ { "type": "command", "command": "notify-send done" } ] }
    ]
  }
}

含義:Bash 工具執行前先跑 guard.sh(超時 10 秒),可通過退出碼攔截;每次 Stop 事件觸發 notify-send done。裝好插件後這份配置不用改,dsh 下次運行時自動生效。

覆蓋插件配置

需要調整行爲時,在 profile 的 cordis.patch.yml 中 replace id: hooks-adapter:

- replace:
    - id: hooks-adapter
      config:
        configPath: /abs/path/to/hooks.json   # 固定單個文件,跳過發現
        discover: false
        llm: { baseUrl: "https://api.example.com/v1", model: "eval-small" }
        proxy: { command: "dsh run --quiet" }

configPath 固定單個配置文件並跳過自動發現;discover: false 關閉發現;llm 配置 oracle handler 使用的 LLM 端點;proxy 配置 proxy handler 委託的子代理運行器命令。

stdio 協議與一次性 CLI

想在 dsh 之外的宿主程序裏複用同一套 hooks 執行器,走 stdio JSON-lines 協議:

echo '{"op":"ping"}' | node lib/index.js listen --config hooks.json
echo '{"op":"dispatch","event":"PreToolUse","payload":{"tool_name":"Bash","tool_input":{}}}' | node lib/index.js listen

調試和檢查用一次性 CLI。先做校驗,再看合併結果,是比較穩的順序:

node lib/index.js validate            # 校驗所有可發現的配置,退出碼 0/1
node lib/index.js run --event PreToolUse --payload payload.json
node lib/index.js dump                # 打印合並後的生效配置
node lib/index.js list                # 列出發現的配置文件

經過上面的步驟,配置是否被正確發現、事件是否按預期觸發,都可以在不啓動完整 dsh 會話的情況下確認。更多格式細節見倉庫的 docs/ 與 examples/ 目錄。

適用場景與注意

適合的場景:

  • 從 Claude Code / Codex / opencode 遷到 dsh,已有的 hooks 邏輯想原樣複用。
  • 多個 harness 並行使用,希望維護一份 hooks 聲明而不是幾份。
  • 想把 hooks 執行器嵌進自己的宿主程序(stdio 協議)。

使用前注意:

  • 需要 Node >= 18;配置文件必須爲嚴格 JSON,不允許註釋。
  • opencode 方言的 Notification 與 PreCompact 僅支持 manual / stdio 觸發。
  • 安全方面:插件以當前 dsh 進程的權限運行,hooks 裏聲明的命令、webhook 和 LLM 調用也在這個權限範圍內執行。安裝任何第三方插件前,建議通讀源碼並確認許可證(本項目爲 MIT)。

結尾

hooks-adapter 做的事情不復雜:把各家 harness 的 hooks 聲明翻譯成 dsh 能執行的事件綁定,配置只讀不改寫,裝上即用,卸掉即回。對從其他 harness 遷移過來的開發者,它省掉的是重寫和同步多份配置的成本。

  • GitHub:https://github.com/JohnXuXianyu22786/hooks-adapter
  • 社區插件目錄:https://www.skillhub.cn/plugins/JohnXuXianyu22786/hooks-adapter (目錄爲社區獨立站點維護,與 DeepSeek / 幻方無官方從屬關係)
羽毛球分组比赛记分
小程序二维码

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

小夜