Skip to content

插件完整交付 ​

这一页适合已经写好第一个命令、准备把插件交给别人使用的作者。目标不只是"代码能跑",而是别人能安装、能配置、出错时行为可预期、能在 Console 里观察到,并且能发布到 npm。

按下面六步走,每一步结尾都有可以自查的问题。

1. 先写清楚插件要做什么 ​

动手前列出:用户输入什么、插件输出什么、有哪些副作用(写数据库、发消息、调外部 API),以及怎么验收。然后为每项能力选择一种写法:

需求放在哪里
用户输入的命令commands/*/index.ts
处理每条消息或平台事件middlewares/*/index.ts / handlers/*/index.ts
卡片、图文等富消息components/*/index.tsx
AI 可调用的动作和背景知识tools/、prompt-sections/、skills/
数据库、定时任务、主动推送plugin.ts 的 setup,通过框架资源(Host token)取用

单个能力放约定目录;需要共享资源或生命周期的放 plugin.ts;只有要给整个生态定义一种新能力时才需要写 Feature。

2. 声明包结构 ​

  • package.json#zhin 声明插件包自身的入口(entry)和用到的 Feature(features);插件实例(适配器、子插件、服务)统一在宿主项目的 zhin.config.yml 的 plugins: 下挂载。
  • zhin.config.yml 声明挂载的插件实例与配置值,它不会安装包,也不会启用 Feature。
  • 发布到 npm 的插件入口必须是 JavaScript(./plugin.js);本地项目可以直接用 ./plugin.ts。见 definePlugin · 开发入口与 npm 发布入口。
  • 可选的能力(数据库、HTML 渲染等)声明为 optional peer,并在 setup 里先用 context.resources.has(token)(或在命令/工具里用 context.has(token))判断,缺失时明确降级。

3. 设计配置 ​

用 definePlugin({ config: Schema.object(...) }) 一次性声明默认值、类型、约束和 Console 表单信息,Schema.Output 会推导出配置类型;也可以用根目录的 schema.json(若同时保留由同一 Schema 生成、结构一致的 schema.json,运行时会校验二者等价并放行;isolated 插件只能用 schema.json)。见 definePlugin · 读取配置。

  • 你的 Bot 自身读 plugin: 段,子插件读 <instanceKey> 段。
  • 密钥用 ${VAR} 引用环境变量,不要写进 Schema 默认值或示例仓库。

自查:修改某个配置后,是否需要重载插件?新配置非法时,旧配置是否继续生效?怎样在 Console 里确认新值已经生效?

4. 实现能力并管理生命周期 ​

  • 命令响应用户的明确调用;中间件按顺序处理入站消息;组件负责在不同平台都能显示的富消息。
  • Tool 声明 AI 可以执行的动作;Prompt Section 只补充上下文,不能授予工具或数据权限。
  • 打开的连接、定时器,以及框架资源注册返回的清理函数,都交给 lifecycle(context.lifecycle.add(...)),热重载时自动释放。
  • 必须连接成功后才能允许切换到新版本的资源,用 handoff 登记。新版本准备失败时,不能影响仍在服务的旧版本。

详见 definePlugin · 在热重载时释放资源。

5. 本地验收 ​

  1. 在 Sandbox 里把命令、组件和 AI 的最简单用法各走一遍。
  2. 在 Console 的"运行时能力"里核对每项能力的所属插件、来源、顺序和当前版本。
  3. 修改一个能力文件,确认只有它被重载;故意写错一次配置,确认旧版本继续服务。
  4. 对有副作用的 Tool,验证审批、取消和失败时的结果。
  5. 重启 Bot,确认数据库、会话和定时任务按预期恢复。

6. 测试与发布 ​

插件至少需要:纯函数的单元测试、一个"能力能被发现"的测试、一次完整运行的集成测试,以及一个失败路径的测试。平台适配器还应使用 adapter harness 验证连接生命周期和消息转换。不想手工拼上下文、写 as never 时,用 插件测试 里的假运行环境。

bash
pnpm build
pnpm check:plugin
pnpm check:plugin-runtime-api
pnpm check:plugin-capability-publish

发布前检查 files、ESM 入口、peer dependency、约定目录生成的 JavaScript 以及 changeset;npx @zhin.js/cli plugin check 会自动检查其中的入口、files 与发布包结构(见 CLI 参考)。用打包后的产物安装到一个新项目里,再跑一次 Sandbox 的完整流程——不要只测试 workspace 里的源码。

zhin new --standalone 生成的独立插件在自己的目录里发布:

bash
npx @zhin.js/cli plugin check    # 检查入口、files、约定目录与打包结果
npx @zhin.js/cli pub --dry-run   # 先自动运行 plugin check,再构建并预览 tarball 内容,不发布
npx @zhin.js/cli pub             # 确认后发布;CI 等非交互环境加 --yes

建议写 npx @zhin.js/cli:插件目录里没有安装 @zhin.js/cli 时,npx zhin 会从 npm 下载名为 zhin 的包。从 zhin@4 起它就是 @zhin.js/cli 的别名;但 npx 缓存或锁定里残留的 zhin@3.x 是已停止维护的旧版框架包。Bot 项目里装了 @zhin.js/cli,npx zhin 直接指向它。

插件市场元数据 ​

插件市场(文档站 plugins.json、Console 插件市场、zhin search / zhin info)只读发布到 npm 的 package.json,不执行插件代码。下列字段决定市场里怎么展示你的插件:

字段写法市场里的用途
zhin.metadata.displayName / displayNameI18n同 Console;{ "zh-CN": "...", "en": "..." }卡片标题,按界面语言选择,回退顺序为当前语言 → en → zh-CN → displayName
zhin.metadata.descriptionI18n{ "zh-CN": "...", "en": "..." },非空字符串卡片描述,回退到顶层 description;搜索也会匹配两种语言的描述
zhin.metadata.category下表中的一个值分类筛选。未声明时按包名与 keywords 推断
author{ "name": "...", "url": "..." }作者。市场显示 author,没有时显示 maintainers,不显示发布账号(CI 可信发布时它是「GitHub Actions」)
keywords3–6 个描述功能的词标签与搜索。zhin、zhin.js、zhinjs、zhin-plugin、bot、chatbot、plugin 属于通用词,市场不展示也不参与搜索;保留 zhin.js 方便在 npm 按关键词查找

descriptionI18n 和 category 只能写在 package.json#zhin.metadata,definePlugin() 不接受它们。清单在加载时严格校验:语言键只接受 zh-CN / en,category 必须是下列值之一:

category含义例子
adapter平台适配器Telegram、OneBot 11、飞书
aiAI 能力与推理服务TypeSafe 决策服务
admin运维管理进程监控
community群组运营群运营套件
entertainment娱乐互动点歌、复读机、答案之书
game游戏21 点、成语接龙
information资讯与订阅推送RSS、地震速报、B 站订阅
moderation内容安全内容审核
service给其他能力用的基础服务活动反馈
utility实用工具二维码、短链接、记账、提醒
json
{
  "name": "zhin.js-plugin-weather",
  "description": "Weather forecasts and alerts for any city",
  "keywords": ["zhin.js", "weather", "forecast", "天气"],
  "author": { "name": "your-github-name", "url": "https://github.com/your-github-name/zhin.js-plugin-weather" },
  "zhin": {
    "protocol": 1,
    "type": "plugin",
    "metadata": {
      "displayName": "Weather",
      "displayNameI18n": { "zh-CN": "天气", "en": "Weather" },
      "descriptionI18n": { "zh-CN": "查询城市天气预报与预警", "en": "Weather forecasts and alerts for any city" },
      "category": "information"
    }
  }
}

本仓库的官方插件还由 pnpm check:plugin 检查:必须有两种语言的 descriptionI18n、合法的 category、{ name, url } 形式且不含邮箱的 author,以及 3–6 个非通用 keywords。

发布前的完成标准 ​

  • 新用户照着 README 能完成安装、最小配置并收到第一条回复。
  • 配置错误、依赖缺失和热重载失败都有明确的行为和提示。
  • Console 能观察到运行状态,但不会泄露 Prompt 正文或密钥。
  • 包内文档、公开 API、changeset 与实际发布的 tarball 一致。

下一步 ​