跳转到内容

plugin.json 完整参考

manifest 的类型单源是 @xinghan/plugin-sdk 的 PluginManifest(packages/plugin-sdk/src/types/manifest.ts)。本页与之对照维护;冲突时以类型定义为准。

字段类型必填说明
idstring✓reverse-DNS 形态全局唯一,如 xinghan.pomodoro;本地开发用 dev. 前缀
namestring✓显示名
versionstring✓版本号
descriptionstring一句话说明(市场卡片、插件列表用)。与 market 同为市场消费的扩展字段 —— PluginManifest 类型未声明它们,loader 原样透传
runtime'node' | 'static'✓运行时(见插件解剖)
entrystringnode 必填后端启动入口(相对插件根),如 dist/server.js
devEntrystringdev 模式后端入口(如 TS 源码,tsx 直跑);缺省用 entry
uistringstatic 必填静态 UI 根目录(相对插件根),如 ui
capabilitiesCapabilityName[]✓能力白名单(可为空数组,但必须是数组)
contributesobject贡献声明(下详)
marketobject市场元数据:category / tags / featured

'dataEngine' · 'llm' · 'storage' · 'events' · 'secrets' · `satellite:${kind}`

satellite:<kind> 是卫星项目作用域:声明后才能经 capability 访问目标为 <parent>#<kind> 的卫星项目(如 Agent 会话库要 satellite:agent)。未声明访问任何卫星一律 403。

一块 iframe UI 及其挂载位置。

字段类型说明
idstring插件内唯一 view id
titlestring显示名
iconstringlucide 图标名(可选)
locationViewLocationright-drawer / activity-bar / settings / fullscreen / floating / bottom-panel
entrystringiframe 入口(相对插件根,支持 hash 路由)
devUiUrlstringdev 模式 iframe 直连地址(如 vite dev server),宿主反代到它

activity-bar:左侧活动栏图标 → 占满编辑区的全屏页,URL 深链 /projects/:id/page/<pluginId>/<viewId>。settings:嵌进宿主偏好设置页 —— 复杂配置 UI 用它,简单 key/value 用 contributes.settings 自动表单。

"views": [
{ "id": "panel", "title": "工具", "icon": "clock",
"location": "right-drawer", "entry": "ui/index.html",
"devUiUrl": "http://localhost:3001" }
]

新工作台布局(左侧导航 + 分栏)里,「功能」段的每一行都是可展开的(仿 VS Code 侧栏 section):一行标题 + 折叠箭头,展开后是一份列表或插件自己的视图。经典布局忽略这个字段,仍按 activity-bar 图标渲染。

字段类型说明
idstring插件内唯一
titlestring显示名(支持多语言 map)
iconstringlucide 图标名(可选,缺省用 open 指向视图的图标)
renderlist / view展开后怎么渲染:list = 宿主通用列表;view = 插件自己的 iframe
itemsstringrender:list:插件后端端点(相对插件根)。宿主 GET <端点>?projectId=<pid>&limit=&cursor=&q=,期望 { ok, data:{ items, nextCursor?, total? } }。limit 一页条数;cursor 是上一页回的 nextCursor(不透明字符串,插件自定义,比如 offset),回包没有 nextCursor 就是到底了;不认这两个参数的端点照旧一次回全部。total 可选,段头显示总数用
entrystringrender:view:iframe 入口(相对插件根,支持 hash 路由)
openstring标题行右侧「打开页面」去的本插件 view id。activity-bar 视图 → 全页;right-drawer 视图 → 工作台的一格
searchablebooleanrender:list:列表支持服务端搜索。宿主在段头给搜索框,把 q 交给 items 端点由插件在库里搜(分页照常);不声明的话宿主只在已加载的条目里本地过滤 title / subtitle

声明了 open 的 section 会顶替那个视图原本在导航里的一行(图标行变成可展开行);没被认领的 activity-bar 视图仍是一行普通入口,老插件零改造。

items 端点返回的每一项:

字段类型说明
id / titlestring必填
subtitlestring行尾灰字(时间、编号…)
iconstringlucide 图标名
badgestring / number行尾强调(如运行中 ●)
groupstring / 多语言 map分组小标题(如「今天 / 昨天 / 本周 / 更早」)。分组语义由插件决定,宿主只在相邻两项 group 变化处画一行小标题;没有 group 的项不画
actionobject点一项做什么,宿主执行:{ kind:'view', view, arg? } 打开本插件的视图并把 arg 交给它(iframe 收 context.openArg;agent 原生壳按 arg.sessionId 切会话);{ kind:'file', nodeId } 打开项目里的文件;{ kind:'route', to } 宿主前端路由;{ kind:'url', url } 外链新窗口

列表变了要宿主重拉时,插件 iframe 向父窗口 postMessage({ type: 'explorer/refresh' });不发的话只在展开、切项目时拉一次。

"explorerSections": [
{ "id": "sessions", "title": { "zh-CN": "会话", "en-US": "Sessions" },
"icon": "bot", "render": "list", "items": "api/nav/sessions",
"searchable": true, "open": "workbench" }
]
字段类型说明
idstring命令 id(命令消息回传用)
titlestring显示名
keystring快捷键,mac 记法(cmd+l),其它平台宿主自动 normalize 成 ctrl
"commands": [
{ "id": "newConversation", "title": "新建对话", "key": "cmd+l" }
]

简单配置项 —— 宿主偏好页按插件分组自动渲染表单,插件用 cap.storage.get('settings:<key>') 读值。

字段类型说明
keystring存储 key(自动加 settings: 前缀)
labelstring表单 label
type'string' | 'secret' | 'boolean' | 'enum' | 'number'控件类型(secret=密码框)
descriptionstringlabel 下方帮助文字
optionsstring[]enum 必填
min / max / stepnumbernumber 可选
default值UI 显示的默认值(不写入存储,插件代码自己 ?? 兜底)
placeholderstringstring/number 占位符
"settings": [
{ "key": "apiUrl", "label": "服务地址", "type": "string",
"placeholder": "https://api.example.com" },
{ "key": "apiKey", "label": "API Key", "type": "secret" },
{ "key": "mode", "label": "模式", "type": "enum",
"options": ["fast", "accurate"], "default": "fast" }
]

插件读值:await cap.storage.get<string>('settings:apiUrl', { actor })。

右键菜单项(详见右键菜单与命令)。

字段类型说明
idstring点击后随命令消息回传
titleLocalizedText单串或 { 'zh-CN': …, 'en-US': … },可含 {count}
pointsContextMenuPoint[]table.rows / table.cells / table.columnHeader / fileTree.table / fileTree.node
modal{ view, width?, height? }以模态框打开某 view(默认是打开右抽屉)
"contextMenus": [
{ "id": "translate",
"title": { "zh-CN": "翻译选中 {count} 格", "en-US": "Translate {count} cells" },
"points": ["table.cells"] }
]

自定义字段类型。核心契约:字段骑在基础类型上存储(baseType: text/number/date/richtext 决定引擎里的真实 type 码),排序/筛选/移动端/未装插件的协同端全按基础类型工作,插件只负责渲染与编辑。字段身份与配置存在 field.properties.xPluginField。

字段类型说明
typeKeystring插件内唯一;全局身份 = ${pluginId}:${typeKey}
nameLocalizedText类型名
iconstringlucide 图标(缺省用基础类型图标)
baseTypePluginFieldBaseType基础存储类型
editor{ view, size?, placement? }双击 cell 的编辑弹窗;placement: anchor(锚到 cell)/ center(默认)。插件 ui.resolveModal({ value }) 回传新值,宿主走 op 系统写入
fieldConfig{ view, height?, maxBytes? }建/改字段时的配置面板;config 进 field.properties 随协同与历史传播,maxBytes 是它的护栏
drawerBlock{ view, height? }记录详情抽屉里的字段块;缺省=摘要文本+编辑按钮
summaryPathstring从 cell JSON 取摘要文本的 path(如 $.summary)—— 网格/导出/未装插件端显示用
columnMenus / cellMenusPluginFieldMenuItem[]仅该类型字段出现的菜单(cellMenus 支持 requiresValue;modal context 带 cellValue)
defaultValueunknown新 cell 默认值(缺省 null)
validation.maxBytesnumber单值写入护栏,缺省 256KB
hideBaseTypeInPickerbooleantrue=本类型是基础类型的升级替代,新建字段选择器里隐藏对应基础类型;卸载后自动回归

最小可用声明(内置 JSON 字段的真实形态):

"fieldTypes": [
{ "typeKey": "jsonDoc",
"name": { "zh-CN": "JSON", "en-US": "JSON" },
"icon": "braces",
"baseType": "text",
"editor": { "view": "editor",
"size": { "width": 760, "height": 560 },
"placement": "center" },
"validation": { "maxBytes": 1048576 } }
]

完整闭环见自定义字段类型。

自定义文件类型:出现在「新建」菜单,编辑区由插件 iframe 渲染。认领语义:fileType 与内建同名(如 markdown)= 升级替代 —— 新建入口替换内建、已有节点渲染也接管;卸载后自动回归内建编辑器,节点零迁移。

字段类型说明
fileTypestring内建同名=认领;新类型用独立名
nameLocalizedText类型名
iconstring宿主图标表名(缺省通用文件图标)
colorstring | number宿主色板槽名(table/doc/json/automation/ai/dashboard/image)或色相角 0-360(宿主按主题算亮度彩度)。不接受裸 hex —— 写死的颜色在暗色主题必然失衡
suffixstring显示后缀(纯展示)
storage'text'底层存储形态(节点内容=文本,经 doc.load/save 读写)
entrystring编辑区渲染入口(iframe)
"fileTypes": [
{ "fileType": "mindmap",
"name": { "zh-CN": "思维导图", "en-US": "Mind map" },
"icon": "braces", "color": "doc", "suffix": "mm",
"storage": "text", "entry": "ui/index.html#/doc" }
]

只接管某 fileType 的渲染(不进新建菜单):{ fileType, entry, label? }。宿主命中该类型时挂插件 iframe 并经 context 桥推入节点 id。

同一张表的另一种投影(日历/画廊/地图/甘特…)。视图实体的 type 存 ${pluginId}:${viewKey};「+新建视图」菜单在内建类型后列出;激活时表编辑区渲染插件 iframe,context 带 { tableNodeId, viewId };视图配置存视图的 styleInfo。未装插件时该视图 tab 显示占位,数据不丢。

字段类型说明
viewKeystring插件内唯一
nameLocalizedText视图名
iconstring单 emoji
entrystring渲染入口
writesobject写入能力声明(缺省只读):cells(改本表已有格)/ addRecords / deleteRecords(单独一档,不可逆)/ maxBytes(缺省 256KB)。宿主按档放行且锁定本视图挂载的表
"tableViews": [
{ "viewKey": "calendar",
"name": { "zh-CN": "日历", "en-US": "Calendar" },
"icon": "📅", "entry": "ui/index.html#/calendar",
"writes": { "cells": true } }
]

自定义自动化节点:声明式配置面板(宿主内建控件渲染,不是 iframe —— 因为 valueSelector 要接宿主的上游变量域)+ 后端执行。身份 = ${pluginId}:${typeKey} 即 node.Type 存储值。

字段类型说明
typeKeystring插件内唯一
claimstring认领内建节点名(v1 仅 llm):在场时接管入口/面板/执行,node.Type 照存内建名,存量零迁移;不在场回退内建
versionnumber配置结构版本(插件自己向后兼容,宿主不做迁移)
name / descriptionLocalizedTextdescription 兼作 AI 工具描述,按写给模型看的质量要求
iconstringlucide svg path 或单 emoji
categorystring归入宿主分类;缺省 plugin 分组
configSchemaNodeConfigField[]配置面板字段(下详)
outputSchemaOutputVarDecl[]输出变量静态声明(下游 valueSelector 编辑期消费)
executionobjecttimeoutMs(缺省 120s,上限 30min)/ maxConcurrency(缺省 4,超出排队)/ idempotent(缺省 false=至多一次,防收费副作用重复)/ supportsDryRun / sideEffects(none/table/external)

NodeConfigField.widget 取值:text / textarea / number / switch / select / valueSelector(可插上游变量)/ tableSelector / fieldSelector(dependsOn 指向同面板 tableSelector)/ optionSelector / optionWeightMap / keyValueList / dynamicSelect(选项来自插件后端 GET /automation/<typeKey>/options)。

前向兼容承诺:宿主碰到不认识的 widget 名,把该字段降级成 text 输入并告警,绝不丢弃整个节点声明 —— 插件可放心用新 widget,无需探测宿主版本。

最小可用声明(一个”翻译文本”节点):

"automationNodes": [
{ "typeKey": "translate", "version": 1,
"name": { "zh-CN": "翻译文本", "en-US": "Translate" },
"description": { "zh-CN": "把输入文本翻译成目标语言" },
"category": "integration",
"configSchema": [
{ "key": "text", "label": { "zh-CN": "文本" }, "widget": "valueSelector",
"required": true },
{ "key": "target", "label": { "zh-CN": "目标语言" }, "widget": "select",
"options": [
{ "value": "en", "label": { "zh-CN": "英语" } },
{ "value": "ja", "label": { "zh-CN": "日语" } }
], "default": "en" }
],
"outputSchema": [
{ "key": "translated", "type": "string", "label": { "zh-CN": "译文" } }
],
"execution": { "timeoutMs": 30000, "sideEffects": "external" } }
]

执行侧在插件后端用 defineAutomationNode() 注册(@xinghan/plugin-sdk/server 导出),宿主把节点任务经 POST /automation/<typeKey> 投给你的进程。

contributes.contributionPoints / contributions

Section titled “contributes.contributionPoints / contributions”

插件间扩展面的声明式形态(与运行时 contributions capability 等价,host 加载时代为注入,下线整体退场):

  • contributionPoints[]:开放一个点。point 必须以本插件 id 为前缀(<pluginId>/<name>,所有权即命名空间);schema 做顶层必填字段浅校验。
  • contributions[]:向某个点投稿纯数据(point 可以是其它插件的点,点未声明时挂 pending);data ≤64KB,语义由点的 owner 定义。

static 插件(无进程)只有这条声明式的路;node 插件两条路并存,纯数据投稿优先写 manifest(可被市场/审核静态检视)。