编写与验证第一个 Hook
用 Node.js 读取 stdin 并输出严格 JSON,独立测试后再绑定事件。
This page has not been translated into English yet. The original Chinese version is shown below.
先实现一个只读取字段并记录名称的脚本,再加入路径、内容或结果校验。下面使用 Node.js JSON 解析器,避免依赖对 JSON 的文本正则提取。
最小脚本
将以下内容保存为 .gemini/hooks/log-tool.cjs:
const fs = require('node:fs');
try {
const input = JSON.parse(fs.readFileSync(0, 'utf8'));
if (typeof input.tool_name !== 'string') {
throw new Error('Expected tool_name');
}
console.error(`Tool: ${input.tool_name}`);
console.log(JSON.stringify({}));
} catch (error) {
console.error(error.message);
process.exit(2);
}这是依据官方协议整理的示例,不是官方分发脚本。它只记录工具名称,不记录完整内容;exit 2 在工具前置事件中阻止该次执行。
绑定事件
{
"hooks": {
"BeforeTool": [
{
"matcher": "read_file",
"hooks": [
{
"name": "log-tool",
"type": "command",
"command": "node .gemini/hooks/log-tool.cjs",
"timeout": 5000
}
]
}
]
}
}相对脚本路径需对应 CLI 运行目录。通过 node 调用时不依赖脚本可执行位;直接执行 shell/JS 文件则需按平台配置解释器和权限。
独立测试
printf '%s' '{"tool_name":"read_file"}' | node .gemini/hooks/log-tool.cjs应在 stdout 仅看到 {},在 stderr 看到工具名称。再测试缺少字段、无效 JSON 和自定义拒绝分支,分别检查退出码及两条输出流。这个最小输入只覆盖示例读取的字段,不代表完整 Hook 输入 schema。
接入后检查
在 /hooks panel 检查是否加载、matcher 是否触发、名称是否被禁用,再观察实际事件输入。如果脚本会写日志或缓存,先建立所需目录并限制内容;不要把官方教程中假设已存在的数据库和目录当作自动创建。
扩展到实际校验
输出统一用 JSON.stringify 或其他 JSON 库,尤其当上下文含换行、引号、Git 提交消息时。官方 Git 历史示例直接插入 heredoc,实际生产脚本应正确编码这些字符串。关键词秘密扫描仅是示例,不能当作覆盖所有提交渠道的完整扫描器。