清单
manifest.json 是插件的唯一事实来源。宿主在安装时解析它,以获知插件的身份、如何启动其 worker、挂载什么 UI、允许它做什么,以及它暴露哪些 AI 工具。它位于 .fyp 归档的根目录。
Schema 参考
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
schemaVersion | number | 是 | — | 清单 schema 版本。当前为 2。 |
id | string | 是 | — | 反向 DNS 的插件 id,例如 fan.summer.excel。在已安装插件中必须唯一。 |
name | string | 是 | — | 人类可读的显示名。 |
description | string | 是 | — | 在市场与插件列表中展示的一行描述。 |
version | string | 是 | — | SemVer 风格的版本字符串,例如 4.0.0。 |
author | string | 是 | — | 作者或组织名。 |
icon | string | 是 | — | 图标标识符(一个 Vuetify/Material 设计图标名,例如 file-excel)。 |
category | string | 是 | — | 合法 category 取值之一。 |
ui | object | 是 | — | UI 子记录。见 ui。 |
backend | object | 否 | — | Worker 子记录。见 backend。可选——纯 UI 插件可省略它。 |
engines | object | 否 | — | 宿主兼容性。engines.fengyu 使用如 >=4.0.0-beta.4 <5.0.0 的 SemVer 范围;不兼容包在解压前被拒绝。 |
rpc | object | 否 | — | RPC 方法表。见 rpc.methods。声明每个方法的 inputSchema/outputSchema(JSON-Schema 对象)。 |
permissions | string[] | 否 | [] | 声明的权限。驱动文件 I/O 授权。 |
homepage | string | 否 | — | 指向插件主页或源码仓库的 URL。 |
official | boolean | 否 | false | 由 OfficialPluginSeeder 预置的插件设为 true;将描述符的 source 设为 OFFICIAL。 |
aiTools | object[] | 否 | [] | 声明的 AI 工具。空数组表示 supportsAi = false。 |
i18n | object | 否 | — | manifest 与 AI 工具显示文案的 locale 覆盖。 |
flowNodes | object[] | 否 | [] | 一等流程画布节点描述符。 |
ui
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
entry | string | 是 | 相对于归档根的入口 HTML 路径,通常为 ui/index.html。通过 /plugin-runtime/{id}/<entry> 提供。 |
backend
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
runtime | string | 否 | java(默认)、python 或 go。可执行文件及制品约定由宿主持有,绝不接受任意命令。 |
protocolVersion | integer | 否 | 新插件设为 1,启用保留的启动握手;仅遗留 Java 包可省略。 |
callTimeoutSeconds | integer | 否 | 插件级的默认每次调用超时(秒)。会被钳制到 [1, 600]。省略时宿主使用 60。aiTools[].timeoutSeconds 会针对单个工具覆盖此值。 |
resources.memoryMb | integer | 否 | Worker 进程树常驻内存上限,64–8192 MiB;Linux/macOS 由宿主监控,Windows 由 Job Object 内核限制强制。 |
resources.maxProcesses | integer | 否 | Worker 进程树总进程数上限(含 worker),1–64。 |
约定制品分别是 Java 的 backend/worker.jar、Python 的 backend/worker.py、Go 的 backend/worker(Windows 为 worker.exe)。三种 runtime 都通过 stdio 上换行分隔的 JSON-RPC 2.0 通信,不再在清单中声明启动命令。设置 protocolVersion: 1 后,宿主先调用保留的 $/fengyu/initialize,校验返回的协议与 runtime,再把插件标为健康。
rpc.methods
插件暴露的 JSON-RPC 方法表,以方法名为键。每个方法自带其参数与输出的 JSON Schema——是真正的 JSON-Schema 对象,而非转义字符串。Java Worker SDK 与 TypeScript UI 客户端均从该表生成类型化绑定。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
description | string | 否 | 方法的简短描述。 |
inputSchema | object | 是 | 描述方法参数的 JSON Schema 对象。 |
outputSchema | object | 否 | 描述 Worker 结果信封的 JSON Schema 对象。 |
aiTools[].method 必须在此表中存在;fengyu CLI 在 check/build 时会校验二者一致。
aiTools[]
每一项声明一个 AI 可调用的工具,宿主会把它们聚合成其 Spring AI 的 ToolCallback[]。参数与输出 Schema 不再内联——它们声明在 rpc.methods 中;aiTools[] 只携带工具的面向模型的元数据与副作用分类。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 是 | 暴露给模型的工具名。 |
description | string | 是 | 给模型的自然语言描述。 |
method | string | 是 | 当模型调用此工具时要调用的 worker JSON-RPC 方法(必须在 rpc.methods 中存在)。 |
effect | string | 是 | 审批分类:read、write 或 external。 |
idempotent | boolean | 否 | 仅当重复完全相同的写入/外部调用不会产生重复副作用时设为 true,从而允许工作流重试;只读工具自动可安全重试。默认 false。 |
timeoutSeconds | integer | 否 | 针对此工具的调用超时(秒),钳制到 [1, 600]。覆盖 backend.callTimeoutSeconds。默认 60。可能超过其声明超时的工具必须拆分为 *_start / *_status / *_cancel 的 job 方法——参见 Worker → 长任务(job 模式)。 |
端到端流程见 AI 工具。
flowNodes[]
面向 Flows 流程构建器的显式画布节点声明。带 flowNodes 声明的工具在画布上呈现为 一等节点——类型化端口、示例值、帮助文案、自定义控件;未声明的工具仍会出现在调色板 「显示全部工具」开关之后,作为按 Schema 推导的降级节点。
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
tool | string | 是 | 该节点渲染并执行的 aiTools[].name。 |
label | string | 否 | 卡片标签(缺省为工具名的人性化形式)。 |
kind | string | 否 | action(默认)/ control / start —— 画布结构节点的保留字。 |
help | string | 否 | 节点级帮助,展示在检查器的帮助区。 |
docsUrl | string | 否 | 外部文档链接。 |
color | string | 否 | 卡片十六进制颜色。 |
icon | string | 否 | 徽章的 MDI 图标名。 |
inputs[] | array | 否 | 声明的输入,见下。 |
outputs[] | array | 否 | 命名输出端口,见下。 |
可执行输入契约由所引用 RPC 的 inputSchema 唯一拥有:每个 Schema 属性都会出现在检查器中, 无需重复填写类型、必填或默认值。可选的输入 UI 增量以 name 开头,可增加 widget (text / number / switch / select / textarea / json / analyze / rows)、 title、description、help、placeholder、examples[]、 advanced(折叠进高级设置)、options[](select 用——纯字符串或 {value, label} 对以支持本地化标签)、source(从插件列表 RPC 加载选项)、context (分析式编辑期数据集)与 fields[](rows 控件的每行字段)。没有增量时,UI 会从 Schema 推断普通控件。fengyu check 会把每个增量名称及控件与 RPC Schema 交叉校验,并拒绝增量 中的 type、required、default;这些可执行字段只能存在于 RPC JSON Schema 中。
每个输出 UI 增量携带 name,并可增加 title、description / help、examples[]。 对象或数组输出还可递归增加只负责显示的 properties / items,用于标注 confirmation.confirmationId、files[0] 等路径;字段是否存在及其类型仍来自 outputSchema。
locale 条目还可包含按工具名索引的紧凑 flowNodes 对象;其中 inputs/outputs 再按规范 端口名索引,只覆盖标题、帮助、选项、示例、嵌套 fields 和输出 properties 等显示字段, 不会重复或改变 RPC 类型。fengyu check 与宿主安装都会拒绝不存在的工具、端口或属性键。
完整词表定义在 toolchain/spec/manifest.schema.json (flowNode、flowNodeInput、flowNodeOutput、flowOutputProperty 定义);宿主的 flow-nodes/builtin.json 以 flow-node.schema.json 校验。
合法 category 取值
category 是一个自由格式的提示性字符串,UI 用它来对插件分组——宿主不会校验它是否属于某个固定集合(它只会把你写的值转为大写,为空时默认为 OTHER)。为保持一致,请使用以下约定取值之一:
| 取值 | 用途 |
|---|---|
dev | 开发者工具 |
text | 文本编辑/渲染(例如 fan.summer.markdown) |
image | 图像处理 |
net | 网络相关 |
network | 网络相关(例如 fan.summer.email) |
file | 文件处理(例如 fan.summer.excel) |
ai | 以 AI 为中心的插件 |
other | 上述未涵盖的任何类型(脚手架的默认值) |
合法权限
permissions 是一个数组,包含零个或多个以下规范集合中的值,由 CLI 与宿主共同强制执行:
| 取值 | 授权 |
|---|---|
files.read | POST /api/plugin-runtime/{id}/files/upload、upload-directory、native(读访问) |
files.write | POST .../files/native(写访问)、POST .../files/output、GET .../files/export/{ref} |
network | 来自 worker 的通用出站网络访问。 |
network.email | worker 可以建立 SMTP/IMAP 连接(fan.summer.email 使用)。 |
clipboard.read | 读取宿主剪贴板。 |
clipboard.write | 写入宿主剪贴板。 |
notifications | 声明性:插件可发出通知。notify 桥不再读取该 token——所有插件的 notify 一律走统一宿主管线(保留接受以兼容既有 manifest)。 |
database | 宿主向 worker 环境注入数据库连接坐标(FENGYU_DB_* —— type/driver/url/username/password —— 以及一个私有数据目录),以隔离 DB 用户/schema 形式 provision;由 worker 自行建立连接。参见插件数据库规范。 |
screen.capture | 桌面插件 UI 可以调用 getDisplayMedia。只有声明该权限时,宿主才会给 iframe 授予 display-capture;Electron 的独立处理器只暴露整屏源,不暴露摄像头、麦克风或单个窗口。macOS 另外要求宿主应用拥有系统“屏幕录制”权限。 |
fengyu dev 模拟器应用同一 manifest 闸门,因此插件可以在打包前验证屏幕捕获链路。
任何其他取值在 validate 与 install 时都会被当作未知权限拒绝。在缺少对应权限的情况下尝试文件操作会被以 403 拒绝。参见 文件 I/O。
强制力度并不一致(P1-9)。 不要假设每个被接受的权限都被同等强制执行:
- 由宿主/OS 沙箱强制:
files.read、files.write(FileRef 授权闸门)、network(OS 网络命名空间)、screen.capture(桌面 iframe Permissions Policy + 仅屏幕的 Electron display-media 处理器)。- 在网络层按全量出站放行(advisory):
network.email、database目前授予宽泛的出站网络——宿主尚未代理 SMTP/IMAP,也未限制 DB 只连特定主机。真正的邮件/DB 代理是一项已立项的后续工作。- 声明性(不强制):
notifications。所有插件的notify调用一律走统一宿主管线 (应用内 toast + 原生桌面通知 + 持久化通知中心)——此前的门控会把未声明权限的插件 路由到 iframe 内部兜底,而其 snackbar 用户实际看不到。token 仍被接受以兼容既有 manifest,仅作为意图声明。- 仅声明(尚无宿主强制):
clipboard.read、clipboard.write只是为未来到桌面外壳的 capability 桥接声明意图,运行时当前不读取。在任何汇总插件权限的 UI 中都要如实呈现——不要对
network.email/database暗示比 OS 实际强制更细的网络隔离。
示例
Markdown 插件
fan.summer.markdown 的清单——一个无权限、无 AI 工具的文本插件:
{
"schemaVersion": 2,
"id": "fan.summer.markdown",
"name": "Markdown Editor",
"description": "Split-pane Markdown editor with isolated server-side rendering",
"version": "4.0.0",
"author": "FengYu",
"icon": "language-markdown",
"category": "text",
"ui": { "entry": "ui/index.html" },
"backend": { "callTimeoutSeconds": 30 },
"permissions": [],
"homepage": "https://github.com/MuskStark/FengYu",
"official": true,
"rpc": {
"methods": {
"render": {
"description": "Render Markdown source to sanitized HTML via commonmark.",
"inputSchema": {
"type": "object",
"properties": {
"markdown": { "type": "string", "description": "The Markdown source to render." }
},
"required": ["markdown"]
},
"outputSchema": {
"type": "object",
"properties": {
"success": { "type": "boolean", "description": "true when the render completed." },
"summary": { "type": "string", "description": "Short localized result summary." },
"html": { "type": "string", "nullable": true, "description": "The rendered, sanitized HTML." }
},
"required": ["success", "summary"]
}
}
}
}
}Excel 插件(含 aiTools)
fan.summer.excel 的清单——一个带读写权限和 AI 工具的文件插件。这里完整展示两个方法:excel_analyze(短时同步调用),以及 excel_execute_start(长时拆分 job 模式对的启动半边)。参数与输出 Schema 是 rpc.methods 里的 JSON-Schema 对象;aiTools[] 只引用方法名并声明副作用:
{
"schemaVersion": 2,
"id": "fan.summer.excel",
"name": "Excel Splitter",
"description": "Split Excel workbooks by sheet, column value, or complex rules",
"version": "4.0.0",
"author": "FengYu",
"icon": "file-excel",
"category": "file",
"ui": { "entry": "ui/index.html" },
"backend": { "callTimeoutSeconds": 60 },
"permissions": ["files.read", "files.write"],
"homepage": "https://github.com/MuskStark/FengYu",
"official": true,
"rpc": {
"methods": {
"excel_analyze": {
"description": "Analyze the granted Excel workbook; returns sheet names.",
"inputSchema": {
"type": "object",
"properties": {
"filePath": { "type": "string", "description": "Resolved absolute path of a readable FengYu FileRef." }
},
"required": ["filePath"]
},
"outputSchema": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"summary": { "type": "string" },
"sheets": { "type": "array", "items": { "type": "string" } }
},
"required": ["success", "summary"]
}
},
"excel_execute_start": {
"description": "Launch the configured split as a background job and return a jobId immediately. Poll excel_execute_status with a cursor to drain progress logs.",
"inputSchema": {
"type": "object",
"properties": {
"outputDir": { "type": "string", "description": "Resolved absolute path of a writable FengYu DirectoryRef." },
"filePrefix": { "type": "string" }
},
"required": ["outputDir"]
},
"outputSchema": {
"type": "object",
"properties": {
"success": { "type": "boolean" },
"summary": { "type": "string" },
"jobId": { "type": "string" }
},
"required": ["success", "summary"]
}
}
}
},
"aiTools": [
{ "name": "excel_analyze", "method": "excel_analyze", "effect": "read", "description": "Analyze the granted Excel workbook; returns sheet names.", "timeoutSeconds": 30 },
{ "name": "excel_execute_start", "method": "excel_execute_start", "effect": "write", "description": "Launch the configured split as a background job and return its job ID.", "timeoutSeconds": 30 }
]
}
inputSchema/outputSchema是真正的 JSON-Schema 对象(不再是转义字符串)。aiTools[]只携带name/method/effect/idempotent/description/timeoutSeconds——参数与输出 Schema 统一声明在rpc.methods中,宿主据此构建 Spring AI 的ToolDefinition。
代码优先清单(manifest.base.json)
插件可以从 Java、Python 或 Go 源码声明 RPC 契约,而不必手写 rpc.methods/aiTools JSON。 新建的 Worker 脚手架默认采用代码优先,并用以下文件替代 manifest.json:
manifest.base.json 身份、ui、backend、权限…(不允许 rpc/aiTools/flowNodes/i18n)
manifest/flow-nodes.json Flow overlay(只允许 flowNodes)
manifest/i18n/<locale>.json
worker/... 契约源码 Java 注解、Python dataclass 或 Go structJava 由 DevKit 注解处理器(fengyu-plugin-devkit,以 proc:only 绑定到 generate-resources)提取;Python 以 dataclass + Annotated[..., Field(...)] 配合 Contract.rpc(...) 声明;Go 以带标签的 struct 配合 NewContract(...).RPC(...) 声明。 各语言的小型生成器写出相同 IR。CLI 将 base + IR + overlay + i18n 合并为 .fyp 内唯一一份完整的根 manifest.json(安装契约不变)。 两种编写模式不得共存——fengyu check/build 在 manifest.json 与 manifest.base.json 同时存在时直接失败。同一份源码连续编译产生字节级一致的结果。
主要注解:@FengYuContract(接口)、@FengYuRpc(方法名、描述、超时)、 @FengYuAiTool(AI 暴露 + effect)、@FengYuField(描述/必填/可空/默认值/主机文件 format+fileAccess 等)、@FengYuSensitive(禁止记录与透传)。不支持裸 Map、未界定泛型、 递归或多态 DTO——直接编译失败,绝不静默退化为无约束 object。三种运行时都用 fengyu generate 完成各自的提取、合并与类型化客户端/方法常量再生成。
引用上游节点的实际输入
Flow 步骤直接暴露模板解析后的实际调用参数,无需声明合成输出。下游参数可这样引用:
{ "attachmentDirectory": "{{steps.0.input.outputDirectory}}" }画布表单生成等价的编写期语法 {{node.<id>.input.outputDirectory}},保存时编译为步骤索引形式。 .input 与 .result 都支持点分路径和 [N] 数组下标。敏感参数名及 Schema 标记字段会从 实际输入快照中过滤,无法解析;缺失路径会明确报错,不会静默变成空字符串。
下一步
- Worker(JSON-RPC)——实现
rpc.methods所声明方法的进程外后端。 - AI 工具——声明并暴露
aiTools。 - 文件 I/O——每条
permissions条目解锁的能力。