New:Socket for Asana Is Now Available.Learn more
Get Started

dsh-cc-hooks

Package Overview
Dependencies
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

dsh-cc-hooks

Run unmodified Claude Code hooks in DSH with per-session discovery: project .claude/hooks + global ~/.claude/hooks + plugin dirs. All five handler types execute (command/http/mcp_tool/prompt/agent) through @deepseek-ai/dsh-hook-protocol (11/31 wired event

latest
Source
npmnpm
Version
0.1.1
Version published
Weekly downloads
198
46.67%
Maintainers
1
Weekly downloads
 
Created
Source

dsh-cc-hooks

Run unmodified Claude Code hooks (all five handler types) in DeepSeek Harness, with per-session / per-plugin discovery — the gap the official bridge (@deepseek-ai/dsh-hooks-claude-code) leaves open (its configPath is process-level, read once at load; its own source carries the TODO(per-session-hook-config)).

包名dsh-cc-hooks
依赖@deepseek-ai/dsh-hook-protocol(官方共享协议层,peer)、dsh-cc-loader(file: 共享解析层)
事件11/31:官方 7 映射集 + 批次 A 扩展 —— SessionStart / UserPromptSubmit / PreToolUse / PostToolUse / PostToolUseFailure / Stop / SubagentStart / SubagentStop / SessionEnd / PreCompact / PostCompact
动作类型全部 5 类执行:command / http / mcp_tool / prompt / agent(批次 B);事件×类型落在官方支持矩阵之外 → 解析即跳过 + 警告,能力缺失(tools/llm 服务、subagent 工具、模型路由)→ 警告 + 非阻断,永不崩溃
宿主 DSH0.1.0-rc.x(协议 peer 钉 0.1.0-rc.6,npm 无 rc.5 发布)

它做什么

每个会话按 session cwd 发现 hooks 配置并合并执行(CC 语义:多份配置 叠加,mergeHookOutputsdeny > ask > allow 最严格折叠):

  • 项目 <projectRoot>/.claude/hooks/hooks.json(projectRoot 由 cwd 向上按 .git 等标记发现)
  • 用户 ~/.claude/hooks/hooks.json(enableGlobal 可关)
  • 每个插件目录 <pluginDir>/hooks/hooks.json(pluginDirs 配置;该文件的 ${CLAUDE_PLUGIN_ROOT} 替换为对应插件根)
  • 只读:不写任何文件,单一事实来源永远是 .claude 原文(与 dsh-cc-loader 生态一致)
  • 每会话发现:agent/session-start 预载 + runPoint 惰性兜底;改 hooks.json新会话自然生效(会话内热重载不做,记录)
  • 路径变量:${CLAUDE_PLUGIN_ROOT}(解析期,按文件)、 ${CLAUDE_PROJECT_DIR}(运行期,按会话;默认 session workspace,同时导出 CLAUDE_PROJECT_DIR 环境变量)、${CLAUDE_PLUGIN_DATA} 无 DSH 落点(记录)

⚠️ Windows 宿主:deny 请用结构化 stdout,别依赖 exit 2

DSH 的 shell 执行器(dsh-pwsh-local)以 pwsh -NoProfile -NonInteractive -Command <hook command> 运行 hook,而 pwsh 7 的 -Command 把任何非零 native 退出码折叠成 1。协议只有 exit 2 才是 deny → exit 2 到达时变成 exit 1(非阻断错误)→ hook 静默放行。官方桥 @deepseek-ai/dsh-hooks-claude-code 在 Windows 同样受此 影响(LESSONS 1.21)。

hook 作者在 Windows 上应使用结构化 stdout JSON 通道(CC 官方支持,且 exit 0 不受 pwsh 包装影响):

process.stdout.write(JSON.stringify({
  hookSpecificOutput: {
    hookEventName: 'PreToolUse',          // 必须等于触发事件
    permissionDecision: 'deny',           // allow / deny / ask
    permissionDecisionReason: 'blocked',
  },
}))
process.exit(0)

安装

# 先装共享库,再装插件(本地开发 checkout 需包内 pnpm install + pnpm link ../cc-loader)
dsh plugin --profile <name> add dsh-cc-loader dsh-cc-hooks

本地 patch 挂载(Web profile 热更新,改完重启 GUI):

# ~/.dsh/profiles/web/cordis.patch.yml 追加
- insert:
    - id: cc-hooks
      name: 'file:///C:/Users/<you>/.../dsh-cc-ecosystem/packages/cc-hooks/src/index.js'
      config:
        enableGlobal: true
        # pluginDirs: ['C:/path/to/plugin-root', ...]

配置(Schema)

默认说明
enabledtrue总开关
defaultTimeoutMs600000未设 timeout 的 hook 默认超时(CC 同值)
stderrSummaryMaxChars500hook/result 事件 stderr 摘要上限
pluginDirs[]插件根列表,扫 <dir>/hooks/hooks.json
enableGlobaltrue是否加载 ~/.claude/hooks/hooks.json
globalClaudeDir~/.claude用户级目录覆盖(测试用)
homeDiros.homedir()家目录覆盖(测试用)
projectRootMarkers['.git']项目根向上发现标记
projectDir会话 cwdCLAUDE_PROJECT_DIR 覆盖值

hooks.json 格式速查(CC 官方格式,直传 JSON)

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash|Write",        // 可选;默认匹配所有;多值用 | 分隔
        "hooks": [
          { "type": "command", "command": "node scripts/guard.mjs", "timeout": 10000 }
          // type 还可能是 http / mcp_tool / prompt / agent —— 全部执行(批次 B)
        ]
      }
    ],
    "PostToolUse": [
      { "matcher": "Read", "hooks": [{ "type": "command", "command": "echo $CLAUDE_PROJECT_DIR" }] }
    ]
  }
}

31 个事件中,已接线的 11 个(WIRED_EVENTS)全类型执行;其余 20 个事件名在 JSON 里是普通 key,解析通过但暂不执行(parsed-but-inert)。

批次 B:http / mcp_tool / prompt / agent 执行语义(官方)

type输入输出阻断默认超时
commandpayload JSON → stdinexit 0 stdout JSON / exit 2 stderrexit 2 / JSON 决策600s(UserPromptSubmit 30s)
httppayload JSON → POST body2xx JSON object body 按 command 规则解析仅 2xx + JSON 决策;状态码不能阻断600s(UserPromptSubmit 30s)
mcp_toolinput 字符串值支持 ${tool_input.x} 替换工具文本按 exit-0 stdout 规则解析文本 JSON 决策600s(UserPromptSubmit 30s)
prompt$ARGUMENTS 替换 payload → 单轮 LLM{"ok": true} / {"ok": false, "reason"}ok=false 阻断30s
agent同 prompt → subagent(默认关 background,等前台答案)同上ok=false 阻断60s
  • http 失败(非 2xx / 非 JSON 体 / 连接失败 / 超时)→ 非阻断错误,继续;headers 值支持 $VAR/${VAR} 插值,仅 allowedEnvVars 白名单内变量被解析,未列入 → 空串
  • mcp_tool 直接调用已注册工具的 ToolDefinition(绕过工具事件管线,避免钩子 递归触发自身);server/tool 未连接或 isError → 非阻断错误。server: "plugin:<plugin>:<server>" 映射到 scoped 名 mcp__plugin_<plugin>_<server>__<tool>
  • prompt/agent 返回非 {ok} JSON → 非阻断错误;模型可包 ```json 代码围栏
  • 能力缺失降级:无 tools/llm 服务、无 subagent 工具、无模型路由(既无 hook.model 也无 agent 模型)→ 警告 + 非阻断,永不崩溃
  • 事件×类型支持矩阵(EVENT_TYPE_SUPPORT,官方):SessionStart/Setup 仅 command/mcp_tool;14 个 observe 事件(SessionEnd/PreCompact/PostCompact/ SubagentStart/Notification/MessageDisplay/DirectoryAdded 等)无 prompt/agent; 其余 11 个事件 5 类全支持。不支持组合 → 解析即跳过 + 警告

批次 A 新增接线

事件DSH 扩展点matcher subject语义
PostToolUseFailuretools/post-execute(result.isError)工具名工具失败时触发;deny → block + 反馈,与 PostToolUse 同形
SessionEndagent/disposed(仅顶层会话)结束原因DSH 无原因概念 → 恒报 other;observe-only
PreCompactsession 事件流 compaction/startmanual / auto手动 /compactsourceCommandId → manual,自动压缩 → auto;observe-only(压缩已落盘,block 无法兑现)
PostCompactsession 事件流 compaction/endmanual / autoobserve-only

if 字段执行过滤

  • 仅 5 个 tool 事件评估:PreToolUse / PostToolUse / PostToolUseFailure / PermissionRequest / PermissionDenied;其他事件上带 if 的 hook 永不运行(CC 官方)
  • 单条权限规则(无 &&/||/列表);Bash 按任一子命令匹配,含 $()/反引号 内命令;前置 VAR=value 剥离;规则无法解析 → fail-open 运行(CC 官方)
  • matcher 同时匹配 DSH 工具名(bash)与 CC 桶名(Bash),CC 原样配置直接生效

与官方桥的差异

官方桥(进程级)本插件(per-session)
加载时读一次 configPath每会话按 cwd 发现 + 缓存;新会话重读
只读一个文件合并项目 + 全局 + 各插件 hooks/hooks.json
配置变化需重启进程新会话自然生效
项目级优先,插件最后(CC 作用域语义)

决策映射(PreToolUse deny/ask、PostToolUse block+context、UserPromptSubmit reject、Stop steer、SessionStart/Subagent* 注入)与官方桥逐点一致;批次 A 的 PostToolUseFailure 沿用 PostToolUse 的 block+context 映射,SessionEnd 与 PreCompact/PostCompact 为 observe-only(不注入、不阻断)。

PostToolUseFailure 的宿主差异(非零退出码)

CC 中 Bash/PowerShell 命令非零退出码 = 工具失败 → 触发 PostToolUseFailure; DSH 的 shell 工具把非零退出码渲染成 [exit code: N] 标记、result.isError 仅为基础设施故障(spawn 错误/abort)。为对齐 CC 语义,本插件在 tools/post-execute 里同时检查 canonical value 的 exitCode !== 0,非零即 走 PostToolUseFailure(git status 在非仓库目录、bash -c "exit 1" 都是此类)。

测试

node --test test/hooks-merge.test.mjs test/hooks-integration.mjs test/hooks-matrix.test.mjs test/hooks-batch-a.test.mjs test/hooks-executors.test.mjs

覆盖:解析(settings/bare 形态、事件×类型矩阵、非法 matcher 抛错)、 ${CLAUDE_*} 替换、三来源发现(项目/全局/插件)、跨源合并、协议折叠 (deny>ask>allow)、matcher 语义、60% 语法矩阵(465 + 12 特殊)、批次 A(if 过滤语义、PostToolUseFailure 分支、SessionEnd 顶层会话、PreCompact/PostCompact manual/auto)、批次 B(http 本地服务器实测、mcp_tool 直调、prompt/agent {ok} 解码、能力缺失降级、runPoint 分发集成)。

License

MIT。接线语义镜像自 @deepseek-ai/dsh-hooks-claude-code(官方,随 deepseek-harness 维护);共享协议层 @deepseek-ai/dsh-hook-protocol(BSD-3-Clause → 官方 0.1.0-rc.6 线,按官方许可使用)。

Keywords

dsh

FAQs

Package last updated on 23 Aug 2026

Related posts