npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-cc-hooks

v0.6.1

Published

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

Readme

dsh-cc-hooks

[!IMPORTANT] Only upgrade to this version when upgrading DSH to 0.1.5-rc.2 or later. It binds to the 0.1.5 host contracts (ToolCallId, snapshotEvents() / eventAt(), ^0.1.5-rc.2 peer ranges) and does not work on older DSH — on a pre-0.1.5 host the dsh-llm import itself fails. If your DSH is still 0.1.0-rc.7–0.1.1-rc.2, do not upgrade — stay on v0.1.x. The two lines are mutually exclusive.

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 工具、模型路由)→ 警告 + 非阻断,永不崩溃 | | 宿主 DSH | 0.1.0-rc.x(协议 peer 钉 0.1.0-rc.6,npm 无 rc.5 发布) |

它做什么

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

  1. 项目 <cwd>/.claude/settings.json 与 settings.local.json 里的 hooks

  2. 项目 <cwd>/.claude/hooks/hooks.json

    (1、2 都锚在会话 cwd —— Claude Code 就是这样读 settings 的 (<cwd>/.claude/),不从祖先目录找。所以从子目录起的会话不会拿到仓库根 的 hooks。)

  3. 用户 ~/.claude/hooks/hooks.json(enableGlobal 可关)

  4. 每个插件目录 <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)。版本号是故意钉死的:pnpm 11 会拦下发布不满 24 小时的版本,只写包名会静默装到旧版并报成功 —— 见为什么要带版本号。

dsh plugin --profile <name> add [email protected] [email protected]

本地 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)

| 键 | 默认 | 说明 | |---|---|---| | enabled | true | 总开关 | | defaultTimeoutMs | 600000 | 未设 timeout 的 hook 默认超时(CC 同值) | | stderrSummaryMaxChars | 500 | hook/result 事件 stderr 摘要上限 | | pluginDirs | [] | 插件根列表,扫 <dir>/hooks/hooks.json | | enableGlobal | true | 是否加载 ~/.claude/hooks/hooks.json | | globalClaudeDir | ~/.claude | 用户级目录覆盖(测试用) | | homeDir | os.homedir() | 家目录覆盖(测试用) | | projectDir | 会话 cwd | CLAUDE_PROJECT_DIR 覆盖值 | | sandboxMode | '' | hook 的沙箱模式。空 = 跟随会话;danger-full-access = 不设防(Claude Code 行为) | | shellDialect | auto | ctx.shell 说的是哪种语言:auto 在 Windows 上探一次 / posix / pwsh |

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 | 输入 | 输出 | 阻断 | 默认超时 | |---|---|---|---|---| | command | payload JSON → stdin | exit 0 stdout JSON / exit 2 stderr | exit 2 / JSON 决策 | 600s(UserPromptSubmit 30s) | | http | payload JSON → POST body | 2xx JSON object body 按 command 规则解析 | 仅 2xx + JSON 决策;状态码不能阻断 | 600s(UserPromptSubmit 30s) | | mcp_tool | input 字符串值支持 ${tool_input.x} 替换 | 工具文本按 exit-0 stdout 规则解析 | 文本 JSON 决策 | 600s(UserPromptSubmit 30s) | | prompt | 会话历史(session.deriveMessages(),与主请求同前缀 → 缓存命中)+ 末尾 user(prompt,无 $ARGUMENTS 时输入 JSON 自动追加,CC 官方)+ JSON-only 输出约束 | {"ok": true} / {"ok": false, "reason"} | ok=false 阻断 | 30s | | agent | 同 prompt → subagent(默认关 background,等前台答案) | 同上 | ok=false 阻断 | 60s |

  • prompt 输入规则(CC 官方):$ARGUMENTS 是 hook 输入 JSON 的占位符;模板里 没有 $ARGUMENTS 时输入 JSON 自动追加到 prompt 末尾。

  • prompt hook 携带完整会话上下文:消息 = agent.session.deriveMessages() (与主 agent 请求字节一致的前缀 → provider prompt cache 命中,多次 hook 调用接近免费) + 末尾一条 user 消息(hook prompt + 输入数据)。Stop 时机 deriveMessages() 已含本轮最终 assistant 消息,故 prompt 如"回顾本轮操作" 能看到 agent 刚做了什么(改了文件、没写 hot.md…),不再盲猜。

  • 模型路由 = 调用 agent 的 provider/model(DSH 无独立 fast-model 池; hook.model 可覆盖)。LLM 只回 JSON——实现强制追加 JSON-only 契约,模型 不包 prose/围栏亦能解码(代码围栏仍容忍)。

  • 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 | 语义 | |---|---|---|---| | PostToolUseFailure | tools/post-execute(result.isError) | 工具名 | 工具失败时触发;deny → block + 反馈,与 PostToolUse 同形 | | SessionEnd | agent/disposed(仅顶层会话) | 结束原因 | DSH 无原因概念 → 恒报 other;observe-only | | PreCompact | session 事件流 compaction/start | manual / auto | 手动 /compact 带 sourceCommandId → manual,自动压缩 → auto;observe-only(压缩已落盘,block 无法兑现) | | PostCompact | session 事件流 compaction/end | manual / auto | observe-only |

if 字段执行过滤

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

Stop / SubagentStop payload:last_assistant_message

CC 官方 Stop/SubagentStop input 携带 last_assistant_message(agent 本轮回合的 最终回复文本),使 hook 无需解析 transcript 即可判断刚结束的回合做了什么。 本插件从 session 事件流取最后一条 assistant/message 的 text 块(reasoning 块排除)填充该字段;无先前回复时降级为空串。prompt/agent 类型 hook 依赖此 字段:它们的 LLM/子代理是裸调用、无工具可读 transcript,若缺失则无法得知 "本轮是否产生修改",只能默认 {"ok": true} 放行 → 一个应阻止停止的 Stop hook(如"有修改未同步 hot.md")会静默失效。

与官方桥的差异

| 官方桥(进程级) | 本插件(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 test/hooks-stop-payload.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 分发集成)、Stop/SubagentStop payload (last_assistant_message 携带最终回复文本且不含 reasoning 块;无回复时降级空串)。

License

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