跳转到内容

下载 Termii · v0.4.5

三分钟,装进你的 Dock

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

安装说明

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

终端 / 主机 / 文件传输

这一组 API 让插件与用户的工作区交互:读写终端、开终端 tab、在主机上执行 命令、传输文件、存取凭证。

ctx.terminal.getActivePane(): ActivePaneInfo | null;
// ActivePaneInfo { paneId: string; kind: "local" | "ssh" | "serial"; backendId: string }

返回当前活跃终端 pane 的只读投影;预览等非终端 pane 返回 null。

ctx.terminal.writeActive(text: string): Promise<boolean>;
ctx.terminal.writePane(paneId: string, text: string): Promise<boolean>;
  • writeActive:向活跃 pane 写入并聚焦。
  • writePane:向指定 pane 写入(pane 不在当前活跃 tab 也能写,宿主 会自动切换 tab 并聚焦,用户能看到注入的命令);pane 不存在或写入失败 返回 false。后端会话未就绪时会主动确保建立(与 attach 路径去重)。
ctx.terminal.onOutput(cb: (chunk: OutputChunk, pane: ActivePaneInfo) => void): Disposer;
// OutputChunk { seq: number; data: string }

订阅活跃 pane 的输出流,切换 pane 自动跟随;返回退订函数。

ctx.terminal.focusActive(): void;

一键连数据库、开运维会话、Docker exec 借道都从这里开终端 tab:

ctx.sessions.openLocalTab(): Promise<string | null>; // 新开本地终端 tab,返回 paneId
ctx.sessions.openHostTab(hostId: string): Promise<string | null>; // 新开指定主机的 SSH tab(自动确保连接在线)
ctx.sessions.focus(paneId: string): void; // 聚焦某个 pane

官方 Docker 插件「在终端中持续跟随」模式:开 tab 后向 pane 注入命令:

const paneId = await ctx.sessions.openLocalTab();
if (paneId) await ctx.terminal.writePane(paneId, `docker exec -it ${id} bash\n`);
ctx.hosts.list(): readonly HostSummary[];
// HostSummary { id, name, host, port, username, group?, tags: string[], favorite }
ctx.hosts.connect(hostId: string): Promise<string>; // 建立(或复用)SSH 连接,返回 sessionId
ctx.hosts.exec(hostId, command, opts?: { timeoutSecs? }): Promise<{ stdout; stderr; exitCode }>;
ctx.hosts.disconnect(hostId: string): Promise<void>;
ctx.hosts.reconnect(hostId: string): Promise<string>; // 重建 transport(复用现有配置),返回新 sessionId
ctx.hosts.execLocal(command: string, opts?: { timeoutSecs? }): Promise<{ stdout; stderr; exitCode }>;
ctx.hosts.execStream(hostId: string, command: string): Promise<ProcessHandle>; // L1 process

要点:

  • list() 返回的是只读投影,不含任何凭证字段。
  • exec / execLocal 是一次性的(等进程退出拿全部输出),撑不起日志 follow / 进度流——流式场景用 process.spawn / hosts.execStream(见 流式进程与 sidecar)。
  • execLocal 在宿主本机执行 shell 命令(临时 PTY 只收集 stdout, stderr 恒为空串);默认超时 60s。
  • execStream 需要 L1 process 能力(与 ctx.process.spawn 同一把信任锁)。
// 在指定主机上执行命令并展示结果
const res = await ctx.hosts.exec(hostId, "df -h /", { timeoutSecs: 15 });
if (res.exitCode === 0) {
ctx.ui.toast.success({ title: res.stdout.trim().split("\n").pop() });
} else {
ctx.ui.toast.error({ title: "执行失败", description: res.stderr });
}
// 在宿主本机执行
const local = await ctx.hosts.execLocal("uname -a", { timeoutSecs: 15 });
ctx.ui.toast.info({ title: local.stdout.trim() });

同步形态的文件传输投影:Promise 在传输真正完成 / 失败后才 settle, 内部使用主机的文件 SSH 会话(与 hosts.exec 的 terminal 会话分离, 互不干扰)。错误消息透传 sftp 命令的原始错误:

ctx.sftp.upload(hostId, localPath, remotePath, onProgress?): Promise<void>;
ctx.sftp.download(hostId, remotePath, localPath, onProgress?): Promise<void>;
// onProgress?: (p: { transferred: number; total: number }) => void
// total 在传输开始后可能为 0,表示总大小未知
await ctx.sftp.upload(hostId, localPath, remotePath, (p) => {
if (p.total > 0) console.log(`${Math.round((p.transferred / p.total) * 100)}%`);
});

keyring 投影(官方 Docker 插件的 registry 登录凭据用)。无能力门禁: vault 与 hosts / tunnels / sessions 同属核心服务投影,不参与 capabilities 声明(process / sidecar 才需要 L1):

ctx.vault.get(id: string): Promise<string | null>; // 不存在返回 null
ctx.vault.set(id: string, secret: string): Promise<void>; // 覆盖写入
ctx.vault.delete(id: string): Promise<void>; // 不存在时静默成功