快速开始
用官方模板 Termii-App/plugin-template 把第一个插件跑起来。整个过程只需要一条构建命令和一个安装动作。
- 已安装 Termii(任意较新版本,示例要求
≥ 0.3.6) - Node.js(
npm可用) - Git
1. 获取模板
Section titled “1. 获取模板”git clone https://github.com/Termii-App/plugin-template.gitcd plugin-templatenpm install # 安装 @termii/plugin-sdk(git 依赖,prepare 自动构建 dist)模板包含两个可运行示例:
| 目录 | 说明 |
|---|---|
hello/ |
入门模板:视图 + 命令 + 设置分区 + 快捷键,纯 JS(.jsx) |
sidecar-sysinfo/ |
原生能力模板:sidecar 二进制桥(macOS + python3) |
bash hello/build.sh# → 生成 hello/main.js(单文件 ES module,压缩后约几 KB)构建脚本内部等价于:
npx termii-plugin-sdk build src/main.jsx --outfile main.js --minify脚手架会把 react / lucide-react alias 到 SDK 的 shims(运行时从宿主
共享实例取),因此产物体积很小,且不会与宿主产生 React 上下文冲突。
打开 Termii:设置 → 插件 → 从磁盘安装,选择 hello/ 目录(包含
plugin.json 与 main.js 的那个目录)。
首次启用会弹出信任确认——hello 未声明任何 L1 能力(capabilities 缺省
为 []),属于纯 UI 插件,确认基础信任即可。
安装启用后:
- 侧栏出现「Hello 面板」视图(也可按 ⌘K 搜索 Hello)
- 面板上有「向活跃终端写入一行」按钮:打开一个终端 tab 后点击,
终端里会出现
echo "hello from plugin #N"的输出 - ⌘K 命令面板里出现
Say Hi命令 - 设置页出现插件的「Hello World」分区(里面有个开关)
- 按
Mod+Shift+H直接跳转到插件视图
模板源码结构
Section titled “模板源码结构”hello/├── build.sh # 构建 main.js├── plugin.json # 清单(id / name / version / apiVersion / contributes)└── src/ ├── main.jsx # definePlugin({ manifest, activate })——插件本体 └── manifest.js # 与 plugin.json 同步的 bundle 内 manifest两个要点:
src/manifest.js与plugin.json必须一致:loader 会校验 bundle 内manifest.id与插件目录名一致(防目录伪造),修改plugin.json时记得同步manifest.js。- 入口是
.jsx:esbuild 的 JSX 解析不支持 TS 语法,因此模板只 import 运行时definePlugin;TS 模板可再写import type { TermiiPlugin }获得完整类型上下文(见 SDK 与打包脚手架)。
示例插件做了什么
Section titled “示例插件做了什么”activate(ctx) 里注册了四类贡献点,是最小的完整示例:
import { definePlugin } from "@termii/plugin-sdk";import React from "react";import { Smile, Zap } from "lucide-react";import manifest from "./manifest.js";
function Panel({ ctx }) { const [count, setCount] = React.useState(() => ctx.storage.get("runCount", 0)); return ( <div className="view-body" style={{ padding: 24 }}> <button className="btn" onClick={async () => { const next = count + 1; setCount(next); ctx.storage.set("runCount", next); const ok = await ctx.terminal.writeActive(`echo "hello from plugin #${next}"\n`); if (!ok) { ctx.ui.toast.error({ title: "没有活跃的终端" }); } }} > 向活跃终端写入一行 </button> </div> );}
export default definePlugin({ manifest, activate(ctx) { ctx.ui.registerView({ id: "hello-world.panel", icon: Smile, labelKey: "panelTitle", ns: "plugin-hello-world", component: () => <Panel ctx={ctx} />, });
ctx.ui.registerCommand({ id: "hello-world.sayHi", group: "Hello World", title: "Say Hi", icon: Zap, run: () => ctx.ui.toast.info({ title: "Hi from hello-world" }), });
// …registerSettingsSection / registerShortcut / i18n.addBundle },});- 想搞清每个字段和每个 API 的细节?沿学习路径继续
- 需要原生能力(系统调用、新协议、重计算)?看
sidecar 原生能力桥
和模板的
sidecar-sysinfo/目录 - 直接开始写自己的插件?从 plugin.json 规范 开始