跳转到内容

插件系统

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.json manifest 和 ESM 入口文件位于同一插件目录内
  • 如果插件没有立即出现,添加后重启一次 OxideTerm

插件从 ~/.oxideterm/plugins/{plugin-id}/ 动态加载:

~/.oxideterm/plugins/my-plugin/
├── plugin.json
├── main.js
├── locales/
└── assets/

宿主会先校验 manifest,再构造冻结的 PluginContext,最后调用插件 ESM 入口里的 activate(ctx)

{
"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.sftpctx.forwardctx.terminal 等命名空间直接暴露。

插件会收到一个冻结的 PluginContext,其中包含顶层 pluginId 字段和 18 个 API 命名空间

  • connections
  • events
  • ui
  • terminal
  • settings
  • i18n
  • storage
  • api
  • assets
  • sftp
  • forward
  • sessions
  • transfers
  • profiler
  • eventLog
  • ide
  • ai
  • app

其中 ctx.ui 现在已经完成宿主接线:

  • ctx.ui.registerContextMenu():支持 terminalsftptabsidebar
  • ctx.ui.registerStatusBarItem():渲染到主布局底部状态栏
  • ctx.ui.registerKeybinding():进入全局快捷键分发链路
  • ctx.ui.showProgress():显示右上角进度 HUD

插件通过 window.__OXIDE__ 使用宿主提供的共享模块:

  • React
  • ReactDOM
  • zustand
  • lucideIcons
  • lucideReact
  • ui
  • version
  • pluginApiVersion

这样可以避免打包重复的 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 类型定义,请继续阅读插件开发指南。