name: debug-hooks description: 系统化钩子调试工作流程。在钩子不触发、产生错误输出或行为异常时使用。 allowed-tools: [Bash, Read, Grep]
调试钩子
用于调试Claude Code钩子的系统化工作流程。
何时使用
- “钩子不触发”
- “钩子产生错误输出”
- “SessionEnd不工作”
- “PostToolUse钩子未触发”
- “为什么我的钩子没运行?”
工作流程
1. 首先检查输出(编辑前观察)
# 检查项目缓存
ls -la $CLAUDE_PROJECT_DIR/.claude/cache/
# 检查特定输出
ls -la $CLAUDE_PROJECT_DIR/.claude/cache/learnings/
# 检查调试日志
tail $CLAUDE_PROJECT_DIR/.claude/cache/*.log 2>/dev/null
# 同时检查全局(常见错误:路径错误)
ls -la ~/.claude/cache/ 2>/dev/null
2. 验证钩子注册
# 项目设置
cat $CLAUDE_PROJECT_DIR/.claude/settings.json | grep -A 20 '\"SessionEnd\"\\|\"PostToolUse\"\\|\"UserPromptSubmit\"'
# 全局设置(钩子从两者合并)
cat ~/.claude/settings.json | grep -A 20 '\"SessionEnd\"\\|\"PostToolUse\"\\|\"UserPromptSubmit\"'
3. 检查钩子文件是否存在
# Shell包装器
ls -la $CLAUDE_PROJECT_DIR/.claude/hooks/*.sh
# 编译包(如果使用TypeScript)
ls -la $CLAUDE_PROJECT_DIR/.claude/hooks/dist/*.mjs
4. 手动测试钩子
# SessionEnd钩子
echo '{"session_id": "test-123", "reason": "clear", "transcript_path": "/tmp/test"}' | \
$CLAUDE_PROJECT_DIR/.claude/hooks/session-end-cleanup.sh
# PostToolUse钩子(Write工具示例)
echo '{"tool_name": "Write", "tool_input": {"file_path": "test.md"}, "session_id": "test-123"}' | \
$CLAUDE_PROJECT_DIR/.claude/hooks/handoff-index.sh
5. 检查静默失败
如果使用分离spawn并设置stdio: 'ignore':
// 这个模式会隐藏错误!
spawn(cmd, args, { detached: true, stdio: 'ignore' })
修复: 添加临时日志:
const logFile = fs.openSync('.claude/cache/debug.log', 'a');
spawn(cmd, args, {
detached: true,
stdio: ['ignore', logFile, logFile] // 捕获标准输出/标准错误
});
6. 编辑后重新构建
如果你编辑了TypeScript源代码,你必须重新构建:
cd $CLAUDE_PROJECT_DIR/.claude/hooks
npx esbuild src/session-end-cleanup.ts \
--bundle --platform=node --format=esm \
--outfile=dist/session-end-cleanup.mjs
仅编辑源代码不会生效 - shell包装器运行捆绑的.mjs文件。
常见问题
| 症状 | 可能原因 | 解决方法 |
|---|---|---|
| 钩子从未运行 | 未在settings.json中注册 | 添加到设置中的正确事件 |
| 钩子运行但无输出 | 分离spawn隐藏错误 | 添加日志,手动检查 |
| 错误的会话ID | 使用“最近”查询 | 明确传递ID |
| 本地有效,CI无效 | 缺少依赖 | 检查npx/node可用性 |
| 运行两次 | 同时在全局和项目中注册 | 移除重复 |
调试检查清单
- [ ] 输出是否存在? (
ls -la .claude/cache/) - [ ] 已注册? (
grep -A10 '\"hooks\"' .claude/settings.json) - [ ] 文件存在? (
ls .claude/hooks/*.sh) - [ ] 包当前? (
ls -la .claude/hooks/dist/) - [ ] 手动测试有效? (
echo '{}' | ./hook.sh) - [ ] 无静默失败? (检查是否有
stdio: 'ignore')
源会话
基于10个会话(所有学习中的83%):
- a541f08a, 1c21e6c8, 6a9f2d7a, a8bd5cea, 2ca1a178, 657ce0b2, 3998f3a2, 2a829f12, 0b46cfd7, 862f6e2c