更新时间:2026-05-11 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/

仅对当前项目有效。

个人级

本地~/.codeartsdoer/plugin或

./.codeartsdoer/plugins

本地~/.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。

    在华为云码道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。
      图4 新建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. 在华为云码道IDE工具左上角,单击“文件(F)”,选择“重启IDE”。因为当前Hook脚本不支持实时加载,所以需要重新启动IDE,脚本才可以正常使用。

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

    2. 在输入框中输入“删除文件***,客户端会弹出预警窗口。
      其中,***为待删除文件的名称。
      图5 出现预警窗口

相关文档