更新时间:2026-09-10 GMT+08:00
分享

Hooks

通过Hook(钩子),您可以在码道IDE及插件的关键生命周期节点中插入自定义逻辑,实现功能扩展,而无需更改任何现有代码。

与依赖模型理解的Prompt指令不同,Hooks的执行是确定性的,即一旦事件被触发,绑定的脚本将稳定、可靠地执行,不受模型理解偏差的影响。

约束与限制

表1 约束限制

限制类别

具体限制

功能限制

当前Hook脚本不支持实时加载,需要重新加载才可使用。

语言限制

Hook脚本仅支持JavaScript/TypeScript语言。

外部依赖

如果使用外部依赖包,您需要在Hook所在的配置目录创建package.json文件,并声明需要使用的依赖。

支持的Hook事件

表2 支持的Hook事件

事件分类

事件名称

触发时机

可阻断

典型使用场景

说明

聊天消息

chat.message

用户发送消息后、进入处理流程前

是

聊天消息处理

新消息到达时自动触发,支持对消息内容及Parts进行编辑

聊天参数

chat.params

每次调用LLM前

是

聊天参数修改

支持动态调整大模型推理参数,包含temperature、topP、topK等,按需优化模型输出结果

聊天请求头

chat.headers

每次调用LLM前

是

聊天请求头修改

支持自定义修改HTTP请求头字段,适配网络代理、接口鉴权等复杂场景需求

聊天响应

chat.response

LLM返回响应后

否

聊天响应记录

自动捕获模型响应的Tokens、Cost、Duration等核心指标,实现精准计费统计、高效故障排查与完整日志留存

聊天错误

chat.error

LLM调用发生错误时

否

聊天错误记录

记录LLM调用失败时的错误日志

聊天压缩

chat.compression

上下文压缩时

否

聊天压缩记录

记录上下文压缩前后的Token数量,辅助存储与性能调优

聊天结束

chat.finished

聊天会话结束时

否

聊天结束记录

记录会话结束事件,包含本次运行的Token消耗和运行信息

用户审批

user.approval

需要用户确认/审批操作时

是

用户审批记录

拦截高风险操作,发起人工确认审批,管控敏感操作执行权限

Turn结束

turn.end

每个对话轮次结束时

否

Turn结束记录

记录每轮对话结束日志,包含处理耗时、终止原因等关键信息

命令执行

command.execute.before

命令执行前

是

命令执行前置处理

支持对Parts进行自定义配置,实现命令的前置处理与灵活适配

工具执行

tool.execute.before

工具执行前

是

工具执行前置参数调整

支持在工具执行前自定义修改参数args,实现校验、动态改写与业务适配

tool.execute.after

工具执行后

是

工具执行后置结果处理

支持自定义修改返回结果,包括title、output及metadata字段

工具定义

tool.definition

工具定义发送给LLM前

是

工具定义修改

支持在工具推送模型前自定义配置描述与参数,确保精准适配业务场景

Shell环境

shell.env

获取Shell环境变量时

是

Shell环境变量配置管理

获取Shell环境变量时,支持添加或修改环境变量

权限请求

permission.ask

需要权限验证时

是

权限请求处理

处理权限校验请求,支持配置allow(允许)、deny(拒绝)、ask(询问)三种策略

消息转换

experimental.chat.messages.transform

消息列表发送给LLM前

是

消息转换

支持在模型上报前预处理聊天消息列表

系统消息转换

experimental.chat.system.transform

系统提示词发送前

是

系统消息转换

支持在系统提示词发送前优化指令内容

会话压缩

experimental.session.compacting

上下文压缩开始前

是

会话压缩

支持在执行上下文压缩前,自定义压缩提示词

文本补全

experimental.text.complete

文本补全完成时触发

是

文本补全结果定制

文本补全完成后,支持对输出内容进行修改

配置加载

config

应用启动配置加载时

否

配置加载

在加载自定义配置时触发,用于执行配置初始化及动态参数注入

通用事件

event

订阅所有Bus事件时触发

否

事件处理

通用事件处理

插件及依赖文件存放路径

插件是一个JavaScript/TypeScript模块,通过导出插件函数来工作。每个函数接收一个上下文对象,并返回对应的Hook对象。如果插件文件中需要使用外部包,必须在配置目录中创建package.json文件并配置所需的依赖项。华为云码道代码智能体在启动时会自动安装这些依赖项。

表3 插件文件加载路径

插件类型

插件文件存放路径

插件依赖文件存放路径

说明

项目级

当前项目根目录./.codeartsdoer/plugin或./.codeartsdoer/plugins

当前项目根目录./.codeartsdoer/

仅对当前项目有效。

个人级

本地%USERPROFILE%/.codeartsdoer/plugin或

%USERPROFILE%/.codeartsdoer/plugins

本地%USERPROFILE%/.codeartsdoer/

对当前用户下所有项目均有效。

快速入门

以下通过一个简单示例,演示如何对用户输入中的密码、密钥等敏感信息进行过滤,有效防止数据泄露。

  1. 创建插件文件存放目录。

    在项目根目录“./.codeartsdoer”下新建一个目录plugin。

    图1 新建plugin目录

  2. 创建脚本。

    在plugin目录下,新建文件sensitiveInfoFilteringPlugin.ts,在插件文件中编写Hook逻辑代码,并保存文件。

    //导入Plugin类型,用于定义插件
    import type { Plugin } from "@opencode-ai/plugin"
    
    
    //导出插件实现,Plugin是一个异步函数,接收插件输入参数并返回Hooks对象
    export const SensitiveInfoFilteringPlugin: Plugin = async ({}) => {
      //返回一个Hooks对象,包含各种钩子函数
      return {
        //监听工具执行后的钩子,在工具执行完成后触发
        "tool.execute.after": async (
          //输入参数:包含工具名称、会话ID、调用ID、推理ID等信息
          input: { tool: string; sessionID: string; callID: string; args: any },
          //输出参数:包含工具执行结果的标题、输出内容、元数据
          output: {
            title: string
            output: string
            metadata: any
          },
        ) => {
          //判断是否为读取文件操作(tool 名称为 "read")且输出内容存在
          if (input.tool === "read" && output.output) {
            //敏感信息匹配模式(支持JSON和其他常见格式)
            //匹配"password": "value"或password: value格式
            //第一个正则:匹配JSON 格式,如 "password": "***"
            //第二个正则:匹配普通键值对格式,如password=***或password:***
            const sensitivePatterns = [
              //匹配JSON格式的敏感字段:双引号包裹的键名 + 冒号 + 双引号包裹的值
              new RegExp(`"(password|passwd|pwd|api[_-]?key|secret|token)"\\s*:\\s*"([^"]+)"`, "g"),
              //匹配普通格式的敏感字段:键名 + 冒号或等号 + 不带引号的值
              new RegExp(`(password|passwd|pwd|api[_-]?key|secret|token)\\s*[:=]\\s*([^"'\\s\\\\]+)`, "gi"),
            ]
            //将工具输出的内容赋值给局部变量content,方便后续处理
            let content = output.output
    
    
            //遍历所有敏感信息匹配模式,逐一进行替换处理
            for (const pattern of sensitivePatterns) {
              //使用replace方法进行替换,传入回调函数处理匹配结果
              //match:完整匹配的字符串
              //key:捕获组1,即敏感字段名(password、api_key等)
              //value:捕获组2,即敏感字段的值(如密码、密钥的实际内容)
              content = content.replace(pattern, (match, key, value) => {
                //如果匹配到敏感信息,将实际值替换为[敏感信息]占位符
                return match.replace(value, "[敏感信息]")
              })
            }
            //更新output对象中的output字段,将过滤后的内容写回
            output.output = content
          }
        }
      }
    }

  3. 重启IDE。

    在工具左上角,单击“文件(F)”,选择“重启IDE”。因为当前Hook脚本不支持实时加载,所以需要重新启动IDE,脚本才可以正常使用。

    为确保脚本生效,建议在任务管理器中结束掉所有Bun进程,以彻底清除残留实例。

  4. 验证效果。

    在输入框中输入指令后,模型返回的结果中敏感信息已自动脱敏。

    图2 模型返回效果

创建Hooks

  1. 选择对应的事件。

    请根据实际业务需求,从支持的Hook事件中匹配并选择对应的事件名称。

  2. 编写Hook脚本。

    1. 创建插件文件。

      在插件及依赖文件存放路径目录下,新建“.ts”或“.js”文件。

    2. 编写Hook逻辑。

      在Hook事件参考内容中,找到“// Hook implementations go here”注释位置,并在此处根据实际需求编写具体的Hook实现代码。

  3. (可选)配置依赖。

    如果插件文件中需要使用外部包,必须在插件及依赖文件存放路径的配置目录中创建package.json文件并配置所需的依赖项。
    {
      "dependencies": {
        "依赖包名1": "版本号",
        "依赖包名2": "版本号"
      }
    }

    package.json文件具体示例如下:

    {
      "dependencies": {
        "@opencode-ai/plugin": "*",
        "@babel/core": "7.29.0",
        "@langfuse/otel": "4.5.1"
      }
    }

  4. 重启IDE验证效果。

Hook事件参考

支持的Hook事件示例如下。请在“// Hook implementations go here”注释处编写具体的实现逻辑,代码编写完成后即可直接使用。

场景示例

以“删除文件前弹窗进行高危操作提示”为例,向您详细介绍如何使用Hook。本示例以项目级,plugin目录为例。

  1. 根据支持的Hook事件中场景描述,选择对应的事件。

    删除文件会调用工具,一般是deleteFile工具,要在删除文件前弹窗,所以此处选择事件“tool.execute.before”。

  2. 编写Hook脚本。

    1. 在项目根目录“./.codeartsdoer”下,新建一个目录plugin。
      图3 新建plugin目录
    2. 在plugin目录下,新建文件deleteFileHintPlugin.ts。
    3. 编写脚本,并保存文件。
      //导入OpenCode插件类型定义
      import type {Plugin} from "@opencode-ai/plugin";
      //导入Node.js子进程模块,用于执行系统命令
      import { exec } from "child_process";
      //导入util模块的promisify函数,用于将回调式函数转为Promise
      import { promisify } from "util";
      //将exec回调函数转换为Promise形式的异步函数
      const execAsync = promisify(exec);
      //定义并导出插件,接收client参数(用于与OpenCode交互)
      export const DeleteFileHintPlugin: Plugin = async ({ client }) => {
        //返回插件的hook集合
        return {
          //监听工具执行前的钩子
          "tool.execute.before": async (
            //输入参数:工具名称、会话ID、调用ID、推理ID
            input: { tool: string; sessionID: string; callID: string; inferenceID?: string },
            //输出参数:工具调用时的参数
            output: { args: any }
          ) => {
            // 判断是否为删除文件操作
            if (input.tool === "deleteFile") {
              //定义弹出警告框的消息内容
              const message = `删除文件是高危操作,请谨慎执行!`
              //根据不同操作系统执行不同的命令
              if (process.platform === "win32") {
                //Windows系统:使用PowerShell调用系统MessageBox
                const cmd = `powershell -NoProfile -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.MessageBox]::Show('${message}', '警告', 'OK', 'Warning')"`
                await execAsync(cmd)
              } else if (process.platform === "darwin") {
                //macOS系统:使用osascript调用系统弹窗
                const cmd = `osascript -e 'display alert "警告" message "${message}"'`
                await execAsync(cmd)
              } else if (process.platform === "linux") {
                //Linux系统:使用notify-send发送桌面通知
                const cmd = `notify-send "警告" "${message}"`
                await execAsync(cmd)
              }
            }
          }
        }
      }

  3. 重启IDE验证效果。

    1. 在工具左上角,单击“文件(F)”,选择“重启IDE”。因为当前Hook脚本不支持实时加载,所以需要重新启动IDE,脚本才可以正常使用。

      为确保脚本生效,建议在任务管理器中结束掉所有Bun进程,以彻底清除残留实例。

    2. 在输入框中输入“删除文件***”,客户端会弹出预警窗口。

      其中,***为待删除文件的名称。

相关文档