跳转到内容

下载 Termii · v0.4.5

三分钟,装进你的 Dock

原生构建,包体仅数 MB。应用内自动更新,始终新鲜。

安装说明

macOS:若提示「无法打开」,在终端执行 xattr -dr com.apple.quarantine /Applications/Termii.app。Windows:首次运行可能触发 SmartScreen,选择「仍要运行」即可。

SDK 与打包脚手架

@termii/plugin-sdk 是插件系统的 官方 SDK(独立仓库,不发 npm,经 git 依赖安装)。给插件作者提供:

  • 宿主 API 类型面(PluginContext / PluginManifest / 各贡献点与数据结构类型)
  • definePlugin() —— 类型收窄与入口约定
  • validateManifest() —— 清单校验(手写,零依赖)
  • termii-plugin-sdk —— esbuild 打包脚手架(单文件 ESM 产物,共享宿主 React / lucide)

在插件项目内安装(git 依赖;prepare 自动构建 dist/,dist 也已提交 进仓库双保险):

Terminal window
npm i -D github:Termii-App/plugin-sdk

插件代码里引用:

import { definePlugin, validateManifest, type PluginContext } from "@termii/plugin-sdk";

SDK 不 import 宿主任何源码,独立可编译。类型面由宿主侧自动生成同步 (见下文「类型同步」):写插件时以 SDK 导出的类型为准,两者不应分叉。 当前 SDK 2.2.x 已包含 ctx.config / ctx.paths / ctx.vault 批量 / ctx.dialog.pickDirectory 等新 API 的类型。

definePlugin(plugin) 原样返回插件对象,不做任何运行时包装;作用是 类型收窄——让 TypeScript 以 PluginContext 为上下文检查 activate(ctx) 的实现,并作为打包脚手架 / loader 的入口约定:

import { definePlugin, type PluginContext } from "@termii/plugin-sdk";
export default definePlugin({
manifest: {
id: "my-plugin",
name: "My Plugin",
version: "0.1.0",
apiVersion: 3, // 缺省按 1 处理;> 宿主支持版本会被 loader 拒绝
capabilities: ["process"], // L1:信任弹窗会列出并警示
},
activate(ctx: PluginContext) {
// …注册贡献点、订阅事件……
},
deactivate() {
// 可选:额外的清理(定时器、自建的连接等)
},
});

.jsx 模板(官方模板的 hello/)只用运行时导入 import { definePlugin } from "@termii/plugin-sdk"——esbuild 的 JSX 解析 不支持 TS 语法;.tsx 模板里再补 import type 即可获得完整类型上下文。

手写清单校验(零依赖,不引入 zod)。错误为中文、逐条收集; ok: true 时返回规范化后的 manifest(apiVersion 缺省已按 1 填入):

import { validateManifest } from "@termii/plugin-sdk";
const result = validateManifest(raw);
if (result.ok) {
// result.manifest:可直接使用的 PluginManifest
} else {
console.error(result.errors.join("\n"));
}

校验规则见 plugin.json 规范 → 校验,字段参考见 manifest schema 参考。

Terminal window
npx termii-plugin-sdk build src/main.jsx --outfile main.js --minify
  • 产物是单文件 ES module(--format=esm);.js 文件按 JSX 解析。
  • --minify 压缩产物;--external <name> 可重复传,把指定包 external 化 (不打包、不 alias 到 shim);--help 查看完整用法。
  • esbuild 缺失时脚手架给出友好报错(先在插件项目 npm install)。

宿主通过 window.__termii.shared 暴露共享的 React / ReactDOM / lucide。 打包脚手架默认把 react、react/jsx-runtime、react-dom、lucide-react alias 到 SDK 包的 shims/(运行时从共享实例取),并把 @termii/plugin-sdk alias 到 SDK 包的 src/index.ts——否则每个插件都会各自打包一份 React (上下文冲突、体积膨胀):

Terminal window
# 等价于 plugin-template 的 hello/build.sh
npx termii-plugin-sdk build src/main.jsx --outfile main.js --minify
  • 传 --external react --external lucide-react 会把共享包改回 external; --external @termii/plugin-sdk 同理。
  • i18next / react-i18next 不提供 shim,必须自带:SDK 主入口会引用 共享 i18n 运行时,因此插件项目构建前需要 npm i i18next react-i18next (官方插件 termii-docker 的 src/i18n.ts 即此模式:副作用 import 初始化插件自身的 i18n 实例)。模板项目已在 package.json 内置。
  • 其余第三方依赖同理,打包进 main.js 即可。

插件目录根放 main.css 时,宿主读取主脚本时会把它的内容一并返回并注入 一个 <style data-plugin-css> 节点;插件去激活 / 卸载时该节点被移除。 样式只作用于插件自身视图(可结合宿主暴露的主题 CSS 变量,见 贡献点 → 主题)。

SDK 的 host-types.ts 自动生成,勿手改:由宿主主仓库 scripts/gen-sdk-types.mjs 从 src/lib/plugins/types.ts + src/lib/types.ts(镜像类型段)生成,经 sync-sdk-types CD(main push) 自动推送到 SDK 仓库;SDK 的 index.ts 以 export * 全部转发。

  • 插件作者直接消费自动生成的类型,无需手工同步。
  • 若发现 SDK 与宿主签名分叉,以宿主实现为准,并检查同步流程 (本地可手动跑 node scripts/gen-sdk-types.mjs 生成对照)。

不想从零搭工程?直接以 plugin-template 为起点:hello/ 是纯 JS 入门模板,sidecar-sysinfo/ 是原生能力模板。 见 快速开始。