首页
/ Tabby 技术指南:终端、SSH 与串口控制台一体化客户端的架构与实战

Tabby 技术指南:终端、SSH 与串口控制台一体化客户端的架构与实战

2026-09-04 12:18:20作者:伍希望

Tabby(曾用名 Terminus)是一款基于 Electron + Angular + TypeScript 构建的跨平台终端模拟、SSH/Telnet 客户端与串口控制台工具,覆盖 Windows、macOS 与 Linux。本文以仓库内的日文版 README(README.ja-JP.md)为骨架,结合 tabby-coretabby-sshtabby-serialtabby-terminal 等插件包的源码,逐项解析其功能实现,帮助你掌握 Tabby 的安装配置、插件机制与二次开发要点。

什么是 Tabby:定位与能力总览

Tabby 是一个高度可定制的终端模拟器 + 连接管理器,官方 README 将其明确定位为 Windows 自带终端(conhost)、PowerShell ISE、PuTTY、macOS 的 Terminal.app 以及 iTerm 的替代方案。README 同时给出了清晰的“不是什么”的边界说明:

  • 不是新的 shell,也不是 MinGW / Cygwin 的替代品;
  • 不追求轻量。如果你更重视 RAM 占用,官方建议使用 Conemu 或 Alacritty 之类的轻量工具。

README 列出的核心能力清单(完整继承自 README.ja-JP.md,并标注了对应的仓库实现位置):

能力 说明 仓库中的实现位置
SSH / Telnet 客户端与连接管理器 内置连接管理器、known hosts、X11/端口转发 tabby-ssh/src/sessiontabby-telnet/src/session.ts
串口控制台 串口参数配置、自动重连 tabby-serial/src/api.ts
主题与配色自定义 内置 + 社区配色方案 tabby-core/src/services/themes.service.ts
自由快捷键定制 支持多键组合 tabby-core/src/hotkeys.ts
分屏(Split Panes) 可嵌套的分割面板 tabby-core/src/components/splitTab.component.ts
标签页保存(工作区恢复) 关闭后可恢复上次会话 tabby-core/src/services/tabRecovery.service.ts
Windows 多 shell 支持 PowerShell / PS Core / WSL / Git-Bash / Cygwin / MSYS2 / Cmder / CMD tabby-electron/src/shells
Zmodem 文件传输 SSH 会话内直接传文件 tabby-terminal/src/features/zmodem.ts
全角字符 Unicode 完整支持 基于 UTF-8 分片的流处理 tabby-core/src/utfSplitter.ts
Windows 下 Tab 补全(Clink) 附带 Clink 发行版 extras/clink
加密 Vault 存储 SSH 密码等机密 tabby-core/src/services/vault.service.ts
Web 版 SSH/SFTP/Telnet 可作 Web 应用运行,支持自托管 web/entry.tstabby-web/src/index.ts

Tabby 终端界面截图,展示分屏与终端功能

获取与安装

README 提供了三种获取途径(仓库只读环境下,你只需要知晓各自适用场景即可):

  1. 最新稳定发布版:从官方 Releases 渠道下载对应平台的安装包;
  2. 包管理器仓库:官方托管了 Debian/Ubuntu(deb)与 RPM 系(rpm)两种软件源,适合 Linux 用户以 apt/yum/dnf 方式安装;
  3. Nightly 开发构建:基于主干自动构建,适合尝鲜新特性。

此外 snap/snapcraft.yaml 表明项目同时提供 Snap 打包描述。发布后的自动更新由 tabby-electron/src/services/updater.service.ts 配合 app/dev-app-update.yml 实现。

多语言支持也是 Tabby 的一大特色:locale 目录下有 20 余种语言的 .po 翻译文件(含 locale/ja-JP.polocale/zh-CN.po),README 本身也有英文、中文、日文等十余个版本(README.mdREADME.zh-CN.mdREADME.ja-JP.md 等),翻译流程通过 Crowdin 管理(见 package.json 中的 i18n:pull / i18n:push 脚本)。

终端功能

分屏、标签页与自由布局

终端标签页由 tabby-terminal 插件提供,窗口内可自由放置标签页,并支持任意层级嵌套的分屏:分割面板的布局、拖拽与尺寸分配在 tabby-core/src/components/splitTab.component.tssplitTabDropZone.component.ts 中实现,配合 tabby-core/src/services/docking.service.ts 提供的停靠基类完成窗口管理。标签页关闭后的恢复能力由 tabRecovery.service.tstabRecovery API 提供,各插件(local、ssh、serial 等)通过注册 recoveryProvider(如 tabby-serial/src/recoveryProvider.ts)来序列化各自会话。

Quake 控制台(全局热键呼出的停靠窗口)

README 提到“全局热键唤出的 Quake 风格控制台”,其实现是 tabby-electron/src/services/docking.service.ts 中的 dock() 方法。从源码可以读出完整的配置驱动逻辑:

  • config.store.appearance.dock 取值为 off / left / right / top / bottom,为 off 时仅关闭置顶(见 L26-L32);
  • dockFill(0–1,窗口沿主方向的占比)与 dockSpace(0–1,垂直方向占比)决定停靠窗口大小(L43-L68);
  • dockAlwaysOnTop 控制是否始终置顶,dockScreen 指定目标显示器;
  • 屏幕分辨率/显示器变化时(screensChanged$ 与 IPC 的 host:displays-changed 事件)会自动重定位窗口,避免窗口“丢失”到屏幕外(L95-L105)。

输入处理、进度检测与 Unicode

输入方向(键盘 → 会话)经过一条中间件链,Backspace 行为是可配置的——tabby-terminal/src/middleware/inputProcessing.ts 将按键 0x7f 根据 profile 选项转换为四种协议之一:ctrl-h\x08)、ctrl-?\x7f)、delete\x1b[3~)或默认 backspace。这类选项在 SSH 与串口 profile 中均可单独设置。

输出方向(会话 → 终端)则由 tabby-terminal/src/middleware/streamProcessing.tsoscProcessing.ts 处理:前者负责换行码转换等流级处理,后者解析 OSC 转义序列,实现进度条/进度检测进程结束通知(通知由 tabby-core/src/services/notifications.service.ts 发出)。

全角/宽字符的“不卡死”关键在 UTF-8 分片:多字节字符跨越 chunk 边界时直接切割会导致乱码,Tabby 用 UTF8SplitterMiddleware(算法核心见 tabby-core/src/utfSplitter.tsapp/lib/utfSplitter.ts)保证跨块字符被完整缓存后再输出。粘贴方向同样经过防护:配置支持 bracketed paste 与多行粘贴告警,防止多行脚本被意外整体执行。

Shell 选择与 Clink

Windows 上的 shell 适配集中在 tabby-electron/src/shells 目录:每个文件对应一种 shell 探测与启动逻辑,如 powershellCore.tswsl.tsgitBash.tscmder.tsmsys2.tswindowsBase.ts 等;本地终端会话的完整实现在 tabby-local/src/session.ts

Windows 下经典的 CMD 体验(Tab 键补全、路径跳转)依赖 Clink:仓库在 extras/clink 内置了完整 Clink 发行版(clink_x64.execlink_dll_*.dll、默认 inputrc 等),并附带 Windows 提权辅助程序 extras/UAC.exetabby-uactabby-electron/src/services/uac.service.ts 负责调用它)。

SSH 客户端

Tabby SSH 客户端截图,展示连接管理器与 SFTP 面板

SSH 能力由 tabby-ssh 插件包实现,README 列出的能力与源码对应关系如下:

X11 转发与端口转发

X11 转发的底层是 tabby-ssh/src/session/x11.ts 中的 X11Socket.resolveDisplaySpec(),这段代码值得细读(L8-L38):

let [_, xHost, xDisplay] = /^(.+):(\d+)(?:.(\d+))$/.exec(spec ?? process.env.DISPLAY ?? 'localhost:0')
// Windows 走 TCP localhost,POSIX 默认走 unix socket
xHost ??= process.platform === 'win32' ? 'localhost' : 'unix'
const port = display < 100 ? display + 6000 : display   // :0 → 6000
if (xHost === 'unix') {
    xHost = `/tmp/.X11-unix/X${display}`              // 形如 /tmp/.X11-unix/X0
}

即:解析 host:display.screen 形式的 DISPLAY 规格,显示号小于 100 时映射为 6000 + display 端口;POSIX 上优先连接 Unix Domain Socket,Windows 上退化为 localhost TCP 连接。

端口转发的会话级实现在 tabby-ssh/src/session/forwards.ts,图形化配置界面为 sshPortForwardingConfig.component.tssshPortForwardingModal.component.ts。此外 README 提到的**自动跳板机(jump host)**管理与 agent 转发(含 Pageant 和 Windows 系统 OpenSSH agent)也在 tabby-ssh/src/config.ts 的 profile 选项与 tabby-ssh/src/session/ssh.ts 的连接参数中体现。

SFTP 与 Zmodem 文件传输

SSH 会话内可直接打开 SFTP 标签进行文件浏览、上传下载、建目录与删除,组件位于 tabby-ssh/src/components/sftpPanel.component.tssession/sftp.ts,菜单扩展点为 tabby-ssh/src/sftpContextMenu.tstabby-electron/src/sftpContextMenu.ts

Zmodem 则用于传统 SSH 会话的 sz/rz 直传,实现在 tabby-terminal/src/features/zmodem.ts(依赖社区 zmodem.js 库,仓库对其打了补丁,见 tabby-terminal/patches/zmodem.js+0.1.10.patch),文件传输的统一 UI 在 tabby-core/src/components/transfersMenu.component.ts

串口控制台

tabby-serial 插件提供串口会话。README 列出的能力——连接保存、行模式输入、十六进制字节输入与十六进制 dump 输出、换行转换、自动重连——分别在 serialTab.component.ts(行模式/十六进制 UI 与自动重连)和 serialProfileSettings.component.ts(参数编辑界面)中落地。

串口参数在 tabby-serial/src/api.ts 中定义得非常精确,可直接对照配置:

export interface SerialProfileOptions extends StreamProcessingOptions, LoginScriptsOptions {
    port: string          // 串口设备路径,留空则默认取枚举到的第一个端口
    baudrate: number|null // 可用速率见 BAUD_RATES:110 ~ 1500000
    databits: 5 | 6 | 7 | 8
    stopbits: 1 | 1.5 | 2
    parity: string
    rtscts: boolean        // 硬件流控
    xon: boolean           // 软件流控
    xoff: boolean
    xany: boolean
    slowSend: boolean      // 逐字节慢速发送,适配无缓冲 MCU
    input: InputProcessingOptions  // 与终端共用 backspace 协议选项
}
export const BAUD_RATES = [
    110, 150, 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600, 1500000,
]

从源码结构看,SerialSessiontabby-serial/src/api.ts)复用了与 SSH/本地终端同一条中间件链TerminalStreamProcessor(流处理/换行转换)→ 可选的 SlowFeedMiddleware(slowSend 时把输入拆成单字节逐个发送)→ UTF8SplitterMiddlewareInputProcessorLoginScriptProcessor。串口绑定探测由 tabby-serial/src/services/serial.service.ts 完成,原生依赖 @serialport/stream(仓库对 serialport 的 C++ 绑定打了平台适配补丁 app/patches/@serialport+bindings-cpp+11.0.3.patch)。端口打开后,readable 事件驱动 emitOutput,异常时通过 NotificationsService 报错并销毁会话(api.ts L98-L119)。

便携(Portable)模式

README 说明:“在 Windows 上,只要在与 Tabby.exe 相同的位置创建 data 文件夹,Tabby 就会以便携应用方式运行。”这段简短描述背后的实现只有 11 行代码,位于 app/lib/portable.ts

const appPath = path.dirname(electron.app.getPath('exe'))
const portableData = path.join(appPath, 'data')
if (fs.existsSync(portableData)) {
    console.log('reset user data to ' + portableData)
    electron.app.setPath('userData', portableData)
}

即:程序启动时检查 exe 同级目录是否存在 data 文件夹,若存在则将 Electron 的 userData 路径整体重定向过去——所有配置、profile、插件都随之落在便携目录内,实现“U 盘携带、即插即用”。

Web 版与自托管

README 指出 SSH、SFTP、Telnet 客户端可以 Web 应用形式运行并支持自托管。仓库中对应两部分:web/ 是 Web 应用的构建入口(web/entry.tsweb/entry.preload.tswebpack.config.mjs),tabby-web 插件包提供 Web 平台的差异实现(platform.tssrc/config.ts)。tabby-web-demo 则演示了用 v86 虚拟 x86 机器在浏览器里跑 BIOS/Linux ISO 的玩法(tabby-web-demo/data/linux.isosession.ts)。

插件机制

加载与发现

README 提到“插件和主题可直接从 Tabby 的设置界面内安装”。安装入口在 tabby-plugin-manager 插件:界面为 pluginsSettingsTab.component.ts,从 NPM 检索并安装插件的逻辑在 tabby-plugin-manager/src/services/pluginManager.service.ts,而主进程侧的插件目录扫描与加载实现在 app/lib/pluginManager.tsHACKING.md 说明了加载规则:

  • 开发模式下加载源码 checkout 中的所有插件,运行时始终加载用户插件目录(设置 → 插件 → “Open Plugins Directory”)以及 TABBY_PLUGINS 环境变量指定的目录;
  • 只有 package.json 中带有 tabby-plugin 关键字的模块才会被加载
  • 在插件目录内可用 TABBY_PLUGINS=$(pwd) tabby --debug 启动调试;
  • 发布到 NPM 时带上 tabby-plugin 关键字,即可出现在插件管理器中。

插件编写要点

HACKING.md 可见,一个 Tabby 插件的标准目录结构为:

tabby-pluginname
├─ src
|  ├─ components        # Angular 组件(.ts / .scss / .pug 三件套)
|  ├─ services          # Angular 服务
|  ├─ api.ts            # 对外导出的公共 API
|  └─ index.ts          # 模块入口(默认导出 NgModule)
├─ package.json
├─ tsconfig.json
└─ webpack.config.js

插件通过 Angular 依赖注入向应用“供给”能力,HACKING.md 给出的工具栏按钮示例(ToolbarButtonProvider + multi: true provider)即是最小的可运行骨架;各包的扩展点清单可参考 tabby-core/src/apitabby-settings/src/api.tstabby-local/src/api.tstabby-terminal/src/api 目录。仓库内的 tabby-auto-sudo-password 是一个完整的插件范例(含 decorator.tsindex.ts)。

README 推荐的第三方插件

日文 README 列出的插件均对应独立仓库(此处只保留名称与用途,链接见原文档):

插件 用途
docker 连接 Docker 容器
title-control 在标签名前后插入/移除指定字符
quick-cmds 向一个或多个标签快速发送命令
save-output 保存终端输出到文件
sync-config 通过 Gist/Gitee 同步配置文件
clippy 官方示例插件(那个“讨厌的家伙”)
workspace-manager 按预设创建自定义工作区
search-in-browser 用默认浏览器打开终端中选中的文本
sftp-tab 类似 SecureCRT,在 SSH 连接中打开 SFTP 标签
web-auth-handler 应用内 Web 认证弹窗(主要面向 warpgate 的浏览器认证)
mcp-server 通过 MCP 客户端(Cursor、Windsurf 等)接入 AI 助手

主题与配色

从源码构建

以下流程完整继承自 HACKING.md。前置条件:Node.js 15+(仓库根 package.json 中使用 TypeScript 4.9、Angular 15、Electron 38、Webpack 5)与 Yarn。

# 1. 安装依赖
# macOS / Windows:
yarn

# Linux (Debian/Ubuntu 示例) 需先安装系统依赖:
sudo apt install libfontconfig-dev libsecret-1-dev libarchive-tools libnss3 libatk1.0-0 \
    libatk-bridge2.0-0 libgdk-pixbuf2.0-0 libgtk-3-0 libgbm1 cmake
yarn

# 注意:fork 场景下可能需要先拉取 tag:
git pull --tags upstream master

# 2. 构建与启动
yarn run build
yarn start        # 开发模式(TABBY_DEV=1,带 --inspect)

yarnpostinstall 会自动执行 patch-package(应用 app/patchespatches 下的补丁)、scripts/install-deps.mjs 与各插件的原生依赖构建。制作安装器的完整命令:

node scripts/prepackage-plugins.mjs
node scripts/build-windows.mjs   # 或 build-linux.mjs / build-macos.mjs

产物输出在 dist 目录。仓库的整体布局(app 是 Electron 壳,tabby-* 目录都是独立插件包)在 HACKING.md 中有目录树说明,实际目录与之一致并扩展了 tabby-settingstabby-serialtabby-sshtabby-telnet 等包。

参与贡献

项目欢迎 PR 与插件。贡献路径建议:

  1. 按上文完成本地构建与 yarn start
  2. 阅读 HACKING.md 的插件开发教程,扩展点见各插件包的 src/api 目录;
  3. 翻译贡献可基于 locale 目录下的 .po 文件进行,提取流程为 yarn i18n:extract(基于 scripts/i18n-extract.mjs);
  4. 提交前可用 yarn lint(eslint 覆盖各插件 srcapp/lib)检查代码规范。

小结

Tabby 的设计可以概括为“Electron 薄壳 + 插件即一切”:app 目录只负责启动、插件加载(app/lib/pluginManager.ts)、便携模式(app/lib/portable.ts)等基础设施,终端、SSH、Telnet、串口、设置、主题、插件管理全部是独立的 tabby-* Angular 插件包,通过 provider 注入互通。理解这条“profile → session → middleware 链 → 组件”的主线(以 tabby-terminal/src/session.tstabby-terminal/src/middleware 为核心),你就能基于仓库源码解释 Tabby 的每一项功能,也能快速上手开发自己的插件与主题。

登录后查看全文
热门项目推荐
相关项目推荐