插件服务总线与依赖
插件服务总线与依赖
Section titled “插件服务总线与依赖”插件之间的协作走服务总线(ctx.plugins),而不是互相 import 代码:
Snippets 之于 BatchTasks 这类「功能复用功能」的场景,调用方与被调方通过
注册表路由,彼此故障隔离。
服务总线(ctx.plugins)
Section titled “服务总线(ctx.plugins)”plugins: { expose(service: string, handler: (method: string, params: unknown) => unknown): Disposer; invoke<T>(pluginId: string, service: string, method: string, params?: unknown): Promise<T>; isActive(pluginId: string): boolean;}expose:注册本插件的一个服务。返回 Disposer,插件去激活时服务自动 摘除;同插件内服务名冲突时拒绝后注册者。invoke:只允许调用**已启用(active)**插件;目标插件未启用 / 未 expose 该服务 / 不存在 → reject 明确错误。被调方 handler 抛错 → reject (故障隔离,不中断调用方)。调用发起时会先等待启动加载收尾,消除 「插件存在但尚未加载」的启动竞态。isActive:目标插件当前是否已激活(同步返回,不触发加载)。可选依赖 探测专用。
// 提供方(termii-snippets 内部):暴露 "snippets" 服务ctx.plugins.expose("snippets", (method, params) => { if (method === "list") return listSnippets(); throw new Error(`unknown method: ${method}`);});
// 消费方(termii-batch 的现网写法):调用 snippets 的 list 方法const list = await ctx.plugins.invoke<SnippetSummary[]>( "termii-snippets", "snippets", "list");// SnippetSummary { id, name, group?, command, variables: string[] }// variables:命令模板里的 {{name}} 占位符名,保留首次出现顺序建议约定:method 用动词(list / get / save / run…),params
传 JSON 可序列化数据,错误一律 throw new Error(会带上调用方上下文
透传)。
依赖声明(dependencies / optionalDependencies)
Section titled “依赖声明(dependencies / optionalDependencies)”前置依赖(dependencies)
Section titled “前置依赖(dependencies)”在 plugin.json 里声明后,宿主按依赖拓扑序加载:先依赖、后使用方,
保证使用方 activate 时依赖已激活、服务可调。
{ "dependencies": ["termii-snippets"] }依赖不可达(未安装 / 未启用 / 未信任 / 加载失败 / 存在循环)时:
- 本插件跳过加载,跳过原因显示在「设置 → 插件」与加载日志中;
- 其余插件不受影响;启用时也会被宿主拦截并 toast 提示 「请先启用并信任:…」。
可选依赖(optionalDependencies)
Section titled “可选依赖(optionalDependencies)”{ "optionalDependencies": ["termii-tunnels"] }- 宿主只做「尽力序」:可选依赖在候选集内(已安装且已启用且已信任)时
优先于使用方加载(保证激活期即可用
isActive探测到)。 - 缺失 / 加载失败不跳过本插件——由插件运行时自检并降级:
if (ctx.plugins.isActive("termii-snippets")) { const list = await ctx.plugins.invoke("termii-snippets", "snippets", "list");} else { // 降级:隐藏「片段」来源}宿主内置的转发服务
Section titled “宿主内置的转发服务”宿主自身也会经服务总线转发部分能力,最典型的是 ctx.tunnels.saveRule:
它把规则保存转发给官方插件 termii-tunnels 的 "tunnels" 服务
(目标插件未启用时 reject):
await ctx.tunnels.saveRule(rule); // 新增或更新一条规则(只落库,不启动)实例:Snippets ↔ BatchTasks
Section titled “实例:Snippets ↔ BatchTasks”官方插件的真实协作:termii-snippets 暴露 "snippets" 服务,
termii-batch 声明 optionalDependencies: ["termii-snippets"],
激活时用 ctx.plugins.isActive 探测,可用则拉取片段列表作为批量任务的
命令来源。这是「功能复用功能」的参考实现。