Skip to content

官方插件——Markdown

fan.summer.markdown 是两个随产品发布的官方插件中较简单的一个。它是一个分栏的 Markdown 编辑器,唯一的后端能力是通过 commonmark 做服务端渲染为 HTML。它不声明任何权限,也不声明任何 AI 工具——插件契约的一个最小化、权威示例。

它做什么

  • 渲染一个 Vuetify 分栏编辑器:左侧是 Markdown 源码,右侧是实时 HTML 预览。
  • 每次编辑时,UI 调用 worker 的 render 方法,该方法用 commonmark 在服务端解析 Markdown 并返回 HTML。
  • 渲染在进程外的 worker 中发生——宿主自己永远不会解析 Markdown。

清单

json
{
  "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" },
            "summary": { "type": "string" },
            "html": { "type": "string", "nullable": true }
          },
          "required": ["success", "summary"]
        }
      }
    }
  }
}

要点:

  • category: "text"——一个文本编辑/渲染插件。
  • permissions: []——它永远不触碰文件系统;没有任何文件 I/O 授权。
  • 没有 aiTools——supportsAifalse;它是一个纯 UI 工具,无法从聊天中调用。
  • backend: { "callTimeoutSeconds": 30 }——线协议固定为 stdio 上的 JSON-RPC 2.0,宿主按约定启动 java -jar backend/worker.jar;清单不再声明启动命令或协议。

每个字段见 清单

render 动作

MarkdownWorkerMain 注册了单个 JSON-RPC 方法:render。它通过类型化 method(...) API 注册——SDK 把入参反序列化为 RenderInput,绑定一个 RpcContext,再把 RenderOutput 序列化回响应:

java
return new JsonRpcWorker().method(
        PluginMethods.RENDER, RenderInput.class, RenderOutput.class,
        (RenderInput input, RpcContext ctx) -> handlers.render(input, ctx));

UI 通过由 rpc.methods 生成的类型化客户端在每次按键时调用它(做了防抖):

js
import { createPluginRpc } from './generated/fengyu-rpc'
const rpc = createPluginRpc(fengyu)
const { html } = await rpc.render({ markdown: source })
方法参数返回
render{ markdown: string }{ success: true, html: string }——commonmark 渲染出的 HTML

由于没有文件 I/O,也没有 AI 表面,这就是整个后端契约:一个方法进,一个 HTML 字符串出。协议见 Worker(JSON-RPC)

UI

UI 是一个 Vuetify 分栏 MF:

  • 左栏——一个 Markdown 源码编辑器(<v-textarea> 或等价物)。
  • 右栏——实时 HTML 预览,每次 render 结果都会重绘。
  • 使用 iframe 内部的 @infinia/plugin-ui Vuetify 实例(MD3)构建,并通过 SDK 环境桥梁跟随宿主的主题与语言变化。

它加载在 /plugin-runtime/fan.summer.markdown/** 下的沙箱化 iframe 中,并通过 @infinia/plugin-sdk 与宿主桥接。参见 UI 微前端

下一步

Released under the GPL-3.0 License.