贡献点
插件通过 ctx.ui.register* 注册六类贡献点。每个注册都返回一个清理函数
(Disposer),插件被禁用 / 卸载时宿主统一回放,无需手动管理。
id 前缀规则
Section titled “id 前缀规则”外部插件(包括官方插件,它们也是从磁盘加载的外部插件)注册的任何贡献点
id 必须以 <pluginId>. 开头(如 my-plugin.panel),否则注册被拒绝。
宿主对未加前缀的旧 bundle 会自动补全前缀(兼容早期插件),但显式书写
前缀仍是推荐做法。同贡献点同 id 冲突时,后注册的被拒绝。
内置插件(随宿主编译、使用核心命名空间)不受此限。
视图(registerView)
Section titled “视图(registerView)”注册侧栏条目 + 主区 React 组件。注册后自动获得 ⌘1..9 快捷键与命令 面板入口(两者都从可见侧栏派生,无需额外注册):
interface ViewContribution { id: string; // "my-plugin.panel" icon: PluginIcon; // lucide 图标组件 labelKey: string; // i18n 文案键,默认在 "views" 命名空间解析 ns?: string; // i18n 命名空间,缺省 "views" component: ComponentType; // React 组件}ctx.ui.registerView({ id: "my-plugin.panel", icon: Package, // lucide 图标组件 labelKey: "panelTitle", ns: "plugin-my-plugin", // 会被强制改写为 plugin-<id> component: MyPanel, // 普通 React 组件,React 来自宿主共享运行时});命令(registerCommand)
Section titled “命令(registerCommand)”⌘K 命令面板条目:
interface CommandContribution { id: string; // "my-plugin.sayHi" group: string; // 分组标题(已本地化的展示字符串) title: string; sub?: string; icon: PluginIcon; run: () => void | Promise<void>;}ctx.ui.registerCommand({ id: "my-plugin.sayHi", group: "My Plugin", title: "Say Hi", icon: Zap, run: () => ctx.ui.toast.info({ title: "Hi!" }),});设置分区(registerSettingsSection)
Section titled “设置分区(registerSettingsSection)”渲染在「设置」页里的配置区块:
interface SettingsSectionContribution { id: string; // "my-plugin.settings" icon: PluginIcon; labelKey: string; // 默认在 "settings" 命名空间解析 ns?: string; // 缺省 "settings" component: ComponentType;}快捷键(registerShortcut)
Section titled “快捷键(registerShortcut)”全局快捷键。combo 形如 "Mod+Shift+D":Mod = ⌘(macOS)/ Ctrl(其他),
Cmd / Ctrl 是 Mod 的同义词;Shift / Alt 可选;最后一段为单字符键。
大小写不敏感。内置快捷键优先命中(⌘K / T / W / D、⌘0..9),未处理的
按键才会落到插件快捷键表:
ctx.ui.registerShortcut({ id: "my-plugin.jump", combo: "Mod+Shift+D", run: () => ctx.ui.navigate("my-plugin.panel"),});主题(registerTheme)
Section titled “主题(registerTheme)”应用主题:注入 :root[data-theme="<id>"] { …vars },并出现在
「设置 → 外观」的主题卡片列表:
interface ThemeContribution { id: string; label: string; // 主题卡片上的显示名(纯文本,插件自行本地化) dark: boolean; // 暗色主题标记(终端回放等需要跟随 app 明暗) previewBg?: string; // 卡片预览色;缺省取 vars 里的 --bg / --fg previewFg?: string; vars: Record<string, string>;}vars的键必须是 CSS 自定义属性(--开头)。常用 token:--bg、--fg、--accent、--green、--red、--fg-dim等 (完整 token 表见宿主内置主题块)。- 键值会经消毒:键不允许
{}/;,值不允许{}/</style, 违规声明被静默丢弃(防止插件逃逸出规则块)。 - 插件被禁用时,宿主把当前主题回落到内置 dark(若正使用该插件主题)。
ctx.ui.registerTheme({ id: "my-plugin.night", label: "Night", dark: true, vars: { "--bg": "#101418", "--fg": "#d8dee9", "--accent": "#88c0d0" },});托盘项(registerTrayItem)
Section titled “托盘项(registerTrayItem)”系统托盘右键菜单的固定区条目(「新建本地终端」与「SSH 主机」子菜单之后),
点击时经 tray://plugin-item 事件分发回注册表触发 run:
ctx.ui.registerTrayItem({ id: "my-plugin.quick", label: "Quick Action", // 纯文本,插件自行本地化 run: () => { // … },});一个注册全部六类贡献点的最小插件:
import { definePlugin } from "@termii/plugin-sdk";import React from "react";import { Package, Zap, Settings, Sun, Cloud } from "lucide-react";
export default definePlugin({ manifest: { id: "my-plugin", name: "My Plugin", version: "0.1.0", apiVersion: 3, contributes: { views: [{ id: "my-plugin.panel", labelKey: "panelTitle" }], commands: [{ id: "my-plugin.sayHi", title: "Say Hi" }], settingsSections: [{ id: "my-plugin.settings", labelKey: "settingsTitle" }], themes: [{ id: "my-plugin.night", label: "Night" }], trayItems: [{ id: "my-plugin.quick", label: "Quick Action" }], }, }, activate(ctx) { ctx.i18n.addBundle("zh-CN", "ignored", { panelTitle: "我的面板", settingsTitle: "我的设置", });
ctx.ui.registerView({ id: "my-plugin.panel", icon: Package, labelKey: "panelTitle", component: () => <div className="view-body">面板内容</div>, });
ctx.ui.registerCommand({ id: "my-plugin.sayHi", group: "My Plugin", title: "Say Hi", icon: Zap, run: () => ctx.ui.toast.success({ title: "Hi!" }), });
ctx.ui.registerSettingsSection({ id: "my-plugin.settings", icon: Settings, labelKey: "settingsTitle", component: () => <div>设置内容</div>, });
ctx.ui.registerShortcut({ id: "my-plugin.jump", combo: "Mod+Shift+D", run: () => ctx.ui.navigate("my-plugin.panel"), });
ctx.ui.registerTheme({ id: "my-plugin.night", label: "Night", dark: true, vars: { "--bg": "#101418", "--fg": "#d8dee9", "--accent": "#88c0d0" }, });
ctx.ui.registerTrayItem({ id: "my-plugin.quick", label: "Quick Action", run: () => ctx.ui.toast.info({ title: "Quick Action" }), }); },});