
使用 Devtools Sample Plugin 在 Stage Tamagotchi 中验证 AIRI 插件宿主生命周期【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi本文以 Stage Tamagotchi 桌面端内置的 devtools-sample-plugin 示例插件为切入点完整讲解 AIRI 插件Extension从清单声明、运行时实现到通过 Extension Host Inspector 页面完成发现、启用、加载与状态验证的完整闭环并深入剖析背后插件宿主服务Extension Host的清单扫描、校验、会话管理与调试快照实现。读完本文你将掌握在 Stage Tamagotchi 中手写一个最小可验证插件、并在开发工具页中调试插件宿主行为的完整方法。示例插件的定位插件宿主的“体检样板”devtools-sample-plugin位于 apps/stage-tamagotchi/src/main/services/airi/plugins/examples/devtools-sample-plugin/其核心定位正如其 README 所述用于在 Extension Host Inspector插件宿主检查器页面中验证插件宿主extension host行为。它刻意保持最小化只有一个清单文件加一个实现文件setup阶段只向 renderer/main 控制台打印一条启动日志不修改任何应用状态。正因如此它非常适合作为生命周期验证的“探针”——任何一次 Enable / Load / Unload 操作都能通过它观察到插件宿主的真实反馈而不必担心副作用污染调试结果。文件构成一个最小插件只有两个文件文件作用extension.airi.json插件清单manifest遵循ExtensionManifestV1规范devtools-sample-plugin.mjs插件运行时实现extension implementation清单负责“声明”实现文件负责“执行”。宿主加载器host loader通过清单找到入口点再把实现文件作为模块加载进插件会话。清单声明身份、权限与入口extension.airi.json的完整内容如下{ apiVersion: v1, kind: manifest.extension.airi.moeru.ai, id: devtools-sample-plugin, permissions: { apis: [ { key: proj-airi:plugin-sdk:apis:protocol:capabilities:wait, actions: [invoke] }, { key: proj-airi:plugin-sdk:apis:protocol:resources:providers:list-providers, actions: [invoke] } ], resources: [ { key: proj-airi:plugin-sdk:apis:protocol:resources:providers:list-providers, actions: [read] } ], capabilities: [ { key: proj-airi:plugin-sdk:apis:protocol:resources:providers:list-providers, actions: [wait] } ] }, entrypoints: { electron: ./devtools-sample-plugin.mjs } }关键字段说明apiVersion清单规范版本当前为v1kind清单类型标识manifest.extension.airi.moeru.ai配合 packages/plugin-sdk/src/plugin-host/shared/types.ts 中的ExtensionManifestV1类型与校验模式extensionManifestV1Schema使用加载时会用 valibot 的safeParse做严格校验见 registry.tsid全局唯一的插件标识也是宿主侧运行时身份ExtensionId。清单校验失败或 id 缺失的插件会被直接跳过permissions声明插件需要的 API、资源与能力。示例声明了两个 APIcapabilities:wait、resources:providers:list-providers的invoke权限、一个资源的read权限以及对应能力的wait权限。这些声明会在调试快照中以capabilities列表形式呈现给检查器页面entrypoints.electronElectron 运行时下的入口文件路径。宿主在加载时会优先取entrypoints.electron其次回退到entrypoints.default见 registry.ts 的resolvePluginRuntimeEntrypointPath。实现一个打印日志的 setupdevtools-sample-plugin.mjs通过 packages/plugin-sdk/src/extension/define.ts 导出的defineExtension声明插件import { defineExtension } from proj-airi/plugin-sdk function nowIso() { return new Date().toISOString() } export default defineExtension({ id: devtools-sample-plugin, setup() { console.info([devtools-sample-plugin] setup, { at: nowIso() }) }, })defineExtension是插件 SDK 提供的公共创作 API它要求id与extension.airi.json中声明一致setup中可通过ctx.kits访问宿主注册的 Kit 能力。示例插件只做一件事在setup被调用时向控制台输出一条带时间戳ISO 格式的启动日志。从源码结构看这是一个刻意保持“无状态变更”的设计确保它可以安全地反复用于生命周期验证。在 Extension Host Inspector 中验证插件生命周期第一步进入/devtools/plugin-host页面在 Stage Tamagotchi 中打开/devtools/plugin-host路由。该入口位于开发者设置页的 “Plugin Host Debug” 菜单项其页面描述为 “Inspect discovered/enabled/loaded plugins and control load/unload lifecycle”检查已发现/已启用/已加载的插件并控制加载/卸载生命周期见 developer.vue。第二步从页面读取registry.root路径页面上会展示插件注册表根目录registry.root。从源码看该快照由buildPluginRegistrySnapshot生成其root字段即扩展根目录见 registry.ts。在桌面端实现中这个根目录由宿主服务在启动时计算const extensionsRoot join(app.getPath(userData), extensions, v1)即 ElectronuserData目录下的extensions/v1子目录见 host/index.ts。如果你在外部挂载或符号链接了插件目录注册表同样支持解析符号链接。第三步把两个文件复制进registry.root将extension.airi.json与devtools-sample-plugin.mjs复制到registry.root目录下并且每个插件必须放在独立的子目录中例如registry.root/ └── devtools-sample-plugin/ ├── extension.airi.json └── devtools-sample-plugin.mjs这是因为清单发现逻辑会遍历根目录下的每个子目录在子目录内查找名为extension.airi.json的文件见 registry.ts 中loadManifestsFrom的目录扫描逻辑。此外若子目录还包含package.json其version字段会被读取为插件版本缺失时回退为0.0.0见 registry.ts。第四步在检查器页面执行 刷新 → 启用 → 加载在 Extension Host Inspector 中按顺序操作点击Refresh触发注册表重新扫描宿主会调用refreshManifests()重新加载磁盘上的清单在列表中定位devtools-sample-plugin每个插件的摘要项由createPluginSummary生成包含extensionId、entrypoints、path、enabled、autoReload、loaded、isNew等状态字段见 registry.ts点击Enable将插件 id 写入持久化配置的enabled列表见 host/index.ts 的setEnabled并记录其清单路径到known映射点击Load或Load Enabledload会按 id 查找清单条目并启动会话loadEnabled则遍历注册表中所有已启用插件逐个加载见 host/index.ts 与 host/index.ts。第五步确认三项验证结果加载完成后检查以下状态是否符合预期插件状态为loaded会话已建立loaded集合中包含该插件 id会话阶段session phase变为ready插件会话完成初始化进入就绪状态能力列表capability list可见检查器页面能够展示插件声明的能力项。同时在 renderer/main 控制台应能看到[devtools-sample-plugin] setup开头的启动日志这是setup钩子被宿主成功调用的直接证据。原理深入插件宿主如何发现、校验与加载清单发现与校验宿主启动时通过setupExtensionHostServiceInternal完成整体装配见 host/index.ts创建配置存储createExtensionHostConfigStore()创建内置 Kit 运行时并注册宿主 KitregisterHostKits创建ExtensionHostruntime 为electron创建扩展注册表并refresh()扫描清单。loadManifestsFrom对每个子目录执行readFile读取清单 JSON再用safeParse(extensionManifestV1Schema, ...)做模式校验只有校验通过的清单才会进入注册表无效清单仅记录警告并跳过。注册表内部以MapextensionId, ManifestEntry维护按 id 的查找索引重复 id 只保留首个条目。加载与自动重载加载loadExtensionById通过host.start(manifestForLoad, { cwd: dirname(entry.path) })启动会话并以cwd指向清单所在目录随后记录loaded与loadedSessionIds映射见 host/index.ts。卸载stopLoadedExtensionById调用host.stop(sessionId)同时清理模块资源会话缓存与静态资源服务保证插件卸载后不留残留见 host/index.ts。自动重载宿主内置 auto-reload 特性features/auto-reload监听清单文件与入口文件的变更重载时通过createManifestForLoad给入口 URL 追加cacheBust参数以避免陈旧模块缓存见 registry.ts。调试快照的构成buildPluginHostDebugSnapshot见 debug.ts向检查器页面返回完整的宿主快照包含registry注册表快照根目录 插件摘要列表sessions每个会话的id、extensionId、phase即 README 中的 session phase、runtime、moduleIdkits宿主已注册的 Kit 列表modules插件声明的模块绑定bindingwidget 模块的 iframe 资源 URL 会被重写为挂载后的扩展资源地址capabilities插件声明的能力列表refreshedAt快照生成时间戳。检查器页面每次点击 Refresh 都会触发inspect()重新构建该快照因此你看到的状态始终与磁盘和内存中的真实状态一致。小结通过 devtools-sample-plugin 示例我们验证了一条完整的插件宿主链路清单声明 → 目录放置 → 注册表扫描与模式校验 → 启用持久化 → 会话加载 → 调试快照反馈。你只需复制两个文件、点几下按钮就能确认宿主基础设施工作正常。在此基础上把示例插件中的setup换成真实业务逻辑并配合 packages/plugin-sdk 的defineExtension、ctx.kits与 kits 中的 gamelet、widget Kit即可快速进入 AIRI 插件开发的实战阶段。相关测试用例可参考 plugins/index.test.ts 与 plugin-sdk 的 core.test.ts。【免费下载链接】airi Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-samas altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考