STerminal —— 跨平台桌面终端管理工具
SSH / SFTP / 本地终端 / 端口转发 / 命令片段 一体化桌面客户端,自带端到端加密的开源云同步。
Electron Vue TypeScript xterm.js ssh libsodium Express SQLite

STerminal
一个我自己每天上班都在用的终端工具。
为什么自己做
终端 / SSH 客户端这个赛道现成产品很多 —— iTerm2 / Warp / Tabby / Termius / Royal TSX。 用了一圈下来,每个都有让我别扭的地方:
- iTerm2: 只是个 emulator,不管 SSH 主机管理。配置散在
~/.ssh/config里手敲,再加一堆 alias - Warp: AI 体验做得不错,但订阅制 + 远程协作要付费 + 历史数据进云端,对生产环境用着心里发毛
- Termius: 跨平台齐全但订阅制,云同步是闭源 SaaS,密码 / 密钥指纹 / 内部主机名全交给服务器
- Tabby: 开源功能堆满,但插件依赖大、UI 老
- Royal TSX: 老牌稳,UI 陈旧
我想要的就一句话:跨平台 + 一体化 + UI 现代 + 云同步 E2EE 且服务器开源可自建。 没有现成的,那就自己做。
一些可能值得讲的设计
环境感知边框
主机配置里加了一个 environment 字段(dev / staging / production)。
xterm 容器外层根据这个值上色 —— 生产服务器是红边、staging 黄边、本地默认绿。
动机直白:每个运维都被「我以为我在测试机,其实在生产」咬过。 那个瞬间不是缺信息(标签页上写着主机名)—— 是注意力被命令吃掉了,没扫到。 颜色比文字截留得住眼神。
实现是个 <div class="terminal-frame" :class="env">,CSS variables 切一下就完事,
工作量两小时。但救你一次就能值回票价。
会话录制 + GIF 导出
xterm 的 onData 钩子写 asciicast v2 NDJSON。回放时按 timestamp 重放(带倍速 0.5x-10x、
进度条、跳转)。最有用的是 一键导出 GIF(带 STerminal 水印)。
用途三个:
- 写文档 —— 命令演示比截图直观,比录屏体积小一个数量级
- 报 bug —— 把"我做了什么导致它崩了"丢出来比文字描述快十倍
- 教徒弟 —— 一段 SSH 操作录下来,新人自己回放就行
asciicast 文件本质是文本,可搜可 diff,理论上可以接 git。
E2EE 云同步
终端配置里有什么?密码、密钥指纹、内部主机名 / 内网 IP、各种 SSH proxyjump 链路 —— 比邮件还敏感。服务器永远不该看到这些明文。
栈:libsodium-wrappers-sumo,Argon2id 从用户密码派生密钥,XSalsa20-Poly1305 加密 payload。
服务器(packages/server)只看得到密文 + 元数据(时间戳、版本号),即便我自己拿数据库
也解不了密。
同步范围:主机配置 / 命令片段 / 设置 / 端口转发 / SSH 密钥 / Vault 密钥库 / 主题 / 快捷键。增量推送、乐观锁、冲突走 Last-Write-Wins。
服务器是独立 npm 包(Express + SQLite + WebSocket + JWT),完全开源, 带 Dockerfile 和 docker-compose。可以选官方云,也可以自己 docker compose up 一台。 这是跟所有商业产品的根本区别。
命令片段变量占位符
${name} / ${name:default} / ${name:A|B|C} / ${!password}(最后一个会遮蔽显示)。
内置 ${date} / ${time} / ${timestamp}。
例子:
kubectl logs ${pod:my-app-pod} -n ${namespace:default} --tail=${lines:100} -f
双击片段,弹一个变量填写对话框(实时预览、密码遮蔽、值记忆)。一键执行到当前终端。
比 alias 灵活(alias 不能交互式填参),比 chezmoi 轻(不用同步整个 dotfiles), 比 Notion 收藏命令快(不用切换上下文复制粘贴)。
CLI 工具
设置页一键把 sterminal 命令安装到 PATH。然后:
sterminal ssh prod-server
直接拉起 GUI 客户端连到 prod-server(这是你在 GUI 里配过的主机名)。
桌面应用 + CLI 共享同一份配置 —— 你既不用在 ~/.ssh/config 里手敲,
也不用每次切到 GUI 找。
这个细节大部分桌面工具不做,因为做了 GUI 就懒得管 CLI 了。但实际上很多操作场景是
先在终端(git push 完想跑个 deploy),切换到 GUI 反而打断节奏。
工程一瞥
sterminal/
├── packages/
│ ├── client/ # Electron 桌面客户端
│ │ └── src/
│ │ ├── main/ # 主进程:IPC / PTY / SSH / DB / 审计 / 更新 / 托盘
│ │ ├── preload/ # contextBridge
│ │ ├── renderer/ # Vue 渲染进程
│ │ └── shared/
│ └── server/ # 同步服务后端(独立可自托管)
│ └── src/
│ ├── controllers/ services/ middleware/ routes/ validators/
│ ├── websocket/
│ └── database/
├── .github/workflows/
│ ├── build.yml # CI: typecheck (vue + main) + 客户端/服务端测试 + 三平台构建
│ └── release.yml # 发布: tag 触发 → Electron 安装包 + Docker 镜像 (GHCR)
└── docs/ PRD.md ARCHITECTURE.md PROGRESS.md
- 测试:274 个 Vitest(happy-dom + better-sqlite3 内存数据库)。覆盖 SSH 连接逻辑、 片段变量解析、加密管线、API endpoint
- CI/CD:GitHub Actions 三平台并行构建(macOS .dmg / Windows .exe / Linux .AppImage)。 tag push 触发 release workflow,自动发包 + 推 GHCR 镜像
- 代码量:TS 584 KB + Vue 519 KB,monorepo 两个包
- i18n:简体 / English / 繁體,即时切换
- 平台适配:macOS 交通灯、Windows 标题栏覆盖、Linux 默认
还在做的
- Beta 收尾 —— 集中清剩下的边角 issue,然后准备 v1.0
- 多窗口 —— 当前一个进程一个窗口,想加一个"一窗多 workspace"模式
- 更精细的审计日志查询 —— 现在能 filter / 分页,但跨字段组合查询 UI 还粗糙
- 官方云同步服务器开服 —— 后端代码已经齐全,部署到 VPS 就行,但还在等 sterminal.app 域名
- AI 辅助层 —— 命令补全 / 错误诊断 / 自然语言转 shell 等。已在路线图里,但有几条原则: 本地模型优先(避免敏感命令进云端)、可一键关、不绑订阅、不抢操作流的主导权。 本质是"减少敲第二遍命令"的体力活,不是替你决策
没做 / 不打算做的
| 没做 | 原因 |
|---|---|
| 插件市场 | 插件生态会反过来限制核心功能演进 —— Tabby 走过这路,再不想踩 |
| 内置 K8s / Docker UI | 那是另一个产品的范畴。要管容器装 Lens / OpenLens / k9s 体验更好 |
| Web 版 | xterm.js 在 web 跑没问题,但本地 PTY / 文件系统是核心,web 版会是阉割品 |
链接
- 源码:github.com/ssssmy/sterminal
- Releases:github.com/ssssmy/sterminal/releases
- 文档:仓库
docs/PRD.md/docs/ARCHITECTURE.md/docs/PROGRESS.md
—— 用着不顺手的地方欢迎提 issue,最快的反馈通道。