插件
编写自己的插件来扩展 OpenCode。
插件允许你通过挂钩各种事件和自定义行为来扩展 OpenCode。你可以创建插件来添加新功能、与外部服务集成或修改 OpenCode 的默认行为。
有关示例,请查看社区创建的插件。
# 使用插件#
有两种方式加载插件。
## 从本地文件#
将 JavaScript 或 TypeScript 文件放在插件目录中。
.opencode/plugin/- 项目级插件~/.config/opencode/plugin/- 全局插件
这些目录中的文件会在启动时自动加载。
## 从 npm#
在配置文件中指定 npm 包。
json1{ 2 "$schema": "https://opencode.ai/config.json", 3 "plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"] 4}
支持普通和作用域 npm 包。
在生态系统中浏览可用插件。
## 插件如何安装#
npm 插件在启动时使用 Bun 自动安装。包及其依赖项缓存在 ~/.cache/opencode/node_modules/ 中。
本地插件直接从插件目录加载。要使用外部包,你必须在配置目录中创建一个 package.json(参见依赖项),或将插件发布到 npm 并添加到配置中。
## 加载顺序#
插件从所有来源加载,所有钩子按顺序运行。加载顺序是:
- 全局配置(
~/.config/opencode/opencode.json) - 项目配置(
opencode.json) - 全局插件目录(
~/.config/opencode/plugin/) - 项目插件目录(
.opencode/plugin/)
具有相同名称和版本的重复 npm 包只加载一次。但是,具有相似名称的本地插件和 npm 插件会分别加载。
# 创建插件#
插件是导出一个或多个插件函数的 JavaScript/TypeScript 模块。每个函数接收一个上下文对象并返回一个钩子对象。
## 依赖项#
本地插件和自定义工具可以使用外部 npm 包。在配置目录中添加一个 package.json,包含你需要的依赖项。
json1// .opencode/package.json 2{ 3 "dependencies": { 4 "shescape": "^2.1.0" 5 } 6}
OpenCode 在启动时运行 bun install 来安装这些依赖。然后你的插件和工具可以导入它们。
typescript1// .opencode/plugin/my-plugin.ts 2import { escape } from "shescape" 3 4export const MyPlugin = async (ctx) => { 5 return { 6 "tool.execute.before": async (input, output) => { 7 if (input.tool === "bash") { 8 output.args.command = escape(output.args.command) 9 } 10 }, 11 } 12}
## 基本结构#
javascript1// .opencode/plugin/example.js 2export const MyPlugin = async ({ project, client, $, directory, worktree }) => { 3 console.log("Plugin initialized!") 4 5 return { 6 // 钩子实现放在这里 7 } 8}
插件函数接收:
project:当前项目信息directory:当前工作目录worktree:git worktree 路径client:用于与 AI 交互的 opencode SDK 客户端$:Bun 的 shell API↗,用于执行命令
## TypeScript 支持#
对于 TypeScript 插件,你可以从插件包导入类型:
typescript1// my-plugin.ts 2import type { Plugin } from "@opencode-ai/plugin" 3 4export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => { 5 return { 6 // 类型安全的钩子实现 7 } 8}
## 事件#
插件可以订阅事件,如下面的示例部分所示。以下是可用的不同事件列表。
命令事件
command.executed
文件事件
file.editedfile.watcher.updated
安装事件
installation.updated
LSP 事件
lsp.client.diagnosticslsp.updated
消息事件
message.part.removedmessage.part.updatedmessage.removedmessage.updated
权限事件
permission.repliedpermission.updated
服务器事件
server.connected
会话事件
session.createdsession.compactedsession.deletedsession.diffsession.errorsession.idlesession.statussession.updated
待办事件
todo.updated
工具事件
tool.execute.aftertool.execute.before
TUI 事件
tui.prompt.appendtui.command.executetui.toast.show
# 示例#
以下是一些可以用来扩展 opencode 的插件示例。
## 发送通知#
当某些事件发生时发送通知:
javascript1// .opencode/plugin/notification.js 2export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => { 3 return { 4 event: async ({ event }) => { 5 // 会话完成时发送通知 6 if (event.type === "session.idle") { 7 await $`osascript -e 'display notification "Session completed!" with title "opencode"'` 8 } 9 }, 10 } 11}
我们使用 osascript 在 macOS 上运行 AppleScript。这里我们用它来发送通知。
注意:如果你使用 OpenCode 桌面应用,它可以在响应准备好或会话出错时自动发送系统通知。
## .env 保护#
防止 opencode 读取 .env 文件:
javascript1// .opencode/plugin/env-protection.js 2export const EnvProtection = async ({ project, client, $, directory, worktree }) => { 3 return { 4 "tool.execute.before": async (input, output) => { 5 if (input.tool === "read" && output.args.filePath.includes(".env")) { 6 throw new Error("Do not read .env files") 7 } 8 }, 9 } 10}
## 自定义工具#
插件还可以向 opencode 添加自定义工具:
typescript1// .opencode/plugin/custom-tools.ts 2import { type Plugin, tool } from "@opencode-ai/plugin" 3 4export const CustomToolsPlugin: Plugin = async (ctx) => { 5 return { 6 tool: { 7 mytool: tool({ 8 description: "This is a custom tool", 9 args: { 10 foo: tool.schema.string(), 11 }, 12 async execute(args, ctx) { 13 return `Hello ${args.foo}!` 14 }, 15 }), 16 }, 17 } 18}
tool 辅助函数创建一个 opencode 可以调用的自定义工具。它接受一个 Zod schema 函数并返回一个工具定义,包含:
description:工具的功能args:工具参数的 Zod schemaexecute:工具被调用时运行的函数
你的自定义工具将与内置工具一起对 opencode 可用。
## 日志记录#
使用 client.app.log() 代替 console.log 进行结构化日志记录:
typescript1// .opencode/plugin/my-plugin.ts 2export const MyPlugin = async ({ client }) => { 3 await client.app.log({ 4 service: "my-plugin", 5 level: "info", 6 message: "Plugin initialized", 7 extra: { foo: "bar" }, 8 }) 9}
级别:debug、info、warn、error。详情请参阅 SDK 文档↗。
## 压缩钩子#
自定义会话压缩时包含的上下文:
typescript1// .opencode/plugin/compaction.ts 2import type { Plugin } from "@opencode-ai/plugin" 3 4export const CompactionPlugin: Plugin = async (ctx) => { 5 return { 6 "experimental.session.compacting": async (input, output) => { 7 // 向压缩提示注入额外上下文 8 output.context.push(`## Custom Context 9 10Include any state that should persist across compaction: 11- Current task status 12- Important decisions made 13- Files being actively worked on`) 14 }, 15 } 16}
experimental.session.compacting 钩子在 LLM 生成续写摘要之前触发。使用它注入默认压缩提示可能遗漏的领域特定上下文。
你也可以通过设置 output.prompt 完全替换压缩提示:
typescript1// .opencode/plugin/custom-compaction.ts 2import type { Plugin } from "@opencode-ai/plugin" 3 4export const CustomCompactionPlugin: Plugin = async (ctx) => { 5 return { 6 "experimental.session.compacting": async (input, output) => { 7 // 替换整个压缩提示 8 output.prompt = `You are generating a continuation prompt for a multi-agent swarm session. 9 10Summarize: 111. The current task and its status 122. Which files are being modified and by whom 133. Any blockers or dependencies between agents 144. The next steps to complete the work 15 16Format as a structured prompt that a new agent can use to resume work.` 17 }, 18 } 19}
当设置 output.prompt 时,它会完全替换默认压缩提示。在这种情况下,output.context 数组会被忽略。