关于 writing-opencode-plugins
用于实现 OpenCode 服务端和 TUI 插件的技能,面向插件开发者。它指导如何选择运行时、核对 API 类型、组织模块,并测试行为与生命周期。
主要功能
- 01选择服务端或 TUI 目标
- 02核对权威插件类型
- 03模块结构与配置指导
- 04测试和生命周期检查清单
适用场景
- 01实现服务端或 TUI 插件
- 02编码前核对插件 API 用法
- 03测试插件加载与清理
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ sveltejs/ ai-tools --skill writing-opencode-plugins安装后在 Claude Code 中输入/writing-opencode-plugins确认已加载。
详细介绍
编写 OpenCode 插件
使用此技能实现可用于生产环境的 OpenCode 插件。请以仓库导出的类型和运行时为准,因为插件 API 仍在演进,公开文档可能滞后。
从这里开始
- 确定哪个运行时负责此功能。
- 编写代码前,先阅读相关的公开类型。
- 查找一个在仓库中使用相同 API 的精简示例。
- 实现最小化的目标专用模块。
- 在所属软件包中测试加载、行为、故障和清理。
| 需求 | 插件目标 | 导入 | 配置 |
|---|---|---|---|
| 钩子、工具、身份验证、提供方、模型参数、Shell 环境 | 服务端 | @opencode-ai/plugin | opencode.json 或自动发现的 .opencode/plugins/*.{ts,js} |
| 命令、键绑定、路由、对话框、插槽、主题、通知 | TUI | @opencode-ai/plugin/tui | 显式的 tui.json plugin 条目 |
| 两者 | 两个目标专用入口点 | 分别在不同文件中导入 | 软件包导出 ./server 和 ./tui |
切勿从同一模块导出 server 和 tui。不要用服务端事件钩子替代交互式 TUI API。
验证当前约定
实现不熟悉的行为前,请先阅读以下文件:
packages/plugin/src/index.ts:权威的服务端插件和钩子类型。packages/plugin/src/tool.ts:自定义工具的架构、上下文、权限、元数据、附件和结果类型。packages/plugin/src/tui.ts:权威的 TUI API 和模块类型。packages/opencode/specs/tui-plugins.md:TUI 加载、打包、生命周期和 API 语义。packages/opencode/src/plugin/shared.ts:目标验证、ID 和入口点解析。packages/opencode/src/plugin/loader.ts:安装、兼容性和导入行为。
如果这些内容与示例或网站文档不一致,请遵循导出的类型和运行时行为,并酌情更新过时的文档。
选择模块形态
对于新的服务端插件,优先使用显式模块对象:
import type { Plugin, PluginModule } from '@opencode-ai/plugin';
const server: Plugin = async ({ client, directory }, options) => ({
dispose: async () => {},
});
export default {
id: 'acme.example',
server,
} satisfies PluginModule & { id: string };
旧式的服务端本地插件可以直接导出插件函数。在旧式模块中,每个不同的命名导出都会被视为一个插件,因此不要导出无关常量。新代码优先使用默认模块对象。
TUI 插件始终使用默认模块对象:
/** @jsxImportSource @opentui/solid */
import type { TuiPlugin, TuiPluginModule } from '@opencode-ai/plugin/tui';
const tui: TuiPlugin = async (api) => {
api.ui.toast({ message: 'Plugin loaded' });
};
export default {
id: 'acme.example-tui',
tui,
} satisfies TuiPluginModule & { id: string };
文件插件必须有稳定且非空的 id。npm 插件可以从软件包名称推导 ID,但明确指定带命名空间的 ID,可让状态、诊断和冲突处理更加清晰。
工程规范
- 使用 TypeScript,并针对公开插件类型使用
satisfies。 - 解析并验证
options;它们以未经验证的Record<string, unknown>形式传入。 - 为插件 ID、命令 ID、路由名称、模式、插槽名称和共享 KV 键添加命名空间。
- 使用插件或工具上下文提供的目录,而非
process.cwd()。 - 对长时间运行或可取消的工作遵循
AbortSignal。 - 使用
client.app.log()进行结构化服务端日志记录,而不是使用console.log。 - 在执行敏感或可能产生重大影响的自定义工具工作前,请求权限。
- 确保通知不会泄露隐私;不要暴露提示词、机密、路径、命令或原始错误。
- 只注册必要的钩子和 UI 资源。如果存在特定钩子,避免订阅范围过广的事件。
- 确保清理操作有界、幂等,并且在仅完成部分初始化后也能安全执行。
- 不要依赖未记录的加载顺序来解决所有权冲突。
测试工作流
服务端插件测试应放在 packages/opencode/test/plugin/ 或最接近的所属子系统下。TUI 运行时测试应放在 packages/opencode/test/cli/tui/;组件级 TUI 测试可以放在 packages/tui。
至少测试以下内容:
- 加载有效性以及目标/入口点选择;
- 配置选项和格式错误的选项;
- 可观察到的行为,而不是重复实现逻辑;
- 中止、失败和部分初始化行为;
- 清理或释放;
- 相关情况下的重复 ID 或注册;
- 发布时本地文件和 npm 打包行为。
请从软件包目录运行测试,切勿从仓库根目录运行。类型检查请在所属软件包中使用 bun typecheck。
审查清单
- 功能位于正确的服务端或 TUI 运行时中。
- 模块结构和导入路径与目标匹配。
- 服务端和 TUI 入口点彼此独立。
- ID 和持久化键稳定且带命名空间。
- 已验证选项和外部数据。
- Hook 输出变更保留其他插件所做的更改。
- 工具正确使用上下文目录、权限、元数据和中止机制。
- 除非有意设为全局,否则 TUI 按键绑定受模式限制。
- TUI 资源和自定义副作用均已释放。
- 软件包导出、
engines.opencode和配置目标正确。 - 测试覆盖行为和生命周期。
参考资料
评论
支持 Markdown