CodeBuddy Hooks 功能使用文档

Hook 功能允许你在 AI Agent 执行的关键节点插入自定义脚本,实现对 Agent 行为的精细控制。Hook 机制完全兼容 Claude Code Hooks 规范,提供了一种强大且灵活的扩展方式。

相关产品
CodeBuddy 产品页,含版本规格、价格与购买入口。

二、功能特性

·多事件支持:支持7种关键事件(SessionStart、SessionEnd、PreToolUse、PostToolUse、UserPromptSubmit、Stop、PreCompact)

·工具拦截:在工具执行前后进行验证、修改或阻止

·上下文注入:在会话不同阶段动态注入额外上下文

·并行执行:多个 Hook 自动并行执行,提升性能

·自动去重:相同命令自动去重,避免重复执行

·灵活配置:支持正则匹配、超时控制、项目级/用户级配置

·会话跟踪:智能识别会话变化,避免重复触发 SessionStart

·安全可靠:完善的错误处理和超时机制

四、1. SessionStart – 会话启动

触发时机:会话开始时(每个新会话只触发一次)

触发逻辑:

·系统通过对比 conversationId 判断是否为新会话

·同一会话中多次请求不会重复触发

·切换到新会话或清空会话后会重新触发

用途:

·初始化项目环境

·注入项目特定上下文

·设置会话级别的配置

·加载项目规范和文档

Matcher 匹配字段:source

·startup – 首次启动(目前仅支持此值)

输入数据 (stdin JSON):

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "SessionStart", "source": "startup"}

输出数据 (stdout JSON):

{ "continue": true, "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": "项目使用 TypeScript + React,请优先使用函数式组件" }}

示例配置:

{ "hooks": { "SessionStart": [ { "matcher": "startup", "hooks": [ { "type": "command", "command": "/path/to/session_start.py", "timeout": 30 } ] } ] }}

五、2. SessionEnd – 会话结束

触发时机:会话终止时

用途:

·清理临时资源

·保存会话状态

·生成会话报告

Matcher 匹配字段:reason

·other – 会话结束(目前仅支持此值,包括切换会话、删除会话、清空会话等场景)

输入数据:

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "SessionEnd", "reason": "other"}

输出数据:

{ "continue": true, "systemMessage": "会话已清理,临时文件已删除"}

六、3. PreToolUse – 工具执行前

触发时机:任何工具执行前

用途:

·验证工具参数

·修改工具输入

·阻止危险操作

·权限检查

·记录审计日志

Matcher 匹配字段:tool_name

·示例:Bash, Write, Read

·支持正则:Write|Edit

·匹配所有:* 或空字符串

输入数据:

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "PreToolUse", "tool_name": "Bash", "tool_input": { "command": "npm install", "requires_approval": false }}

输出数据 – 允许执行:

{ "continue": true, "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow" }}

输出数据 – 修改参数:

{ "continue": true, "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow", "permissionDecisionReason": "已添加 –legacy-peer-deps 参数", "modifiedInput": { "command": "npm install –legacy-peer-deps", "requires_approval": false } }}

输出数据 – 阻止执行:

{ "continue": false, "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": "检测到危险命令: rm -rf /" }}

输出数据 – 请求用户确认:

{ "continue": true, "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "ask", "permissionDecisionReason": "检测到 git push –force,是否继续?" }}

七、4. PostToolUse – 工具执行后

触发时机:工具执行完成后

用途:

·记录工具执行日志

·后处理工具输出

·触发后续操作

·发送通知

Matcher 匹配字段:tool_name

输入数据:

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "PostToolUse", "tool_name": "Bash", "tool_input": { "command": "npm test" }, "tool_response": { "exitCode": 0, "stdout": "All tests passed", "stderr": "" }}

输出数据:

{ "continue": true, "hookSpecificOutput": { "hookEventName": "PostToolUse", "additionalContext": "测试已通过,可以继续开发" }}

八、5. UserPromptSubmit – 用户输入提交

触发时机:用户提交消息时

用途:

·预处理用户输入

·添加上下文信息

·检测特定关键词

·输入验证

Matcher:不使用(所有提交都触发)

输入数据:

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "UserPromptSubmit", "prompt": "帮我实现一个登录功能"}

输出数据:

{ "continue": true, "hookSpecificOutput": { "hookEventName": "UserPromptSubmit", "additionalContext": "提示:项目已集成 JWT 认证库,建议使用" }}

阻止输入:

{ "continue": false, "stopReason": "输入包含敏感信息,已阻止"}

九、6. Stop – Agent 停止响应

触发时机:Agent 完成响应时

用途:

·提供反馈给 Agent

·记录执行状态

·触发后续任务

Matcher:不使用

输入数据:

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "Stop", "stop_hook_active": false}

输出数据 – 提供反馈 (exit code 2):

{ "continue": false, "stopReason": "请验证代码是否通过了单元测试"}

十、7. PreCompact – 上下文压缩前

触发时机:上下文即将被压缩时

用途:

·保存重要信息

·提供压缩指导

·备份完整上下文

Matcher 匹配字段:trigger

·manual – 用户手动触发 /summarize

·auto – 自动压缩

输入数据:

{ "session_id": "abc123", "transcript_path": "/path/to/transcript.txt", "cwd": "/project/path", "hook_event_name": "PreCompact", "trigger": "auto", "custom_instructions": "保留所有 API 设计相关的讨论"}

输出数据 (exit code 0):

{ "continue": true, "hookSpecificOutput": { "hookEventName": "PreCompact", "additionalContext": "重要:保留数据库表结构设计" }}

注意:说明:

注意:Exit code 0 时,stdout 的内容会被添加为额外的压缩指导。

十二、输入格式

Hook 脚本通过 stdin 接收 JSON 格式的输入数据。

通用字段:

{ "session_id": "会话 ID", "transcript_path": "对话记录文件路径", "cwd": "当前工作目录", "hook_event_name": "事件名称"}

事件特定字段:

·SessionStart: source

·SessionEnd: reason

·PreToolUse/PostToolUse: tool_name, tool_input, tool_response

·UserPromptSubmit: prompt

·PreCompact: trigger, custom_instructions

·Stop: stop_hook_active

十三、输出格式

Hook 脚本通过 stdout 返回 JSON 格式的输出。

基本结构:

{ "continue": true, "suppressOutput": false, "systemMessage": "可选的系统消息", "stopReason": "阻止原因(当 continue=false 时)", "hookSpecificOutput": { "hookEventName": "事件名称", "permissionDecision": "allow|deny|ask", "permissionDecisionReason": "决策原因", "modifiedInput": {}, "additionalContext": "额外上下文" }}

字段说明:

·continue: 是否允许操作继续(false 表示阻止)

·suppressOutput: 是否隐藏 stdout 输出

·systemMessage: 显示给用户的系统消息

·stopReason: 阻止原因

·hookSpecificOutput: 事件特定的输出数据

十四、退出码规范

退出码 含义 行为
0 成功执行 允许操作继续,stdout 可能被处理
1 非阻塞错误 显示 stderr 作为警告,允许继续
2 阻塞错误 阻止操作,stderr 传递给 Agent/模型
其他 非阻塞错误 同退出码 1

特殊规则:

·PreToolUse: 退出码2会阻止工具执行

·Stop: 退出码 2 表示提供反馈,stderr 会注入到下一条消息

·PreCompact: 退出码0时,stdout 会作为额外的压缩指导

十五、环境变量

Hook 脚本执行时可访问以下环境变量:

·CLAUDE_PROJECT_DIR: 项目根目录(兼容 Claude Code)

·CODEBUDDY_PROJECT_DIR: 项目根目录(CodeBuddy 特定)

十七、配置文件位置

优先级(高到低):

1. 项目级:<workspace>/.codebuddy/settings.json

2. 用户级:~/.codebuddy/settings.json

项目级配置会覆盖用户级配置。

十八、配置文件结构

{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "/absolute/path/to/script.py", "timeout": 10 } ] }, { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "/path/to/backup_script.sh", "timeout": 20 } ] } ], "SessionStart": [ { "matcher": "startup", "hooks": [ { "type": "command", "command": "/path/to/init.py", "timeout": 30 } ] } ] }}

20、matcher (匹配器)

正则表达式,用于匹配特定条件。

语法:

·空字符串 "" 或 "*": 匹配所有

·单个值: "Bash"

·多个值: "Write|Edit"

·正则表达式: "Read.*|Grep.*"

不同事件的匹配目标:

·PreToolUse/PostToolUse: 匹配 tool_name(如 Bash, Write, Read, Edit 等)

·SessionStart: 匹配 source

·SessionEnd: 匹配 reason

·PreCompact: 匹配 trigger

·UserPromptSubmit/Stop: 不使用 matcher

21、command (命令路径)

Hook 脚本的路径。

要求:

·推荐使用绝对路径

·支持环境变量: "$CODEBUDDY_PROJECT_DIR/.codebuddy/hooks/script.py"

·可包含解释器: "python3 /path/to/script.py"

·需要确保脚本有执行权限

22、timeout (超时时间)

Hook 执行的超时时间,单位:秒。

·默认值: 60 秒

·推荐设置: 根据脚本复杂度调整

·简单验证: 5 – 10 秒

·文件操作: 15 – 30 秒

·网络请求: 30 – 60 秒

24、示例 1:命令安全验证

场景: 阻止危险的 rm -rf 命令

Hook 脚本 (validate_command.py):

#!/usr/bin/env python3import jsonimport sysDANGEROUS_COMMANDS = ['rm -rf /', 'dd if=/dev/zero', 'mkfs']def main(): input_data = json.loads(sys.stdin.read()) if input_data.get('tool_name') != 'Bash': print(json.dumps({"continue": True})) return 0 command = input_data.get('tool_input', {}).get('command', '') for dangerous in DANGEROUS_COMMANDS: if dangerous in command: output = { "continue": False, "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "deny", "permissionDecisionReason": f"检测到危险命令: {dangerous}" } } print(json.dumps(output, ensure_ascii=False)) return 0 print(json.dumps({"continue": True})) return 0if __name__ == "__main__": sys.exit(main())

配置:

{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "/path/to/validate_command.py", "timeout": 10 } ] } ] }}

25、示例 2: 智能修改命令参数

场景: 自动为 npm install 添加 –legacy-peer-deps 参数

Hook 脚本 (modify_npm.py):

#!/usr/bin/env python3import jsonimport sysimport redef main(): input_data = json.loads(sys.stdin.read()) if input_data.get('tool_name') != 'Bash': print(json.dumps({"continue": True})) return 0 tool_input = input_data.get('tool_input', {}) command = tool_input.get('command', '') # 检查是否是 npm install if re.match(r'^npm\\s+(i|install)\\b', command.strip()): # 如果没有 –legacy-peer-deps,添加它 if '–legacy-peer-deps' not in command: modified_command = command.strip() + ' –legacy-peer-deps' output = { "continue": True, "hookSpecificOutput": { "hookEventName": "PreToolUse", "permissionDecision": "allow", "permissionDecisionReason": "已自动添加 –legacy-peer-deps 参数", "modifiedInput": { "command": modified_command, "requires_approval": tool_input.get('requires_approval', False) } } } print(json.dumps(output, ensure_ascii=False)) return 0 print(json.dumps({"continue": True})) return 0if __name__ == "__main__": sys.exit(main())

26、示例 3: 文件修改前自动备份

场景: 在修改文件前自动创建备份

Hook 脚本 (backup_files.py):

#!/usr/bin/env python3import jsonimport sysimport osimport shutilfrom datetime import datetimedef main(): input_data = json.loads(sys.stdin.read()) tool_name = input_data.get('tool_name', '') # 只处理文件写入工具 if tool_name not in ['Write', 'Edit']: print(json.dumps({"continue": True})) return 0 tool_input = input_data.get('tool_input', {}) file_path = tool_input.get('filePath') if not file_path or not os.path.exists(file_path): print(json.dumps({"continue": True})) return 0 # 创建备份目录 project_dir = os.environ.get('CODEBUDDY_PROJECT_DIR', '') backup_dir = os.path.join(project_dir, '.codebuddy', 'backups') os.makedirs(backup_dir, exist_ok=True) # 生成备份文件名 timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') backup_name = f"{os.path.basename(file_path)}.{timestamp}.bak" backup_path = os.path.join(backup_dir, backup_name) # 创建备份 shutil.copy2(file_path, backup_path) output = { "continue": True, "systemMessage": f"已备份至: {backup_path}" } print(json.dumps(output, ensure_ascii=False)) return 0if __name__ == "__main__": sys.exit(main())

配置:

{ "hooks": { "PreToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "/path/to/backup_files.py", "timeout": 15 } ] } ] }}

27、示例 4: 会话启动时注入项目上下文

场景: 在会话开始时自动注入项目配置信息

Hook 脚本 (session_start.py):

#!/usr/bin/env python3import jsonimport sysimport osdef main(): input_data = json.loads(sys.stdin.read()) project_dir = os.environ.get('CODEBUDDY_PROJECT_DIR', '') # 读取项目配置 config_file = os.path.join(project_dir, '.codebuddy', 'project.json') project_info = "" if os.path.exists(config_file): with open(config_file, 'r') as f: config = json.load(f) project_info = f"""项目名称: {config.get('name', 'Unknown')}技术栈: {', '.join(config.get('tech_stack', []))}编码规范: {config.get('coding_standard', 'Standard')}""" output = { "continue": True, "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": f"""会话已启动!项目目录: {project_dir}启动源: {input_data.get('source', 'unknown')}{project_info}""" } } print(json.dumps(output, ensure_ascii=False)) return 0if __name__ == "__main__": sys.exit(main())

28、示例 5: 上下文压缩前保存重要信息

场景: 在自动压缩前保存完整对话历史

Hook 脚本 (save_context.py):

#!/usr/bin/env python3import jsonimport sysimport osimport shutilfrom datetime import datetimedef main(): input_data = json.loads(sys.stdin.read()) # 只处理自动压缩 if input_data.get('trigger') != 'auto': print(json.dumps({"continue": True})) return 0 project_dir = os.environ.get('CODEBUDDY_PROJECT_DIR', '') transcript_path = input_data.get('transcript_path', '') if not transcript_path or not os.path.exists(transcript_path): print(json.dumps({"continue": True})) return 0 # 创建保存目录 save_dir = os.path.join(project_dir, '.codebuddy', 'context_history') os.makedirs(save_dir, exist_ok=True) # 保存对话历史 timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') save_path = os.path.join(save_dir, f'transcript_{timestamp}.txt') shutil.copy2(transcript_path, save_path) output = { "continue": True, "systemMessage": f"上下文已保存至: {save_path}" } print(json.dumps(output, ensure_ascii=False)) return 0if __name__ == "__main__": sys.exit(main())

配置:

{ "hooks": { "PreCompact": [ { "matcher": "auto", "hooks": [ { "type": "command", "command": "/path/to/save_context.py", "timeout": 20 } ] } ] }}

30、快速开始 – 5分钟配置第一个 Hook

第一步:创建配置文件

mkdir -p ~/.codebuddycat > ~/.codebuddy/settings.json << 'EOF'{ "hooks": { "SessionStart": [ { "matcher": "startup", "hooks": [ { "type": "command", "command": "/usr/bin/env python3 -c \\"import json,sys; print(json.dumps({'continue': True, 'hookSpecificOutput': {'hookEventName': 'SessionStart', 'additionalContext': 'Hook 配置成功!'}}))\\"", "timeout": 5 } ] } ] }}EOF

第二步:重启 Agent

启动新会话,如果看到“Hook 配置成功!”说明配置生效。

第三步:创建你的第一个真实 Hook

# 创建 Hook 脚本目录mkdir -p ~/.codebuddy/hooks# 创建测试脚本cat > ~/.codebuddy/hooks/my_first_hook.py << 'EOF'#!/usr/bin/env python3import jsonimport sysdef main(): input_data = json.loads(sys.stdin.read()) output = { "continue": True, "hookSpecificOutput": { "hookEventName": "SessionStart", "additionalContext": f"欢迎使用 Agent-Craft!当前项目: {input_data.get('cwd', 'unknown')}" } } print(json.dumps(output, ensure_ascii=False)) return 0if __name__ == "__main__": sys.exit(main())EOF# 添加执行权限chmod +x ~/.codebuddy/hooks/my_first_hook.py

第四步:更新配置文件

{ "hooks": { "SessionStart": [ { "matcher": "startup", "hooks": [ { "type": "command", "command": "/Users/YOUR_USERNAME/.codebuddy/hooks/my_first_hook.py", "timeout": 10 } ] } ] }}

31、调试技巧进阶

技巧1: 使用日志文件调试

import sysdef debug_log(message): """写入调试日志而不影响 stdout""" with open('/tmp/hook_debug.log', 'a') as f: f.write(f"{message}\\n")# 在 Hook 脚本中使用debug_log(f"Received input: {json.dumps(input_data)}")

技巧2: 验证 JSON 输出格式

# 测试脚本输出的 JSON 是否有效echo '{"hook_event_name":"SessionStart"}' | python3 your_hook.py | jq .

技巧3: 监控 Hook 执行

# 实时查看 Hook 日志tail -f ~/.codebuddy/logs/agent-craft.log | grep -i hook

技巧4: 使用环境变量传递信息

import os# 在 Hook 中获取项目目录project_dir = os.environ.get('CODEBUDDY_PROJECT_DIR', '')claude_dir = os.environ.get('CLAUDE_PROJECT_DIR', '') # 兼容 Claude Code

32、常见 Hook 模式

模式1: 白名单验证

ALLOWED_COMMANDS = [ 'npm install', 'npm test', 'git status', 'git diff']def is_allowed(command): return any(command.startswith(allowed) for allowed in ALLOWED_COMMANDS)

模式2: 参数增强

def enhance_command(command): """自动添加常用参数""" enhancements = { 'npm install': ' –legacy-peer-deps', 'git push': ' –dry-run', # 安全模式 } for prefix, suffix in enhancements.items(): if command.startswith(prefix) and suffix not in command: return command + suffix return command

模式3: 条件路由

def should_block(input_data): """根据多个条件判断是否阻止""" tool_name = input_data.get('tool_name') tool_input = input_data.get('tool_input', {}) # 规则1: 阻止删除重要文件 if tool_name == 'Write': file_path = tool_input.get('file_path', '') if any(important in file_path for important in ['.git', 'package.json']): return True, "不能删除重要文件" # 规则2: 阻止危险命令 if tool_name == 'Bash': command = tool_input.get('command', '') if 'rm -rf /' in command or 'dd if=' in command: return True, "检测到危险命令" return False, None

33、项目模板推荐

Node.js 项目 Hook 配置

{ "hooks": { "SessionStart": [ { "matcher": "startup", "hooks": [ { "type": "command", "command": "node ~/.codebuddy/hooks/nodejs-init.js", "timeout": 15 } ] } ], "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "python3 ~/.codebuddy/hooks/npm-safety-check.py", "timeout": 5 } ] } ] }}

Python 项目 Hook 配置

{ "hooks": { "SessionStart": [ { "matcher": "startup", "hooks": [ { "type": "command", "command": "python3 ~/.codebuddy/hooks/python-env-check.py", "timeout": 10 } ] } ], "PostToolUse": [ { "matcher": "Write|Edit", "hooks": [ { "type": "command", "command": "python3 ~/.codebuddy/hooks/python-lint.py", "timeout": 20 } ] } ] }}

35、1. 脚本开发

·错误处理: 脚本配置异常处理,减少阻塞主流程

·快速执行: Hook 应快速完成,减少耗时操作

·幂等性: Hook 可能被多次调用,多次执行结果一致

·日志记录: 使用 sys.stderr 输出调试信息,不要污染 stdout

36、2. 安全性

·输入验证: 始终验证输入数据的合法性

·白名单优于黑名单: 使用白名单机制进行权限控制

·避免代码注入: 不要直接执行用户输入

·最小权限: Hook 脚本应以最小必要权限运行

37、3. 性能优化

·设置合理超时: 根据脚本复杂度设置 timeout

·并行设计: 避免 Hook 之间的依赖,充分利用并行执行

·缓存结果: 对于重复计算,考虑缓存结果

38、4. 调试技巧

手动测试 Hook 脚本:

echo '{"hook_event_name":"PreToolUse","tool_name":"Bash","tool_input":{"command":"npm install"}}' | \\ python3 /path/to/your_hook.py

调试输出:

# 在 Hook 脚本中输出调试信息import syssys.stderr.write(f"[DEBUG] Processing command: {command}\\n")sys.stderr.flush()

39、5. 配置管理

·项目特定 Hook: 放在 <workspace>/.codebuddy/ 下,随项目版本控制

·个人 Hook: 放在 ~/.codebuddy/ 下,跨项目复用

41、1. 减少 Hook 执行时间

·使用快速语言: Shell 脚本通常比 Python 启动更快

·避免重复工作: 缓存计算结果

·异步处理: 非关键操作使用后台任务

·提前退出: 尽早判断是否需要处理

示例:

# 不好的做法:每次都加载大文件def main(): with open('huge_config.json', 'r') as f: config = json.load(f) # 每次都读取 # … 处理逻辑# 好的做法:缓存配置CONFIG_CACHE = Nonedef get_config(): global CONFIG_CACHE if CONFIG_CACHE is None: with open('huge_config.json', 'r') as f: CONFIG_CACHE = json.load(f) return CONFIG_CACHE

42、2. 优化 Matcher 配置

{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "/path/to/fast_check.sh", "timeout": 3 } ] }, { "matcher": ".*", "hooks": [ { "type": "command", "command": "/path/to/general_check.py", "timeout": 10 } ] } ] }}

43、3. 并行执行的注意事项

·多个 Hook 会并行执行,不要依赖执行顺序

·避免 Hook 之间的文件写入冲突

·使用文件锁或原子操作处理共享资源

import fcntldef safe_append_log(message): """线程安全的日志写入""" with open('/tmp/hook.log', 'a') as f: fcntl.flock(f.fileno(), fcntl.LOCK_EX) f.write(message + '\\n') fcntl.flock(f.fileno(), fcntl.LOCK_UN)

45、1. 输入验证

永远不要信任输入数据:

def validate_input(input_data): """验证输入数据的完整性""" required_fields = ['hook_event_name', 'session_id'] for field in required_fields: if field not in input_data: raise ValueError(f"Missing required field: {field}") # 验证字段类型 if not isinstance(input_data.get('tool_input'), dict): raise ValueError("tool_input must be a dictionary") return True

46、2. 命令注入防护

不要直接执行用户输入:

# 危险:直接执行os.system(f"echo {user_input}")# 安全:使用参数化import subprocesssubprocess.run(['echo', user_input], check=True)

47、3. 路径遍历防护

import osdef safe_file_access(file_path, project_dir): """确保文件路径在项目目录内""" abs_path = os.path.abspath(file_path) abs_project = os.path.abspath(project_dir) if not abs_path.startswith(abs_project): raise ValueError("Path traversal detected") return abs_path

48、4. 权限最小化

# Hook 脚本应该以最小权限运行# 避免使用 sudo 或 root 权限# 检查权限if os.geteuid() == 0: print("Warning: Running as root is not recommended", file=sys.stderr)

50、条件执行

在 Hook 脚本中根据条件决定是否处理:

def main(): input_data = json.loads(sys.stdin.read()) # 仅在特定条件下处理 if not should_process(input_data): print(json.dumps({"continue": True})) return 0 # 执行处理逻辑 …

51、多规则组合

在一个 Hook 脚本中实现多个规则:

def main(): input_data = json.loads(sys.stdin.read()) # 应用多个规则 for rule in RULES: if rule.matches(input_data): return rule.apply(input_data) # 默认行为 print(json.dumps({"continue": True})) return 0

52、外部服务集成

Hook 可以调用外部 API 或服务:

import requestsdef check_with_external_service(command): response = requests.post('https://api.example.com/validate', json={'command': command}, timeout=5) return response.json()

54、Q1: Hook 没有被执行?

检查清单:

1. 配置文件路径正确 (settings.json 在 .codebuddy 目录下)

2. hooks 字段配置正确,JSON 格式有效

3. matcher 正则表达式能匹配目标

4. Hook 脚本有执行权限 (chmod +x script.py)

5. 脚本路径正确(推荐使用绝对路径)

6. 脚本第一行有正确的 shebang (#!/usr/bin/env python3)

55、Q2: Hook 执行超时?

解决方法:

·增加 timeout 配置值

·优化 Hook 脚本性能

·检查是否有死循环或阻塞操作

56、Q3: 如何调试 Hook 脚本?

调试步骤:

1. 使用 echo 手动传入测试数据

2. 在脚本中使用 sys.stderr 输出调试信息

3. 验证 JSON 格式是否正确

57、Q4: 多个 Hook 的执行顺序?

答案:

·Hook 并行执行,不保证执行顺序

·如需顺序执行,将逻辑合并到一个 Hook 脚本中

·相同命令会自动去重

58、Q5: Hook 修改的参数不生效?

检查要点:

·确保返回了 modifiedInput 字段

·确保 permissionDecision 为 allow

·检查字段名称是否与工具参数匹配

·验证 JSON 格式正确

·确保 continue 为 true

59、Q6: SessionStart Hook 每次请求都触发?

原因: SessionStart 应该只在新会话触发一次

解决方法:

·系统通过 conversationId 跟踪会话

·同一会话中多次请求不会重复触发

·如果仍有问题,查看日志中的会话 ID 是否变化

61、A. 完整的 HookInput 接口定义

interface HookInput { // 通用字段 session_id?: string; // 会话 ID transcript_path?: string; // 对话记录路径 cwd?: string; // 当前工作目录 hook_event_name: string; // Hook 事件名称 // SessionStart 专用(目前仅支持 'startup') source?: 'startup'; // UserPromptSubmit 专用 prompt?: string; // 用户输入内容 // PreToolUse/PostToolUse 专用 tool_name?: string; // 工具名称 tool_input?: Record<string, any>; // 工具输入参数 tool_response?: any; // 工具响应(仅 PostToolUse) // Stop 专用 stop_hook_active?: boolean; // 是否已激活 Stop Hook // PreCompact 专用 trigger?: 'manual' | 'auto'; // 触发方式 custom_instructions?: string; // 自定义压缩指令}

62、B. 完整的 HookOutput 接口定义

interface HookOutput { // 基本控制 continue?: boolean; // 是否继续执行(默认 true) stopReason?: string; // 停止原因 suppressOutput?: boolean; // 是否隐藏输出 systemMessage?: string; // 系统消息 // Hook 特定输出 hookSpecificOutput?: { hookEventName: string; // Hook 事件名称 // PreToolUse 专用 permissionDecision?: 'allow' | 'deny' | 'ask'; permissionDecisionReason?: string; modifiedInput?: Record<string, any>; // SessionStart/UserPromptSubmit/PostToolUse 专用 additionalContext?: string; // 额外上下文 };}

63、C. 环境变量列表

环境变量 说明 示例值
CODEBUDDY_PROJECT_DIR 项目根目录 /path/to/project
CLAUDE_PROJECT_DIR 项目根目录(Claude Code 兼容) /path/to/project

64、D. 退出码详细说明

退出码 含义 stdout stderr 行为
0 成功 作为结果处理 忽略 继续执行,可能注入上下文
1 警告 忽略 作为警告显示 继续执行
2 阻止/反馈 忽略 传递给 Agent PreToolUse: 阻止执行<br>Stop: 提供反馈
其他 错误 忽略 作为警告显示 继续执行

65、E. 常用工具名称列表

注意:配置文件中的 matcher 支持双向别名匹配(写 CLI 风格或 IDE 风格都可以匹配)。但 Hook 脚本接收到的 tool_name 取决于运行环境:

工具名称映射表:

CLI 风格 IDE 风格 功能说明
Read read_file 读取文件
Write write_to_file 写入文件
Edit replace_in_file 编辑/替换文件内容
Glob list_dir 文件模式匹配/搜索文件
Grep search_content 内容搜索
Bash execute_command 执行 Shell 命令
Task task 子代理任务
WebSearch web_search 网络搜索
WebFetch web_fetch 获取网页内容

66、总结

Hook 功能提供了强大的扩展能力,允许你在 AI Agent 的关键节点插入自定义逻辑。通过合理使用 Hook,你可以:

·增强安全性: 验证和阻止危险操作

·自动化流程: 智能修改参数、自动备份文件

·监控审计: 记录工具执行日志

·定制行为: 注入项目特定上下文

开始使用 Hook 功能,让你的 AI Agent 更智能、更安全、更符合项目需求!

Happy Hooking!

赞 (0)
上一篇 4天前
下一篇 4天前