manifest.json 规范
manifest.json 规范
Section titled “manifest.json 规范”每个插件包的 ZIP 根目录必须有一个 manifest.json。它是容器认识插件的入口——告诉容器这是什么插件、叫什么、支持哪些平台、内部有哪些文件。
公共字段(所有类型都有)
Section titled “公共字段(所有类型都有)”| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
id |
string | 是 | — | reverse-DNS 风格插件 id |
type |
string | 是 | — | "friend" / "application" / "pack" |
name |
string | 是 | — | 展示名称 |
description |
string | 是 | — | 一句话描述 |
version |
string | 是 | — | 语义化版本号 |
author |
string | 是 | — | 作者或组织名 |
icon |
string | 否 | null |
包内图标资源的相对路径 |
system |
boolean | 否 | false |
系统插件(不可卸载),社区插件别设 |
uninstallable |
boolean | 否 | true |
是否允许用户卸载 |
defaultEnabled |
boolean | 否 | false |
安装后是否默认启用 |
platforms |
object | 否 | 空对象 | 平台兼容性矩阵,见下 |
platforms 子对象
Section titled “platforms 子对象”"platforms": { "supported": ["android", "wearos", "windows", "linux", "macos"], "optimized": ["android"], "fallback": { "windows": "无震动反馈" }}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
supported |
string[] | 是 | 支持运行的平台 id 列表;当前平台不在里面则拒绝 enable |
optimized |
string[] | 否 | 最佳体验平台,信息性字段 |
fallback |
object | 否 | 平台降级说明,{平台id: 说明文字} |
合法平台 id:android / wearos / windows / linux / macos。传别的值会在加载时抛 ArgumentError。
公共字段由 PluginManifest.parseBase() 解析。id / type / name / description / version / author 这六个字段缺一个或类型不对都会抛 FormatException——插件加载失败,出现在插件管理页的“加载失败”列表里。platforms 缺失时退化为空(任何平台都不支持,但插件仍会加载展示)。
Friend 专属字段
Section titled “Friend 专属字段”{ "id": "moodpet.friend.default_smiley", "type": "friend", "interfaces": { "personality": "system_prompt.txt", "expression": "emoji_mapping.json", "identity": "assets/identity.json", "voice": null, "ui": null, "rules": null }, "dependencies": { "minContainerVersion": "1.0.0", "plugins": [], "services": [] }, "configSchema": { "greeting": { "type": "string", "default": "嗨,我在呢", "label": "打招呼语" } }}interfaces(必填)
Section titled “interfaces(必填)”| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
personality |
string | 是 | system_prompt.txt 的相对路径,加载时必读 |
expression |
string | 否 | emoji_mapping.json 的相对路径,离线模式用 |
identity |
string | 否 | identity.json 的相对路径,展示元数据覆盖 |
voice |
string | 否 | 语音配置相对路径(社区扩展) |
ui |
string | 否 | UI 样式配置相对路径(社区扩展) |
rules |
string | 否 | 规则目录相对路径(社区扩展) |
personality 是唯一必填的 interface——没有它 Friend 无法工作。其他都是可选的社区扩展点。
dependencies(可选)
Section titled “dependencies(可选)”| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
minContainerVersion |
string | null |
要求的最低容器版本(semver 字符串) |
plugins |
string[] | [] |
依赖的其他插件 id |
services |
string[] | [] |
依赖的容器服务名,如 ["tts"] |
configSchema(可选)
Section titled “configSchema(可选)”定义用户可编辑的插件配置项。每个 key 是配置字段名,value 是字段定义:
"configSchema": { "greeting": { "type": "string", "default": "嗨,我在呢", "label": "打招呼语", "secret": false }, "language": { "type": "select", "default": "zh", "label": "语言", "options": ["zh", "en"] }}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
type |
string | 是 | "string" / "boolean" / "number" / "select" |
default |
any | 否 | 默认值 |
label |
string | 否 | 设置 UI 里显示的标签 |
secret |
boolean | 否 | 是否敏感值(API key 等),UI 会掩码显示 |
options |
string[] | 否 | type: "select" 时的可选项 |
容器的插件设置 UI 会根据 configSchema 自动生成表单。greeting 字段的 default 会被用作伙伴首次问候语。
Application 专属字段
Section titled “Application 专属字段”{ "id": "moodpet.app.elevenlabs_tts", "type": "application", "entry": "main.dart", "language": "dart", "overrides": { "services": { "tts": true }, "ui": {} }, "provides": { "triggers": ["on_reply"], "actions": ["speak"], "interfaces": ["tts"] }, "dependencies": { "minContainerVersion": "1.0.0", "plugins": [], "services": [] }, "requirements": { "webview": null, "permissions": ["internet"], "minPlatformVersion": { "android": "8.0" }, "runtime": { "dart": ">=3.0" } }, "resources": { "minRam": 128, "minDisk": 10, "maxCpuCores": null }, "configSchema": { "apiKey": { "type": "string", "label": "ElevenLabs API Key", "secret": true } }}entry + language(必填)
Section titled “entry + language(必填)”| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
entry |
string | 是 | 入口文件相对路径,如 main.dart / python/main.py |
language |
string | 是 | 实现语言:dart / python / binary |
容器按 language 选运行时:dart 走 Flutter 插件运行时,python 走 Python 子进程,binary 直接执行。entry 指向的文件必须在 ZIP 内存在,否则验证脚本报错。
overrides(可选)
Section titled “overrides(可选)”声明这个插件接管哪些容器服务 / UI 页面:
| 字段 | 类型 | 说明 |
|---|---|---|
services |
object | {服务名: bool},如 {"tts": true} 表示接管 TTS |
ui |
object | {页面名: bool},如 {"home_page": true} 表示接管首页 |
接管后,原内置服务/页面停止贡献,由这个插件替代。一个服务同时只能被一个启用的 Application 接管。
provides(可选)
Section titled “provides(可选)”声明插件暴露的能力:
| 字段 | 类型 | 说明 |
|---|---|---|
triggers |
string[] | 响应哪些事件触发,如 ["on_reply"] |
actions |
string[] | 提供哪些动作,如 ["speak"] |
interfaces |
string[] | 实现哪些接口,如 ["tts"] |
其他插件或容器通过这些声明发现和调用本插件。
requirements(可选)
Section titled “requirements(可选)”| 字段 | 类型 | 说明 |
|---|---|---|
webview |
string | 需要的 WebView 版本 |
permissions |
string[] | 需要的系统权限,如 ["internet", "microphone"] |
minPlatformVersion |
object | {平台id: 最低版本字符串} |
runtime |
object | 运行时依赖,{语言: 版本约束} |
resources(可选)
Section titled “resources(可选)”| 字段 | 类型 | 说明 |
|---|---|---|
minRam |
number | 最低内存(MB) |
minDisk |
number | 最低磁盘(MB) |
maxCpuCores |
number | 最多使用 CPU 核数 |
configSchema
Section titled “configSchema”和 Friend 的 configSchema 格式完全一样。Application 用它声明用户需要配置的字段(比如 API key)。
Pack 专属字段
Section titled “Pack 专属字段”{ "id": "moodpet.pack.anime_collection", "type": "pack", "plugins": { "friend": [ { "id": "moodpet.friend.hatsune", "path": "friend/hatsune" }, { "id": "moodpet.friend.rem", "path": "friend/rem" } ], "application": [ { "id": "moodpet.app.anime_tts", "path": "application/anime_tts" } ] }, "recommended": { "defaultFriend": "moodpet.friend.hatsune", "defaultApplication": ["moodpet.app.anime_tts"] }}plugins(可选)
Section titled “plugins(可选)”| 字段 | 类型 | 说明 |
|---|---|---|
friend |
object[] | 包含的 Friend 子插件列表 |
application |
object[] | 包含的 Application 子插件列表 |
每条目:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
string | 是 | 子插件 id |
path |
string | 是 | 子插件在 ZIP 内的目录路径 |
path 指向的目录必须在 ZIP 内存在,目录内要有自己的 manifest.json。安装时容器把每个子插件目录复制到 plugins root。
recommended(可选)
Section titled “recommended(可选)”| 字段 | 类型 | 说明 |
|---|---|---|
defaultFriend |
string | 装完后默认激活的 Friend id |
defaultApplication |
string[] | 装完后默认启用的 Application id 列表 |
Pack 的固定行为
Section titled “Pack 的固定行为”Pack 的 system 永远是 false,uninstallable 永远是 true,defaultEnabled 永远是 false——这三个字段在 PackManifest 构造函数里硬编码,manifest 里写了也会被忽略。
验证脚本会检查插件包内 manifest.json 的 id 和 type 必须和同目录 .meta.json 的 id 和 type 完全一致。不一致的话 CI 会红,PR 合不进去。
version 用语义化版本:MAJOR.MINOR.PATCH,比如 1.0.0、1.2.3。
- 破坏性变更(manifest 字段不兼容、system_prompt 完全重写)→ 升 MAJOR
- 新增功能(加 configSchema 字段、加 emoji)→ 升 MINOR
- 修复(调文案、修 bug)→ 升 PATCH
客户端的 UpdateChecker 用 semver 比较判断有没有新版本——1.2.0 > 1.1.0 会提示更新。非数字段会退化成字符串比较,所以别用 1.0.0-beta 这种带后缀的格式(-beta 会被剥掉再比,可能误判)。