Skip to content

插件

编写你自己的插件来扩展 OpenCode。

插件允许您通过钩入各种事件和自定义行为来扩展 OpenCode。您可以创建插件来添加新功能、与外部服务集成或修改 OpenCode 的默认行为。

有关示例,请查看社区创建的插件


使用插件

有两种加载插件的方式。


从本地文件加载

将 JavaScript 或 TypeScript 文件放置在插件目录中。

  • .opencode/plugin/ - 项目级插件
  • ~/.config/opencode/plugin/ - 全局插件

这些目录中的文件会在启动时自动加载。


从 npm 加载

在您的配置文件中指定 npm 包。

opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-helicone-session", "opencode-wakatime", "@my-org/custom-plugin"]
}

支持常规 npm 包和作用域包。

生态系统中浏览可用的插件。


插件如何安装

npm 插件会在启动时使用 Bun 自动安装。包及其依赖项会被缓存到 ~/.cache/opencode/node_modules/ 目录中。

本地插件直接从插件目录加载。要使用外部包,您必须在配置目录内创建一个 package.json 文件(请参阅依赖项),或者将插件发布到 npm 并将其添加到您的配置中


加载顺序

插件会从所有来源加载,并且所有钩子按顺序运行。加载顺序如下:

  1. 全局配置 (~/.config/opencode/opencode.json)
  2. 项目配置 (opencode.json)
  3. 全局插件目录 (~/.config/opencode/plugin/)
  4. 项目插件目录 (.opencode/plugin/)

具有相同名称和版本的重复 npm 包只加载一次。但是,具有相似名称的本地插件和 npm 插件会分别加载。


创建插件

插件是一个 JavaScript/TypeScript 模块,它导出一个或多个插件函数。每个函数接收一个上下文对象并返回一个钩子对象。


依赖项

本地插件和自定义工具可以使用外部 npm 包。在你的配置目录中添加一个 package.json 文件,包含你需要的依赖项。

.opencode/package.json
{
"dependencies": {
"shescape": "^2.1.0"
}
}

OpenCode 在启动时会运行 bun install 来安装这些依赖项。然后你的插件和工具就可以导入它们。

.opencode/plugin/my-plugin.ts
import { escape } from "shescape"
export const MyPlugin = async (ctx) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "bash") {
output.args.command = escape(output.args.command)
}
},
}
}

基本结构

.opencode/plugin/example.js
export const MyPlugin = async ({ project, client, $, directory, worktree }) => {
console.log("插件已初始化!")
return {
// 钩子实现放在这里
}
}

插件函数接收:

  • project:当前项目信息。
  • directory:当前工作目录。
  • worktree:git 工作树路径。
  • client:一个用于与 AI 交互的 opencode SDK 客户端。
  • $:用于执行命令的 Bun shell API

TypeScript 支持

对于 TypeScript 插件,你可以从插件包导入类型:

my-plugin.ts
import type { Plugin } from "@opencode-ai/plugin"
export const MyPlugin: Plugin = async ({ project, client, $, directory, worktree }) => {
return {
// 类型安全的钩子实现
}
}

事件

插件可以订阅事件,如下面的示例部分所示。以下是可用的事件列表。

命令事件

  • command.executed

文件事件

  • file.edited
  • file.watcher.updated

安装事件

  • installation.updated

LSP 事件

  • lsp.client.diagnostics
  • lsp.updated

消息事件

  • message.part.removed
  • message.part.updated
  • message.removed
  • message.updated

权限事件

  • permission.replied
  • permission.updated

服务器事件

  • server.connected

会话事件

  • session.created
  • session.compacted
  • session.deleted
  • session.diff
  • session.error
  • session.idle
  • session.status
  • session.updated

待办事项事件

  • todo.updated

工具事件

  • tool.execute.after
  • tool.execute.before

TUI 事件

  • tui.prompt.append
  • tui.command.execute
  • tui.toast.show

示例

以下是一些可以用来扩展 opencode 的插件示例。


发送通知

在特定事件发生时发送通知:

.opencode/plugin/notification.js
export const NotificationPlugin = async ({ project, client, $, directory, worktree }) => {
return {
event: async ({ event }) => {
// 会话完成时发送通知
if (event.type === "session.idle") {
await $`osascript -e 'display notification "Session completed!" with title "opencode"'`
}
},
}
}

我们使用 osascript 在 macOS 上运行 AppleScript。这里我们用它来发送通知。


.env 文件保护

防止 opencode 读取 .env 文件:

.opencode/plugin/env-protection.js
export const EnvProtection = async ({ project, client, $, directory, worktree }) => {
return {
"tool.execute.before": async (input, output) => {
if (input.tool === "read" && output.args.filePath.includes(".env")) {
throw new Error("Do not read .env files")
}
},
}
}

自定义工具

插件也可以向 opencode 添加自定义工具:

.opencode/plugin/custom-tools.ts
import { type Plugin, tool } from "@opencode-ai/plugin"
export const CustomToolsPlugin: Plugin = async (ctx) => {
return {
tool: {
mytool: tool({
description: "这是一个自定义工具",
args: {
foo: tool.schema.string(),
},
async execute(args, ctx) {
return `Hello ${args.foo}!`
},
}),
},
}
}

tool 辅助函数创建一个 opencode 可以调用的自定义工具。它接收一个 Zod 模式函数并返回一个工具定义,包含:

  • description:工具的功能描述
  • args:工具参数的 Zod 模式
  • execute:工具被调用时执行的函数

你的自定义工具将与内置工具一起对 opencode 可用。


日志记录

使用 client.app.log() 代替 console.log 进行结构化日志记录:

.opencode/plugin/my-plugin.ts
export const MyPlugin = async ({ client }) => {
await client.app.log({
service: "my-plugin",
level: "info",
message: "插件已初始化",
extra: { foo: "bar" },
})
}

日志级别:debuginfowarnerror。详情请参阅 SDK 文档


压缩钩子

自定义会话被压缩时包含的上下文:

.opencode/plugin/compaction.ts
import type { Plugin } from "@opencode-ai/plugin"
export const CompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// 向压缩提示词中注入额外的上下文
output.context.push(`
## 自定义上下文
包含应在压缩过程中持久化的任何状态:
- 当前任务状态
- 已做出的重要决策
- 正在积极处理的文件
`)
},
}
}

experimental.session.compacting 钩子在 LLM 生成延续摘要之前触发。使用它可以注入默认压缩提示词可能遗漏的领域特定上下文。

您也可以通过设置 output.prompt 来完全替换压缩提示词:

.opencode/plugin/custom-compaction.ts
import type { Plugin } from "@opencode-ai/plugin"
export const CustomCompactionPlugin: Plugin = async (ctx) => {
return {
"experimental.session.compacting": async (input, output) => {
// 替换整个压缩提示词
output.prompt = `
您正在为多智能体集群会话生成一个延续提示词。
请总结:
1. 当前任务及其状态
2. 哪些文件正在被修改以及由谁修改
3. 任何阻塞或智能体之间的依赖关系
4. 完成工作的后续步骤
格式化为新智能体可以用来恢复工作的结构化提示词。
`
},
}
}

当设置了 output.prompt 时,它将完全替换默认的压缩提示词。在这种情况下,output.context 数组将被忽略。