create-plugin
当用户想创建或改造 OneWorks plugin,实现界面入口、按钮、tab、launcher 搜索、server 命令、scoped API 或本地服务时,先理解目标效果;需求不明确时列出不确定点让用户确认,再转成 manifest、前端入口、server 入口和验证步骤。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
当用户想创建或改造 OneWorks plugin,实现界面入口、按钮、tab、launcher 搜索、server 命令、scoped API 或本地服务时,先理解目标效果;需求不明确时列出不确定点让用户确认,再转成 manifest、前端入口、server 入口和验证步骤。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
Configure OneWorks model services using built-in provider defaults, management portals, API base URLs, model lists, balance/status capabilities, and safe config-source writeback.
Control the current OneWorks session's internal browser tabs with semantic snapshots, reliable element refs, screenshots, waits, and page-safe concurrent workflows.
Drive native macOS apps through the Cua Driver tools. Use when a task asks to open, inspect, click, type, scroll, capture a final screenshot, or verify a real macOS app without stealing the user's focus.
Control a user-paired external browser through a Chrome extension, explicit typed targets, and semantic operations.
Apply, review, and continuously evolve the OneWorks team's durable UI design standards. Use for any OneWorks task that changes or reviews layout, styling, theme, spacing, responsive behavior, component appearance, visual assets, or reference-image fidelity, and whenever user visual feedback may express a reusable team standard. Require a Visual Brief, conflict-aware project memory capture, a completed independent visual consistency session with real expected-behavior validation, and experience persistence before delivery; do not promote one-off pixel nudges into lasting rules.
快速说明 One Works CLI 的常用命令、配置命令、会话查看和基础技能选择方式。
| name | create-plugin |
| description | 当用户想创建或改造 OneWorks plugin,实现界面入口、按钮、tab、launcher 搜索、server 命令、scoped API 或本地服务时,先理解目标效果;需求不明确时列出不确定点让用户确认,再转成 manifest、前端入口、server 入口和验证步骤。 |
在用户描述“想创建一个插件”“想在界面里加一个入口 / 按钮 / tab / 搜索 / 调试面板 / 本地服务能力”,或明确要求“用 plugin 实现某个 UI 效果”时使用这个 skill。
先理解用户真正想要的交互效果、入口位置和 runtime 能力,再把自然语言效果转换为一个可运行、可调试、可维护的 OneWorks plugin。优先落到 plugin manifest、前端 activatePlugin(ctx)、server activatePlugin(ctx) 和 scoped runtime 通道;不要把 plugin 需求改成宿主硬编码,除非现有 plugin 扩展点明显不足。
这是 OneWorks 内置的 create-plugin skill,只面向本仓库的 OneWorks plugin。不要套用 Codex 系统 $plugin-creator 的 .codex-plugin/plugin.json、.agents/plugins/marketplace.json、~/.codex/skills 或 marketplace 规则,也不要修改全局 Codex skill。
开始写或改 plugin 前,先读取当前仓库里的插件规则和示例:
.oo/docs/usage/plugins.md.oo/docs/usage/plugins/ui-runtime.md.oo/docs/usage/plugins/server-runtime.mdpackages/plugins/demo/package.jsonpackages/plugins/demo/plugin.jsonpackages/plugins/demo/README.mdpackages/plugins/demo/README.zh-Hans.md如果用户是在改已有 plugin,先读目标 plugin 自己的 plugin.json、README 多语言文件、client/ 和 server/ 入口,再决定最小修改点。
先把用户诉求拆成这些问题;用户已经给出时不要重复问:
+ 菜单、右侧/下方 workbench tab、launcher 搜索、独立 plugin route。workspace;设备级、launcher 级或跨 workspace 协调才使用 manager。一台设备可以同时有多个 workspace server,不要假设只有一个 workspace endpoint。packages/plugins/<name> 并通过 .oo.config.json 显式声明;临时开发目录才放在 .oo/plugins.dev/<name>,开启 watch。本地路径 plugin 的 client source 会通过宿主 Vite dev server 加载,不需要单独启动插件 Vite dev server。如果缺失信息会改变入口、交互、数据来源、权限、本地服务、scope 或验证方式,先列出“不确定点”让用户确认。每个不确定点都要写清它会影响什么;可以给出推荐默认值,但不要在关键需求模糊时直接替用户拍板。只有名称、图标、文案这类低风险细节缺失时,才采用保守默认并在结果里说明。
按效果选择 manifest 字段:
plugin.contributions.navItems。默认路径是 /plugins/<scope>/<id>;也可以给 route 或 command。navMoreMenu,支持 command、route、href。navFooterBefore,支持 command、route、href。chatHeaderActions,用 command 触发 plugin 命令。chatHeaderMoreMenu。chatInteractionPanelEmptyActions,支持 command、route、href,额外支持展示用 shortcut。routeHeaderActions,用 targetRoute / targetRoutes 限定宿主 route container,用 command 触发 plugin 命令。routeWindowBarActions,通常和 routeHeaderActions 成对注册,也用 targetRoute / targetRoutes 限定宿主 route container。routeMoreMenuItems,支持 command、route、href;其中 route 是点击后的跳转目标,不是宿主显示条件。routeSidebarContextMenu,支持 command、route、href;其中 route 是点击后的跳转目标,不是宿主显示条件。routes + clientView,前端用 ctx.views.register(viewId, render) 提供内容。workbenchTabs 或 workspaceDrawerTabs,用 placement: "bottom" | "right" 决定位置。+ 菜单:workbenchAddMenu。如果要点击后创建 tab,设置 tab 指向 workbenchTabs[].id。launcherSearchProviders,桌面 launcher 使用 server-backed command;workspace client 可以再用 ctx.launcher.registerSearchProvider 注册本地搜索。toolUsePresentations,用纯声明配置工具匹配、Material Symbol、国际化标题、摘要目标、输入字段和结果格式;不要为单个插件在聊天组件里新增 renderer 或注入 JSX/HTML。extensionPoints 或 ctx.extensionPoints.register 暴露 <scope>/<id>;其他插件用 ctx.extensionPoints.onAvailable('<scope>/<id>', point => ctx.extensionPoints.contribute(...)) 监听目标点出现后补充结构化能力。只有 manifest 里声明的静态贡献才用 extensionContributions。ctx.pluginApis.register({ id, inputSchema, outputSchema, handler }) 暴露 in-client 过程调用;调用方用 await ctx.pluginApis.call('<scope>/<id>', input)。所有调用必须是 Promise,运行时会等待目标 API 注册并等待 handler 完成。ctx.registerCommand 或 ctx.registerApi;前端通过 ctx.commands.execute 或 ctx.api.fetch 调用。ctx.runtime.registerChannel 和 ctx.runtime.invokeChannel;前端通过 ctx.runtime.invokeChannel 调用当前 scope 的 server runtime channel。关键语义:
workbenchTabs 是“可创建 tab 模板”,不是启动后常驻 tab。targetRoute / targetRoutes 是宿主显示条件,菜单项里的 route 是点击后的导航目标,二者不要混用。targetRoute / targetRoutes 支持 route key、当前 pathname 和 /* 后缀路径通配。路径可以写应用内路径(如 /plugins/*)或带 client basename 的路径(如 /ui/plugins/*),两者都会归一匹配。配置页的 settings / config 是互通 alias:targetRoute: "settings" 可以匹配当前 config route,targetRoute: "config" 也可以匹配旧的 settings route。nav-rail-more-menu / overlay 结构渲染;不要让 plugin 或业务 route 自己拼菜单 DOM、局部 CSS 或 hover / selected / shortcut 样式。useRoutePluginChrome(routeKey) 统一安装;route sidebar 右键菜单只有在宿主 route 提供共享 sidebar 数据时才会显示。active 切换 activeIcon / activeLabel / activeTitle,disabled 禁用,danger hover/focus 使用危险色,shortcut 进入 tooltip;菜单型贡献额外支持 selected。旧 routeMoreMenu 只是兼容别名,新插件写 routeMoreMenuItems。chatInteractionPanelEmptyActions 是 chat 专属扩展点,只扩展新建面板默认页的 action card;它不进入通用 route container,也不替代 workbenchAddMenu。如果需要新增真实底部 / 右侧 tab,继续用 workbenchTabs + workbenchAddMenu。toolUsePresentations 默认只按 base name 匹配当前插件 scope 下的 OneWorks MCP 工具;只有明确要展示其他来源工具时才设置 origin: "any"。对象数组使用宿主 records 字段并声明 item 路径,短原子数组使用 chips;结果较大时优先用 result.mode: "declared" + result.fields 做渐进披露,不要默认铺完整协议 JSON。输入和结果只能选择宿主支持的结构化格式,不允许可执行模板、任意 HTML 或插件私有 React renderer。workbenchAddMenu 创建的新 tab 应该可关闭;不要把普通 plugin tab 做成默认固定。/api/*;所有 API 必须在 /api/plugins/<scope>/* 下。plugin.server.roles。package.json 的 exports["./server"] 只补入口路径;未声明 roles 时宿主拒绝注册 server 入口并在 diagnostics 暴露错误。需要 manager 时必须显式写 roles: ["manager"] 或 ["manager", "workspace"]。target 里传 role 和 serverBaseUrl;不要把当前 workspace server 当成唯一 server。id、titleI18n / descriptionI18n、icon 和 command,由拥有方 view 决定如何渲染。如果 plugin 需要用户可编辑配置,必须优先在 manifest 里声明 config.schema,让插件详情页「配置」tab 自动渲染表单:
type: "object" 和 properties。titleI18n 和 descriptionI18n,至少覆盖 en 与 zh-Hans;保留 title / description 作为兜底也可以,但不要只写英文标题。string、number、integer、boolean、字符串数组、enum、oneOf / anyOf 里的字符串 const 选项。default 表达默认值;不要为了默认值提前写入 .oo.config.json。x-oneworks-ui.icon、placeholder、control、sensitive 描述图标、占位符、textarea / 普通输入、敏感字段。format: "password"、writeOnly: true 或 x-oneworks-ui.sensitive: true 用于 token、密钥等敏感配置。config.uiSchema 直接声明配置页内部 ConfigUiObjectSchema;不要为普通字段手写自定义页面。配置值读取规则:
.oo.config.json。default 或代码里的保守默认兜底。plugins[].options,不要污染其他 scope 或全局配置。view.options.value 读取当前实例配置,并调用 await view.options.update(nextOptions) 写回当前实例;不要绕过宿主去直接请求顶层 /api/plugins/*/options。每个用户可见贡献项都要写清楚名称和说明:
id 是稳定机器标识,短横线命名,不展示给用户当说明。displayName、displayNameI18n.en、displayNameI18n.zh-Hans 和 icon。displayName 是兼容旧宿主的英文兜底;宿主优先显示当前语言的 displayNameI18n。icon 必须指向 plugin 根目录内的相对资产(推荐 ./assets/icon.svg),禁止绝对路径和 .. 穿越。优先设计简洁、深浅主题都清晰的 SVG,不要用宿主固定的 extension 图标冒充插件自己的品牌图标。title 是兜底文案;同时写 titleI18n.en 和 titleI18n.zh-Hans。titleI18n / descriptionI18n 解析成当前应用语言;不要在左侧导航、菜单、workbench 等宿主 slot 里自己判断浏览器语言。descriptionI18n.en 和 descriptionI18n.zh-Hans 描述这个入口点击后做什么、展示在哪里、是否调用命令或 server。icon 使用 Material Symbols 名称,选择能表达入口语义的图标。README 多语言规则:
README.md 使用用户当前对话语言作为默认语言:用户用中文沟通时写中文,用户用英文沟通时写英文。README.en.md,默认是英文时补 README.zh-Hans.md。优先复用已有 plugin;没有时创建可提交 package plugin:
packages/plugins/<plugin-name>/
package.json
plugin.json
assets/icon.svg
README.md
README.zh-Hans.md
client/src/index.tsx
client/src/view.tsx
client/src/i18n.ts
client/src/styles.ts
client/dist/index.js
client/vite.config.ts
server/src/index.ts
server/dist/index.js
server/tsconfig.json
package.json 最小骨架:
{
"type": "module",
"scripts": {
"build": "pnpm run build:client && pnpm run build:server",
"build:client": "tsc -p client/tsconfig.json --noEmit && vite build --config client/vite.config.ts",
"build:server": "tsc -p server/tsconfig.json"
},
"exports": {
"./client": {
"source": "./client/src/index.tsx",
"default": "./client/dist/index.js"
},
"./server": {
"source": "./server/src/index.ts",
"default": "./server/dist/index.js"
},
"./package.json": "./package.json"
},
"devDependencies": {
"vite": "^5.4.8"
}
}
plugin.json 最小骨架:
{
"__oneWorksPluginManifest": true,
"name": "@local/plugin-example",
"displayName": "Plugin Example",
"displayNameI18n": {
"en": "Plugin Example",
"zh-Hans": "插件示例"
},
"icon": "./assets/icon.svg",
"version": "0.1.0",
"config": {
"schema": {
"type": "object",
"properties": {
"greeting": {
"type": "string",
"default": "Hello from Plugin Example",
"titleI18n": {
"en": "Greeting",
"zh-Hans": "问候语"
},
"descriptionI18n": {
"en": "Text shown by plugin commands and views.",
"zh-Hans": "插件命令和视图展示的文本。"
},
"x-oneworks-ui": {
"icon": "waving_hand",
"placeholder": "Hello from Plugin Example"
}
}
}
}
},
"plugin": {
"server": {
"roles": ["workspace"]
},
"contributions": {
"routes": [
{
"id": "home",
"title": "Plugin Example",
"titleI18n": {
"en": "Plugin Example",
"zh-Hans": "插件示例"
},
"descriptionI18n": {
"en": "Opens the standalone plugin route.",
"zh-Hans": "打开独立插件页面。"
},
"clientView": "home"
}
],
"workbenchTabs": [
{
"id": "panel",
"title": "Plugin Example",
"titleI18n": {
"en": "Plugin Example",
"zh-Hans": "插件示例"
},
"descriptionI18n": {
"en": "Renders a bottom workbench tab.",
"zh-Hans": "渲染底部工作区标签页。"
},
"placement": "bottom",
"clientView": "panel"
}
],
"workbenchAddMenu": [
{
"id": "open-panel",
"title": "Plugin Example",
"titleI18n": {
"en": "Open Plugin Example panel",
"zh-Hans": "打开插件示例面板"
},
"descriptionI18n": {
"en": "Creates a new bottom workbench tab from the panel template.",
"zh-Hans": "基于面板模板创建新的底部工作区标签页。"
},
"tab": "panel"
}
]
}
}
}
路径规则:
packages/plugins/<plugin-name>/,通过 package name / exports 和 .oo.config.json 的 plugins 数组显式声明启用。.oo/plugins.dev/<plugin-name>/,它会自动发现并默认开启 watch。packages/plugins 语义、不是前端工程,或只是想在普通项目资产目录快速放一个轻量插件,可以使用 .oo/plugins/<plugin-name>/,但需要在 .oo.config.json 里用显式目录路径声明;宿主不会再把 .oo/plugins/* 普通子目录自动当成 UI plugin 加载。plugin.json / plugin.yaml / plugin.yml,不放在 .codex-plugin/ 下面。README.md 使用当前对话语言,另一种语言使用 README.en.md 或 README.zh-Hans.md。两个 README 描述同一组入口、配置项、命令、API 和调试方式。plugins[].options。client/src/index.tsx 导出 activatePlugin(ctx),并由 Vite 编译到 client/dist/index.js:
package.json exports 约定暴露入口:exports["./client"].source 指向 client/src/index.tsx,exports["./client"].default 指向 client/dist/index.js,exports["./server"].source 指向 server/src/index.ts,exports["./server"].default 指向 server/dist/index.js。server 入口的运行层级写在 manifest 的 plugin.server.roles;不要在 manifest 里重复写 plugin.client.entry、plugin.client.root 或 plugin.server.entry。.oo/plugins.dev/* 时,开发态宿主会把 exports["./client"].source 转成同源 /@fs/... entry,由宿主 Vite dev server 负责 TS / TSX 转译、source map、样式模块 HMR 和 React Fast Refresh;新插件不要配置 plugin.client.devServer。client/src/index.tsx 只做薄入口:加载子模块、注入样式、注册 view / command / launcher provider、集中 dispose。页面组件、i18n 文案、样式和数据模型拆到 client/src/view.tsx、client/src/i18n.ts、client/src/styles.ts 等 ESM 模块;不要把整套插件都写进一个入口文件。vite build --config client/vite.config.ts 生成 client/dist/index.js;不要把含 TS / TSX 语法的源码文件当作静态入口。exports["./server"].source,并用 esbuild register 转译 .ts / .tsx / .mts / .cts。发布 / 提交时使用 exports["./server"].default 的 JS 产物。.oo/plugins.dev/* watch、显式 watch: true 和插件详情页 watch 对 manifest、server、README、静态入口,以及 host Vite client source 下普通 TS / 数据 / i18n / model 模块变更提供 plugin scope 级 reload。TSX / JSX 组件和样式模块交给 Vite HMR / React Fast Refresh,入口文件变化仍走 plugin scope 级 reload。ctx.views.register(viewId, { renderNode }) 注册 React view;manifest 的 clientView 必须能找到同名 view。无构建插件从 ctx.react 取 createElement / hooks;TSX 插件也必须复用宿主 React 单例,不要 bundle 第二份 React。ctx.views.register(viewId, render) 是兼容 DOM view,只用于简单无 React 插件。view.host.language 是当前界面语言,view.host.themeMode 是用户选择的 light | dark | system,view.host.resolvedThemeMode 是实际 light | dark,view.host.isDarkMode 是深色状态,view.host.surface 表示当前挂载在 route | workbench | drawer。view.i18n.resolveText({ en, "zh-Hans": "..." });前端命令、界面消息、launcher 本地搜索这类不在 view render 内执行的逻辑使用 ctx.i18n.resolveText(...) 或 ctx.i18n.getLanguage()。不要用 view.host.language.startsWith('zh') 手写分支,也不要只写英文硬编码。view.ui.* 声明式组件,不要复制宿主组件 DOM。当前组件包括 Icon、Button、Input、Segmented、Switch、Sender、ProjectFileTree,以及 overlay 系列的 OverlayDropdown、OverlayMenu、OverlaySearchMenu、OverlaySearchRow、OverlaySegmented、OverlaySelectLabel、OverlayTree;菜单、搜索、树、确认态、danger 态、快捷键和嵌套 submenu 都应该走这些结构化 overlay props。需要真实弹出浮层时优先用 OverlayDropdown,不要把 overlay primitive 直接平铺在插件页面里。overlay 树需要独立浮层外观时传 surface: true,不要在插件内手写 panel 样式。Sender 默认套用 chat sender surface,并包含模型、权限、adapter / account 和 status bar 编排。sender 样式只能通过 surface: "chat" | "plain"、density: "default" | "compact"、showHeader、showStatusBar、placeholder、initialContent、defaultAdapter、defaultModel 这类结构化选项控制。DOM view 兼容路径才使用 view.components.render(component, container, props),返回的 { dispose() } 必须在 view 的 dispose() 里清理;需要示例时参考 .oo/docs/usage/plugins/ui-runtime.md 的“宿主组件用法示例”。ctx.commands.register(commandId, handler) 注册前端命令。ctx.commands.execute(commandId, payload) 调用前端或 server command。ctx.extensionPoints.register({ id, title, description, contributionSchema }) 暴露插件自己的扩展点;贡献方用 ctx.extensionPoints.onAvailable('other-scope/point', point => ctx.extensionPoints.contribute('other-scope/point', contribution)),不要用激活时的一次性 has(...) 判断来决定是否贡献。React view 里用 view.extensions.getContributions('point') 读取当前插件扩展点的贡献。ctx.pluginApis.register({ id, title, description, inputSchema, outputSchema, handler }) 暴露插件内过程调用;其他插件用 await ctx.pluginApis.call('other-scope/api-id', input) 调用。call 的 Promise 会等待目标 API ready,也会等待 handler 处理完成;必要时传 timeoutMs 明确失败边界。ctx.api.fetch('apiId/path') 调 scoped API;不要传绝对 URL、协议相对 URL 或顶层 /api/*。ctx.runtime.invokeChannel(channelId, { payload, target }) 调用当前 scope 的 server runtime channel;跨 workspace / manager 调用时显式给 target.role 和 target.serverBaseUrl。ctx.notifications.show({ title, description, actions }) 发布宿主级消息。宿主会自动显示插件来源、发送时间、markdown 描述、按钮回调和关闭 / 屏蔽插件这类通用操作。不要在插件里自己创建 fixed toast 或引入另一套通知 UI。ctx.i18n.t({ en, "zh-Hans": ... }) / ctx.i18n.select(...) 渲染插件自带文案,跟随宿主应用语言;DOM view 需要在 ctx.i18n.subscribe() 里重绘,并在 dispose() 中清理订阅。ctx.hot.accept() 和 ctx.hot.reload() 支持本 plugin 的 scope 级调试重载;它不是 Vite Fast Refresh。React Fast Refresh 由宿主 Vite /@fs client source entry 提供,插件仍要复用宿主 React 单例、宿主组件继续走 view.ui.*。dispose() 里清理。默认把 plugin UI 做成宿主里的功能界面,不做营销页或展示页:
box-sizing: border-box; width: 100%; min-width: 0; min-height: 0;,需要纵向布局时再加 display: flex; flex-direction: column;。h1、eyebrow 或解释性 header;直接呈现当前页面的工具栏、表单、列表、输出区域等核心内容。pre / 列表 / 表格展示,但应跟随父容器宽度,避免固定宽度导致右侧空白。var(--ant-color-text)、var(--ant-color-text-secondary)、var(--ant-color-bg-container)、var(--ant-color-border)、var(--ant-color-border-secondary)、var(--ant-color-fill-quaternary)、var(--primary-color)、var(--primary-soft-bg)、var(--primary-text-color)、var(--bg-color)、var(--sub-bg-color)、var(--text-color)、var(--border-color) 等;不要硬编码一套高饱和主题色。var(--app-chrome-icon-size)、var(--app-chrome-action-gap)、var(--route-container-header-overlay-height)、var(--route-container-header-padding-inline)、var(--route-container-header-padding-block);不要在 plugin 里重新定义 header、tab、图标按钮高度。flex: 1 1 auto; width: 100%; min-width: 0;,不要用额外 wrapper 或固定 max-width 掩盖问题。server/src/index.ts 或发布态 server/dist/index.js 导出 activatePlugin(ctx):
ctx.registerCommand(commandId, handler) 暴露 scoped command。ctx.registerApi(apiId, { handler }) 暴露 scoped HTTP API,真实路径固定为 /api/plugins/<scope>/proxy/<apiId>/*。它就是插件的 route 注册工具;不要注册顶层 /api/*。ctx.registerApi(apiId, { proxy: { target } }) 只能代理到 loopback HTTP(S) 本地服务。registerApi 都必须写清 title、description、inputSchema、outputSchema、headerSchema。旧插件缺失时运行时兼容但会产生 plugin_api_metadata_missing 诊断;新插件不要省略。ctx.registerLocalService(serviceId, start) 管理随 plugin 生命周期启动/停止的本地服务。ctx.runtime.role 标识当前入口运行在 workspace 还是 manager;不要用环境变量或 URL 自己判断。ctx.runtime.registerChannel(channelId, handler) 注册当前 scope 的 runtime 通信通道。ctx.runtime.invokeChannel(channelId, invocation) 调用当前 scope 的 runtime 通道;跨 runtime 时必须传明确目标。ctx.dispose(callback) 清理 timer、server、watcher、临时资源。ctx.workspaceFolder、ctx.projectHome 和 ctx.pluginRoot,不要猜路径。registerApi 的 handler 按 request.method 和 request.path 分发子路由;如果需要完整 Express / Hono / Fastify router,使用 registerLocalService 启动本地 loopback 服务,再用 registerApi(..., { proxy }) 暴露为 scoped API。Server route 示例:
const json = (body: unknown, status = 200) => ({
status,
headers: {
'content-type': 'application/json; charset=utf-8'
},
body
})
export function activatePlugin(ctx) {
ctx.registerCommand('snapshot', payload => ({
ok: true,
scope: ctx.scope,
received: payload
}))
ctx.registerApi('notes', {
title: {
en: 'Notes API',
'zh-Hans': '笔记 API'
},
description: {
en: 'Creates and lists notes inside the plugin scoped API.',
'zh-Hans': '在插件作用域 API 内创建和列出笔记。'
},
inputSchema: {
type: 'object',
properties: {
title: { type: 'string' }
},
additionalProperties: false
},
outputSchema: {
type: 'object',
additionalProperties: true
},
headerSchema: {
type: 'object',
properties: {
'content-type': { const: 'application/json' }
},
additionalProperties: true
},
handler: async request => {
if (request.method === 'GET' && request.path === '') {
return json({ notes: [] })
}
if (request.method === 'POST' && request.path === 'create') {
const payload = JSON.parse(request.body.toString('utf8') || '{}')
return json({ created: true, payload }, 201)
}
return json({ error: 'Not found' }, 404)
}
})
}
前端调用时使用 ctx.api.fetch("notes/create", { method: "POST", body: JSON.stringify(payload) }),不要拼绝对 URL。
实现后按影响面验证:
GET /api/plugins 能看到 plugin、scope、贡献项和诊断。GET /api/plugins 中能看到 displayName、displayNameI18n 与 icon;切换中文/英文后插件列表与详情标题使用对应名称,图标资产请求返回成功。/plugins 插件商店能看到 plugin;/plugins/<scope> 详情能看到 README、entry、contributions、runtime 注册项和 watch 开关。+ 菜单、创建/关闭 workbench tab、launcher 搜索。workbenchAddMenu.tab 创建的是新 tab 实例,不是常驻 tab。client/src/view.tsx 或样式文件后,宿主 Vite dev server 应能触发模块 HMR / React Fast Refresh;改 client/src/index.tsx、普通 TS / 数据 / i18n / model 模块、manifest、server 或 README 后,plugin watch 触发 scope 级 reload,不需要重启 Electron。vitest、pnpm typecheck 和 pnpm dprint check。如果新增了用户可见 plugin 能力,同步更新:
.oo/docs/usage/plugins.md:manifest、扩展点、watch、plugin store、server API。.oo/docs/usage/web.md:Web UI 上的具体入口和交互变化。