词元之母TOK.MOM - 平台充值汇率 1:1 即 1 人民币充值到账 1 美元,支持一个 Key 调用近 600+ 海内外模型,限时特价模型低至 1 折,欢迎上岸!

💡 一句话总结:Hook 是 OpenCode 的"扩展接口",你可以在事件发生时执行逻辑,或在关键流程中拦截并修改数据。
不吹牛,只写「立刻能干」的事
如果你正在经历这些,这课就是给你的
不是每天都用,但用到就很爽
确保你已经完成以下事项,否则请先停下
先讲「怎么想」,不讲命令
opencode.json 里配置命令(更简单,但功能有限)| Hook | 说明 | 用途 |
|---|---|---|
tool.definition | 修改工具定义 | 自定义工具描述、调整参数 Schema |
command.execute.before | 命令执行前拦截 | 修改命令参数、添加日志 |
shell.env | Shell 执行前 | 注入环境变量 |
一步一步来,假设你会犯错
// .opencode/plugin/notify.ts
import type { Plugin } from "@opencode-ai/plugin"
export const NotifyPlugin: Plugin = async ({ $ }) => {
return {
event: async ({ event }) => {
if (event.type === "session.idle") {
await $`osascript -e 'display notification "会话已完成" with title "OpenCode"'`
}
},
}
}tool.execute.before Hook 拦截工具调用,阻止 AI 读取敏感文件。// .opencode/plugin/guard.ts
import type { Plugin } from "@opencode-ai/plugin"
export const GuardPlugin: Plugin = async () => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool !== "read") return
const filePath = String(output.args.filePath)
const sensitivePatterns = [".env", ".pem", ".key", "credentials"]
for (const pattern of sensitivePatterns) {
if (filePath.includes(pattern)) {
throw new Error(`安全策略:禁止读取敏感文件:${filePath}`)
}
}
},
}
}.env 文件时,会抛出错误并阻止执行。chat.params Hook 自动调整。// .opencode/plugin/params.ts
import type { Plugin } from "@opencode-ai/plugin"
export const ParamsPlugin: Plugin = async () => {
return {
"chat.params": async (input, output) => {
// 代码生成需要更确定性的输出
if (input.agent === "code") {
output.temperature = 0.2
}
// 规划任务需要更多创造性
if (input.agent === "plan") {
output.temperature = 0.7
}
// 添加自定义追踪头
output.options["X-Trace-Session"] = input.sessionID
},
}
}// .opencode/plugin/auto-permit.ts
import type { Plugin } from "@opencode-ai/plugin"
export const AutoPermitPlugin: Plugin = async () => {
return {
"permission.ask": async (input, output) => {
// 读取操作自动允许
if (input.tool === "read") {
output.status = "allow"
return
}
// 危险命令自动拒绝
if (input.tool === "bash" && String(input.metadata?.command).includes("rm -rf")) {
output.status = "deny"
return
}
// 其他操作保持询问
output.status = "ask"
},
}
}// .opencode/plugin/compaction.ts
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async () => {
return {
"experimental.session.compacting": async (input, output) => {
output.context.push(`
## 项目关键信息
- 正在修改的文件:src/**
- 关键约束:禁止读取 .env、密钥文件
- 当前任务:实现 Hook 教程并加入侧边栏
- 重要决策:使用 TypeScript 严格模式
`)
},
}
}// .opencode/plugin/tool-definition.ts
import type { Plugin } from "@opencode-ai/plugin"
export const ToolDefinitionPlugin: Plugin = async () => {
return {
"tool.definition": async (input, output) => {
// 为 read 工具添加中文描述
if (input.toolID === "read") {
output.description = "读取文件内容。支持文本文件和图片。路径必须是绝对路径。"
}
// 为 bash 工具添加安全提示
if (input.toolID === "bash") {
output.description += "\n\n⚠️ 注意:危险命令(如 rm -rf)需要用户确认。"
}
// 修改参数 Schema(例如添加默认值或约束)
if (input.toolID === "write" && output.parameters?.properties?.filePath) {
output.parameters.properties.filePath.description = "文件绝对路径,必须以 / 开头"
}
},
}
}全部通过才能继续;任一项失败,回到第 X 步重来
.opencode/plugin/ 目录.env 时抛出了错误80% 的人会卡在这里
| 现象 | 原因 | 解决 |
|---|---|---|
| 插件未加载 | 文件扩展名错误 | 确保是 .ts 或 .js 文件 |
output 修改无效 | 返回了新对象而非修改原对象 | 直接修改 output.xxx = ... |
| 事件没触发 | event.type 拼写错误 | 用 TypeScript 获得类型提示 |
| 实验性 Hook 失效 | 版本更新后 API 变化 | 查看更新日志,调整代码 |
| 配置 Hook 不生效 | 可能未实现执行逻辑 | 优先使用插件 Hook |
| 多个插件冲突 | Hook 重复定义 | 检查是否有重复的 Hook 实现 |
下一课我们将学习自定义工具,需要用到本课的 Hook 和插件知识。
开发时最常用的 10 个 Hook,快速参考
| Hook | 触发时机 | 用途 | 是否可修改数据 |
|---|---|---|---|
event | 所有事件 | 统一订阅 ,日志/通知/统计 | ❌ |
config | 配置加载后 | 初始化插件,修改配置 | ✅ |
tool.execute.before | 工具执行前 | 拦截/修改参数,阻止执行 | ✅ |
tool.execute.after | 工具执行后 | 记录结果,修改输出 | ✅ |
chat.message | 新消息接收时 | 记录/修改消息内容 | ✅ |
chat.params | LLM 调用前 | 修改温度/Top-P/Top-K | ✅ |
permission.ask | 权限请求时 | 自动允许/拒绝 | ✅ |
tool | 注册工具 | 添加自定义工具 | - |
experimental.session.compacting | 会话压缩前 | 注入项目关键信息 | ✅ |
tool.definition | 工具注册时 | 修改工具描述/参数 | ✅ |
command.execute.before | 命令执行前 | 拦截/修改命令参数 | ✅ |
shell.env | Shell 执行前 | 注入环境变量 | ✅ |
auth | 认证流程 | 自定义认证方式 | - |
开发时最常用的 10 个事件,快速参考
| 事件 | 说明 | Hook 用途 |
|---|---|---|
session.idle | 会话完成(空闲) | 发送通知、清理资源、记录耗时 |
session.created | 新会话创建 | 初始化会话级状态 |
file.edited | 文件被编辑 | 触发格式化、触发构建 |
message.updated | 消息更新 | 记录对话历史、统计 |
tool.execute.after | 工具执行后 | 记录日志、审计追踪 |
tool.execute.before | 工具执行前 | 参数验证、权限检查 |
permission.replied | 用户响应权限 | 记录权限决策 |
command.executed | 命令执行后 | 命令审计 |
session.error | 会话错误 | 错误上报、通知 |
server.connected | 服务器连接 | 连接状态通知 |
| 功能 | 文件路径 | 行号 |
|---|---|---|
| Hook 类型定义 | packages/plugin/src/index.ts | 148-231 |
tool.definition Hook 定义 | packages/plugin/src/index.ts | 227-230 |
tool.definition Hook 触发 | packages/opencode/src/tool/registry.ts | 157 |
| 插件加载逻辑 | packages/opencode/src/plugin/index.ts | 20-82 |
| 插 件目录扫描 | packages/opencode/src/config/config.ts | 322-335 |
| 插件去重逻辑 | packages/opencode/src/config/config.ts | 369-387 |
| 配置 Hook Schema | packages/opencode/src/config/config.ts | 1009-1030 |