shaomang/mtnode-aio/plugin-dev
Claude Code and agent skill by shaomang/mtnode-aio
- community
Checking that the SKILL.md file is still in the repository.
MTNode 应用插件(catalog 窗口插件 / builtin / 本地后端插件)的开发规范:插件类型与边界、后端插件三层结构(主进程宿主 · 预加载桥 · 控制台 UI)、主进程与渲染层接线点、build.json 打包白名单、画布节点与 i18n / 指南 / 冒烟交付清单、报错总线与自我修复、数据目录纪律,含最小骨架与常见坑。新建或改造 MTNode 插件(顶栏「插件」对话框里那个东西)时按需加载。
Install
npx vskill@latest install shaomang/mtnode-aio/plugin-devSKILL.md
MTNode 插件开发规范
本技能是仓库内部开发纪律(不写 menu: user,不进用户技能清单):新建 / 改造 MTNode 应用插件时照着做。 所有结论来自当前仓库真实代码;与代码冲突时以代码为准,并回来修订本文件。
一、先把边界划清
MTNode 里「扩展能力」有四种完全不同的东西,别混为一谈:
| 东西 | 是什么 | 契约出处 | |
|---|---|---|---|
| 应用插件(本技能管的) | 顶栏「插件」对话框里的卡片:窗口插件、pet、以及带本地后端 + 控制台 + 画布节点的 music3 / yue2 / sensenova / h3 / llama / tts / remotion | plugins/catalog.default.json、plugins/main-app-plugins.js、各 */main-*.js | |
| DSH 插件 | Agent 网关侧插件(工具能力) | dsh/gateway/*-plugin.mjs、dsh/DESIGN.md | |
| 技能 Skills | Agent 的按需指令集 | mtnode-agent-skills/**、skills/**(安装类)、ext-repo/skills/**(云发版) | |
| MCP 扩展 | 外部 MCP server 接入 | renderer/app-plugins.js 的 EXT_KINDS + #extManagerDlg |
后三类都在「设置 → 扩展能力 → 管理…」里维护(EXT_UI);应用插件卡片只在顶栏「插件」对话框,两者不要互相塞。 本技能只讲第一类。
二、实例登记表(当前真实在库的插件)
| 插件 id | kind | 主进程目录 | 控制台入口 | 画布节点 | 打包脚手架 | |
|---|---|---|---|---|---|---|
minimax-music3 | music3 | music3/main-music3.js | music3/ui/index.html | music_gen | music3-pack/ | |
yue2-local | yue2 | `yue/main-yue.js` | yue/ui/ | yue_gen | yue-pack/ | |
sensenova-local | sensenova | sensenova/main-sensenova.js | sensenova/ui/ | sensenova_gen | sensenova-pack/ | |
minimax-h3 | h3 | h3/main-h3.js | h3/ui/ | video_gen | h3-pack/ | |
llama-local | llama | llama/main-llama.js | llama/ui/console.html | (做模型服务,无媒体节点) | llama-pack/ | |
breeze-tts-local | breeze | breeze/main-breeze.js | breeze/ui/console.html | breeze_gen | breeze-pack/ | |
remotion | remotion | remotion/main-remotion.js | remotion/ui/index.html | remotion | remotion-pack/ | |
bongochat | pet | pet/main-pet.js | 独立宠物进程 --mtnode-pet | — | pet-pack/ | |
forum | builtin(window) | plugins/main-app-plugins.js 的 BUILTIN_WINDOW_PLUGINS | 应用内 forum/chat.html | — | forum/** 直接打包 |
坑(必记):目录名 ≠ kind ≠ id。YuE2 的目录叫 yue/、pack 叫 yue-pack/,但 kind 是 yue2、id 是 yue2-local。 新插件起名时目录、pack、kind、id 四处都写清楚,别靠猜。
三、三类插件的形态
- 窗口插件(kind: `window`):一个 zip(入口
index.html+ 宿主plugins/preload-window.js),云端catalog.json里带zipUrl+sha256,用户点「下载安装」后解到<数据目录>/app-plugins/<id>/runtime/。不动主程序即可上新。 - builtin:随应用内置(当前只有讨论区
forum),BUILTIN_WINDOW_PLUGINS里写死dir / entry / window,不走下载链。 - 本地后端插件(八类 kind):主进程宿主 + Python/Node 后端 + 控制台窗 + 画布节点。本技能的重点,见下。
KNOWN_KINDS(plugins/main-app-plugins.js)是白名单:新 kind 不加进去,卡片会被降级成 `unknown`,按钮与控制台入口全失效。
四、后端插件的共同结构
数据流(一条生成任务的全链):
五、五层接线点(新插件一个都不能漏)
- catalog:
plugins/catalog.default.json加词条(id/kind/handler/order/version/minAppVersion/icon/title{zh,en}/subtitle{zh,en}),order决定卡片顺序(现用 20/30/35/36/40/50/60/65/70)。 - 主进程白名单:
plugins/main-app-plugins.js→KNOWN_KINDS(把新 kind 加进去);若 kind 与 handler 不同名,normalizePlugin里的 handler 兜底链也要补一条;build.json→files:<kind 目录>/**与<pack 目录>的 extraResources 条目(见第八节)。
- main.js 接线:
require("./<dir>/main-<name>.js")→ 在app.whenReady段register<Name>Ipc({ getDataDir: DATA, getMainWin: () => mainWin, appRoot: __dirname, getDsh: () => dsh() }),紧跟在initPluginErrorBus({ getMainWin: () => mainWin })之后;app.on("before-quit")里补shutdown<Name>UiOnly()。
- 后端要不要随 MTNode 退出:单例后端(music3 / h3 / yue / sensenova)故意不杀,只在 before-quit 关控制台窗;新插件必须在两处注释里写明选了哪种、为什么。
- preload.js 桥:
window.api.<kind>Xxx白名单转发(ipcRenderer.invoke('<kind>:…')),事件订阅(onXxxProgress/onXxxConsoleChanged/onXxxGpu)返回退订函数。渲染层拿不到桥 = 卡片与节点全是「未就绪」。 - 渲染层卡片:
renderer/app-plugins.js→refresh<Name>PluginCard(root)+bind<Name>Progress(card),并在openAppPluginsDialog()的kind === "<kind>" || handler === "<kind>"链里挂一行(顺序无所谓,但要和attachInstalled/ catalog 词条一致);卡片动作按钮的图标只能取PLUGIN_ACT_SVG(play/stop/download/update/gear)——表里没有的 kind 必须先补图标,否则按钮渲染成没有图标的空方块。
封面图标放 plugins/icons/<id>.png(1:1),加载顺序 plugins/icons → renderer/plugin-icons。
六、画布节点接线
- 节点类型在
renderer/app-nodes.js里实现,命名用 kind 短名(music_gen/yue_gen/breeze_gen/video_gen/remotion/sensenova_gen)。 - 节点运行前先判插件就绪:后端没装 / 没起时给明确中文指路(去顶栏「插件」装或起),不要只报「生成失败」。
- 宿主返回的错误码要在节点状态行 + 插件卡片 + 报错报告三处口径一致(同一串 code,渲染层按串匹配文案)。
- 关联回归:
test/smoke-media-gen-menu.js(菜单与节点归属)、test/smoke-tools.js、test/smoke-plugin-repair.js。 - 新增节点类型必须补指南
guides/nodes/<kind>.md,并登记进guides/nodes/index.json;面向用户的操作说明进guides/manual/(如media-gen.md)。
七、数据与目录纪律
- 用户数据只写
%APPDATA%\pipeline-console(main.js的DATA,由getDataDir()传进宿主)或用户自己选的安装目录。
绝不写进应用目录(app.getAppPath() / exe 同目录):升级 / 卸载会带走或覆盖,且启动时 auditAppDirData() 会体检报警。
- 典型落点:
<数据目录>/app-plugins/<id>/{config.json,installed.json,data.json,runtime/}(宿主自己path.join(getDataDir(), …))。 - 打包资源(
*-pack/)运行时落<resources>/<xxx>-pack,安装时由宿主复制到用户选的安装目录,脚手架文件本身不落应用目录。 - 密钥 / 凭据只进
%APPDATA%,不入库、不提交。 - 运行时热更新用
plugins/runtime-feed.js的fetchRemoteManifest/downloadRuntimeTo(<kind>Feed走process.env.MTNODE_<NAME>_URL可覆盖,便于本地联调)。
八、打包清单(最容易漏的一节)
build.json 的 files 是显式白名单,不是整仓拷贝。新插件必须同步:
- 根目录新增 / 拆出的主进程模块(
*-store.js/*-lib.js/plugin-error-repair.js这类)只要会被main.js或已打包文件require,必须写进 `files`,否则解包运行Cannot find module './xxx.js'(真发生过:assets-store.js)。 extraResources的filter是正向白名单:venv、模型权重、依赖锁、`_probe_*.py` 一律不随包。- 渲染层新脚本挂进
renderer/index.html的脚本加载顺序(= 模块分层),样式进renderer/css/对应文件。
九、报错总线与自我修复(后端类插件必接)
- 总线行为契约见
docs/plugin-auto-repair.md:错误码归一、同插件同码 60s 去抖、可修复性判定 + 一次性 repairToken(10 分钟 TTL)、修复成功自动restart()。 - 不弹修复的错误(
NOT_REPAIRABLE):cancelled/user_stopped/force_killed/busy*/low_disk等 —— 交给 Agent 也修不好的,只出报告 + 中文指路。 - 修复技能的唯一真源是
skills/<id>-install/SKILL.md的【自我修复】模式:已知故障、交付要件、判据都写那里;别在弹窗文案里再抄一份。 - 窗口插件没有主进程宿主:失败时
plugins/main-app-plugins.js的ensureReportHost(id)按需登记(现场 =<数据目录>/app-plugins/<id>,不注册tailConsole)。 - 回归:
test/smoke-plugin-repair.js(宿主注册表、技能真源唯一、打包白名单、总线行为、三桥、persistent、i18n、文档存在性)。
十、配套能力:dsh / 缓存 / 存储
- 用 dsh 跑 LLM:
getDsh由main.js注入;鉴权用dsh/mtnode-llm-creds.js的resolveDshRunAuth(getDataDir())(复用 MTNode 设置里的模型 Key),把{ model, maxTokens, apiKey, baseUrl, provider, mtnodeProviders }塞进runFields。事件回灌:导出on<Name>DshEvent(ev)并在main.js的 dsh 事件分发里挂一行。 - 转写 / 生成缓存:明文 JSON 落插件自己的数据目录(tts 的音色库、llama 的模型清单都是范本)。
- AI 事实库 / 素材库 / 工具库:走
db-store.js、assets-store.js、tools-store.js的既有 IPC,不要为插件新开一套存储。 - 音视频互斥:
media-gen-global-lock.js的tryAcquireLock / refreshStaleLock / clearLock / releaseLock / busyMessage—— 同时在跑的只有 1 个音视频任务。 - 资产落盘:宿主拿
assetDirFor(wfId)回调(sensenova 范本)或自己在宿主内落<数据目录>/assets/<wfId>。
十一、最小骨架(占位符照抄替换)
后端插件 · 主进程宿主
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 90 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingmtnode-agent-skills/plugins/plugin-dev/SKILL.md
Popularity
- 7-day trend score
- 5
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/shaomang/mtnode-aio/plugin-dev)