Hooks

更新时间:
复制为 MD 格式

Hooks 让您可以在通义Qoder CN IDE 执行的关键节点插入自定义逻辑,而无需修改任何代码。您只需编辑 JSON 配置文件,就能实现诸如:

  • 在工具执行前拦截危险操作

  • 写文件后自动跑 lint,保持代码风格一致

  • Agent 完成任务时弹出桌面通知,不用一直盯着 IDE

与 Prompt 指令不同,Hooks 是确定性的——只要事件触发,脚本就一定执行,不受模型理解偏差的影响。

支持的事件

当前通义Qoder CN IDE 支持以下五种 Hook 事件:

事件名称

触发时机

可阻断

UserPromptSubmit

用户提交 Prompt 后、Agent 处理前

PreToolUse

工具调用执行前

PostToolUse

工具调用成功后

PostToolUseFailure

工具调用失败后

Stop

Agent 完成响应时

快速开始

下面以拦截 rm -rf 这类危险命令为例,演示 Hooks 的配置流程。

步骤一:创建脚本

mkdir -p ~/.lingma/hooks
cat > ~/.lingma/hooks/block-rm.sh << 'EOF'
#!/bin/bash
input=$(cat)
command=$(echo "$input" | jq -r '.tool_input.command')

if echo "$command" | grep -q 'rm -rf'; then
  echo "危险命令已被阻止: $command" >&2
  exit 2
fi

exit 0
EOF
chmod +x ~/.lingma/hooks/block-rm.sh

步骤二:添加配置

~/.lingma/settings.json 中添加:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "~/.lingma/hooks/block-rm.sh"
          }
        ]
      }
    ]
  }
}

步骤三:验证效果

重启 IDE,在Qoder CN面板中让 Agent 执行包含 rm -rf 的命令。Hook 会阻止执行,并把错误信息反馈给 Agent。

适用场景

场景

对应事件

说明

拦截危险命令

PreToolUse

在 Agent 执行 rm -rfDROP TABLE 等命令前阻止

文件路径校验

PreToolUse

限制 Agent 只能在指定目录下创建或编辑文件

自动 Lint / 格式化

PostToolUse

每次写文件后自动执行 ESLint / Prettier

日志审计

PostToolUse

记录 Agent 的所有工具调用,用于安全审计

失败监控告警

PostToolUseFailure

工具调用失败时发送告警或记录错误日志

Prompt 内容审查

UserPromptSubmit

检测用户输入中是否包含敏感信息(密码、密钥等)

自动注入上下文

UserPromptSubmit

自动在 Prompt 末尾追加项目规范或编码约定

桌面通知

Stop

Agent 完成后弹出系统通知提醒用户

工作原理

Hook 的使用流程可以概括为三步:编写脚本 → 注册配置 → 自动生效。

当 Agent 执行到某个生命周期节点时(如工具调用前),插件会检查配置中是否有对应的 Hook:

  1. IDE 在启动时加载所有 Hook 配置。

  2. Agent 运行过程中,到达某个事件节点(如 PreToolUse)。

  3. 遍历该事件下所有 Hook 分组,用 matcher 匹配当前上下文。

  4. 匹配成功的 Hook 按顺序执行对应的 shell 脚本。

  5. 脚本通过 stdin 接收事件上下文(JSON),通过 exit code 和 stdout 返回决策。

  6. IDE 根据返回结果决定后续行为(放行或阻断)。

前置条件

  • jq:示例脚本依赖 jq 解析 JSON。macOS 下执行 brew install jq,Linux 下执行 apt install jq

  • 脚本权限:所有 Hook 脚本需要有可执行权限(chmod +x)。

创建 Hooks

步骤一: 确定需求:选择事件和匹配范围

首先明确您要在哪个节点介入,以及匹配什么条件:

我想在「什么时候」拦截 / 处理「什么操作」?
        ↓                         ↓
     选择事件                  编写 matcher

需求

事件

matcher

Agent 执行任何 Shell 命令前检查

PreToolUse

"Bash"

Agent 写入或编辑文件后做处理

PostToolUse

"Write | Edit"

Agent 工具调用失败时记录

PostToolUseFailure

"Bash" 或不填

用户提交的所有 Prompt 做审查

UserPromptSubmit

不填(匹配所有)

Agent 停止时触发通知

Stop

不填(匹配所有)

只拦截 MCP 工具

PreToolUse

"mcp__.*"

步骤二:编写 Hook 脚本

Hook 脚本是一个标准的 shell 脚本,遵循以下协议:

  • 输入:通过 stdin 接收 JSON 格式的事件上下文

  • 输出:通过 exit code 控制行为

exit 0   →  放行(继续执行)
exit 2   →  阻断(停止操作,stderr 注入对话)
其他值   →  错误(继续执行,stderr 展示给用户)

脚本模板

#!/bin/bash

# 1. 读取 stdin 的 JSON 输入
input=$(cat)

# 2. 用 jq 提取你关心的字段
#    不同事件有不同的字段,具体见「事件参考」章节
tool_name=$(echo "$input" | jq -r '.tool_name')
tool_input=$(echo "$input" | jq -r '.tool_input')

# 3. 编写你的判断逻辑
if [ "$tool_name" = "Bash" ]; then
  command=$(echo "$input" | jq -r '.tool_input.command')

  # 检查是否包含危险操作
  if echo "$command" | grep -qE 'rm\s+-rf|DROP\s+TABLE'; then
    # 阻断:exit 2 + stderr 消息会反馈给 Agent
    echo "操作被拒绝: $command" >&2
    exit 2
  fi
fi

# 4. 放行
exit 0

除了 exit code,您还可以在 exit 0时输出 JSON 来提供更精细的控制:

#!/bin/bash
input=$(cat)

# 输出 JSON 实现精细控制(仅 exit 0 时生效)
echo '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"该操作不被允许"}}'
exit 0

步骤三:注册到配置文件

将脚本路径写入配置文件的对应事件下:

{
  "hooks": {
    "事件名": [
      {
        "matcher": "匹配条件(可选)",
        "hooks": [
          {
            "type": "command",
            "command": "脚本路径"
          }
        ]
      }
    ]
  }
}

步骤四:测试与调试

可以直接在终端用管道模拟测试:

# 模拟 PreToolUse 事件
echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"},"hook_event_name":"PreToolUse"}' \
  | ~/.lingma/hooks/block-rm.sh
echo "Exit code: $?"

检查 stderr 输出(阻断消息):

echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /"}}' \
  | ~/.lingma/hooks/block-rm.sh 2>&1

配置 Hooks

配置文件位置

Hook 配置从以下文件加载,多级配置会被合并执行(优先级从低到高):

位置

作用域

优先级

可共享

说明

~/.lingma/settings.json

用户级

1(最低)

用户个人配置,对所有项目生效

.lingma/settings.json

项目级

2

可提交到 Git,团队共享

.lingma/settings.local.json

项目级(本地)

3

建议加入 .gitignore,个人开发配置

说明

当前版本暂不支持热加载,修改配置文件后需要重启 IDE 才能生效。

配置格式

{
  "hooks": {
    "事件名": [
      {
        "matcher": "匹配条件",
        "hooks": [
          {
            "type": "command",
            "command": "要执行的命令"
          }
        ]
      }
    ]
  }
}

字段

必填

说明

type

固定为 "command"

command

要执行的 shell 命令或脚本路径

timeout

超时时间(秒),默认 30

matcher

匹配条件,不填则匹配该事件的所有触发

一个事件下可以配置多个 matcher 分组,每个分组可以包含多个 Hook 命令。

matcher 匹配规则

matcher 用于过滤 Hook 的触发范围,不同事件匹配不同的字段(见各事件说明)。

写法

含义

示例

不填或 "*"

匹配所有

所有工具都会触发

精确值

精确匹配

"Bash" 只在 Bash 工具时触发

| 分隔

匹配多个值

"Write | Edit" 在 Write 或 Edit 时触发

正则表达式

正则匹配

"mcp__.*" 匹配所有 MCP 工具

工具名映射

Qoder CN支持两套工具名——原生工具名与兼容工具名。配置 Hook 时可使用任意一套,运行时会统一映射后执行匹配。例如 matcher: "Bash"matcher: "run_in_terminal" 等价。

原生名

兼容名

说明

run_in_terminal

Bash

执行 shell 命令

read_file

Read

读取文件内容

create_file

Write

创建 / 写入文件

search_replace

Edit

编辑文件

delete_file

-

删除文件

grep_code

Grep

搜索文件内容

search_file

Glob

文件名匹配

list_dir

LS

列出目录

task

Task

启动子任务 / 子代理

mcp__<server>__<tool>

同左

MCP 工具

编写 Hook 脚本

Hook 脚本通过 stdin 接收 JSON 输入,通过 exit code 和 stdout 输出来控制行为。本节说明所有事件通用的输入输出格式,各事件的额外字段见事件参考

输入

Hook 脚本通过 stdin 接收 JSON 数据。所有事件都包含以下通用字段:

字段

说明

session_id

当前会话 ID

cwd

当前工作目录

hook_event_name

触发的事件名称

transcript_path

会话上下文 JSON 文件路径

不同事件会在此基础上附加额外字段(见下文事件参考)。用 jq 解析输入:

#!/bin/bash
input=$(cat)
tool_name=$(echo "$input" | jq -r '.tool_name')

输出

Hook 通过 exit code 和 stdout 控制行为。

exit code 决定基本行为:

Exit Code

含义

行为

0

成功

继续执行,尝试解析 stdout JSON

2

阻断

停止操作,stderr 内容注入对话(仅对支持阻断的事件)

其他值

错误

继续执行,stderr 内容仅展示给用户

stdout JSON(仅 exit 0 时生效,可选):

{
  "continue": true,
  "stopReason": "",
  "suppressOutput": false,
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow | deny | ask",
    "permissionDecisionReason": "说明原因"
  }
}

事件参考

UserPromptSubmit

  • 触发:用户提交 Prompt 后、Agent 处理前

  • 可阻断:是(exit 2 阻止本次请求)

  • 额外字段prompt(用户输入的原始文本)

PreToolUse

  • 触发:工具调用执行前

  • 可阻断:是(exit 2 拒绝本次工具调用)

  • 匹配字段tool_name

  • 额外字段tool_nametool_input

PostToolUse

  • 触发:工具调用成功后

  • 可阻断:否

  • 匹配字段tool_name

  • 额外字段tool_nametool_inputtool_response

PostToolUseFailure

  • 触发:工具调用失败后

  • 可阻断:否

  • 匹配字段tool_name

  • 额外字段tool_nametool_inputerror

Stop

  • 触发:Agent 完成响应时

  • 可阻断:否

  • 额外字段stop_hook_activelast_assistant_message

常见问题

修改配置后为什么没生效?

当前版本不支持热加载,修改 settings.json 后需要重启 IDE。

Hook 脚本执行超时会怎样?

默认 30 秒超时,超时视为错误(继续执行,stderr 展示给用户)。

多个 Hook 执行顺序如何确定?

同一事件下按配置声明顺序执行;跨配置文件时,按「用户级 → 项目级 → 项目本地」优先级从低到高依次执行。

Hook 脚本能访问哪些环境变量?

Hook 在当前项目根目录(cwd)下以当前用户身份执行,继承 IDE 进程的环境变量。

如何查看 Hook 执行日志?

Hook 的 stderr 输出会反馈给 Agent 或用户;详细调用日志可在Qoder CN运行时日志中查找 [hook] 前缀的条目。