插件系统
OxideTerm 提供运行时插件系统,允许第三方扩展在不修改核心应用的情况下添加标签页、侧边栏面板、终端钩子、命令、SFTP 工作流,以及轻量级宿主 UI 集成。
本页同时覆盖用户视角的插件模型和开发者视角的运行时 API。
OxideTerm 刻意保持核心应用本地优先、按需启用。官方插件则在这个基础上补充特定工作流:
- Cloud Sync — 通过 WebDAV、HTTP JSON、Dropbox、Git 或 S3 对
.oxide快照进行加密的自托管同步与备份 - Telnet Client — 面向旧路由器、交换机和设备的原生 Telnet 客户端
官方插件完全是可选项。你不需要注册账号就能使用 OxideTerm,任何云相关工作流也都保持 opt-in。
只要插件的 manifest 和入口文件位于 ~/.oxideterm/plugins/{plugin-id}/ 下,插件就会被 OxideTerm 识别。
- 将插件下载或 clone 到插件目录中
- 保持
plugin.jsonmanifest 和 ESM 入口文件位于同一插件目录内 - 如果插件没有立即出现,添加后重启一次 OxideTerm
插件从 ~/.oxideterm/plugins/{plugin-id}/ 动态加载:
~/.oxideterm/plugins/my-plugin/├── plugin.json├── main.js├── locales/└── assets/宿主会先校验 manifest,再构造冻结的 PluginContext,最后调用插件 ESM 入口里的 activate(ctx)。
Manifest 结构
Section titled “Manifest 结构”{ "id": "my-plugin", "name": "My Plugin", "version": "1.0.0", "main": "./main.js", "engines": { "oxideterm": ">=1.6.0" }, "contributes": { "tabs": [ { "id": "dashboard", "title": "Dashboard", "icon": "LayoutDashboard" } ], "sidebarPanels": [ { "id": "overview", "title": "Overview", "icon": "PanelLeft", "position": "top" } ], "apiCommands": ["list_connections"] }}当前插件运行时没有单独的 permissions 字段。后端命令访问通过 contributes.apiCommands 声明,而更高层的能力则通过 ctx.sftp、ctx.forward、ctx.terminal 等命名空间直接暴露。
PluginContext API
Section titled “PluginContext API”插件会收到一个冻结的 PluginContext,其中包含顶层 pluginId 字段和 18 个 API 命名空间:
connectionseventsuiterminalsettingsi18nstorageapiassetssftpforwardsessionstransfersprofilereventLogideaiapp
其中 ctx.ui 现在已经完成宿主接线:
ctx.ui.registerContextMenu():支持terminal、sftp、tab、sidebarctx.ui.registerStatusBarItem():渲染到主布局底部状态栏ctx.ui.registerKeybinding():进入全局快捷键分发链路ctx.ui.showProgress():显示右上角进度 HUD
插件通过 window.__OXIDE__ 使用宿主提供的共享模块:
ReactReactDOMzustandlucideIconslucideReactuiversionpluginApiVersion
这样可以避免打包重复的 React 实例,也能保持插件体积更小。
当前插件运行时采用的是分层约束,而不是真正的浏览器沙箱:
- 冻结膜层:
PluginContext通过Object.freeze()构造,防止修改宿主 API 对象。 - Manifest 校验:tabs、sidebar panels、terminal hooks、backend commands 都需要先声明再使用。
- 建议性后端白名单:
ctx.api.invoke()只能调用contributes.apiCommands中声明过的命令。 - 路径安全:插件文件读取会拒绝跳出插件目录的路径遍历。
- 熔断器:频繁抛错的插件会被自动禁用。
- 终端 fail-open:终端输入/输出钩子抛错时会回退到原始数据。
const { React } = window.__OXIDE__;const { createElement: h } = React;
function DashboardTab({ pluginId, tabId }) { return h('div', { className: 'p-6' }, `Hello from ${pluginId}:${tabId}`);}
export function activate(ctx) { ctx.ui.registerTabView('dashboard', DashboardTab);
ctx.ui.registerCommand( 'hello.open-dashboard', { label: '打开 Dashboard', icon: 'LayoutDashboard' }, () => ctx.ui.openTab('dashboard'), );
ctx.events.onConnect((connection) => { ctx.ui.showNotification({ title: '连接已激活', body: `${connection.username}@${connection.host}`, severity: 'info', }); });}如果你需要完整的 API 参考、manifest 字段说明、共享模块细节和 TypeScript 类型定义,请继续阅读插件开发指南。