当服务器从个位数长到几十台,原生 ssh 就开始不够用了:IP 记不住,密钥和密码混着用,某些机器登录完还得手动 sudo -i,换台 Mac 主机清单又得重新搬一遍。市面上的 SSH 客户端能解决一部分,但代价通常是把你的主机数据塞进它自己的私有数据库或者云同步格式——用得越久,越离不开它。
Wireline 是我最近在做的一款原生 macOS SSH 客户端,想解决的就是这件事,但坚持一个前提:不锁定用户。
一个别名,连接一切——但配置永远是你的
Wireline 的主机数据始终以标准 ~/.ssh/config 作为唯一数据源。图形界面只是这份标准配置之上的一层高效外壳,它自己需要的额外元数据(分组、描述、认证方式、是否自动提权)都以 # wireline: 注释行的形式写在同一个 Host 块里,原生 ssh 会正常忽略这些注释。
这意味着哪天你不用 Wireline 了,命令行的 ssh / scp / rsync、VS Code Remote,依然读的是同一份配置,一切照旧。
回写这份文件时也做了该做的事:原子写入、按时间戳留备份、权限强制 0600。密码类凭据只进 macOS Keychain,配置文件里只留一个 auth=password 的标记,绝不落明文。

它长什么样
界面刻意做成了终端黑客风——等宽字体、绿字黑底、可换主题——但底下是实打实的原生能力:
- 全局快捷连接(⌘K):Spotlight 式的模糊搜索,输入别名首字母回车即连,密钥/密码自动识别
- 内置真 PTY 终端(基于 SwiftTerm),不用再开外部 Terminal;密码主机通过 OpenSSH askpass 自动复用 Keychain 里的密码,可选登录后自动
sudo -i - 可视化 SFTP 浏览器(基于 Citadel):双栏、拖拽/双击传输、右键增删改
- 图形化端口转发:
ssh -L、走跳板机、一键启停 - 批量 / 舰队执行:框选一组主机,对它们并发跑同一条命令,聚合结果
- 加密备份与迁移:一键导出主机清单 + 密码为单个加密文件(PBKDF2-SHA256 + AES-GCM),也能加密后传到 WebDAV,换 Mac 一次导入全部恢复
- App 级壁纸:静态图或循环 mp4,面板半透明浮在上面(离屏时暂停渲染)

真正不一样的地方:一个会动手的 AI 副驾
大多数工具的 AI 停在「帮你把自然语言翻译成命令」。Wireline 想再往前走一步——让 AI 真的能替你做事,但每一步都在你的掌控里。
在 设置 → AI 里填一个 OpenAI 兼容的 endpoint + key,或者直接指向本地 Ollama(数据不出本机)。终端旁边的 ✨ 按钮打开 AI 面板。它能做的事:
- 自然语言 → 命令:描述需求,拿到命令,
Insert或Run——但永远不会自动执行 - 诊断 / 解释 / 总结:分析终端输出、解释命令(带危险提示)、把超长日志压成结论
- Agent 模式:AI 跑一条命令 → 读输出 → 接着跑,直到得出结论;危险命令要确认,还有一个只读沙箱能拦掉所有写操作
- 舰队问答:选一批主机 + 一句话 → 并发执行 → AI 把结果汇总成一张表/一个结论
- 给 App 本身当副驾:建隧道、加主机、连接、开文件、跑 snippet,都带确认
- SFTP 上的 AI 改文件:右键远程文件 → 描述改动 → 预览 → 变更评审(影响面 + 风险) → 写回
- 每台主机的记忆:AI 记住关于每台机器的长期事实,后续回答时纳入考量
这里有一条我坚持的底线:

架构
两个 SwiftPM target,边界很清楚:
WirelineCore——纯 Swift、无 UI、可单测。负责解析/回写~/.ssh/config、Keychain 服务、ssh命令封装、端口转发管理、加密备份Wireline——SwiftUI app。各种@Observable的 Store、内置终端、actor 隔离的 SFTP、通过复用 ControlMaster 连接拿远端 CPU/内存指标、OpenAI 兼容的流式 AI 客户端、并发舰队执行
没有服务端,没有中心数据库,所有状态都在你本机。除了你自己配的那个 AI endpoint,没有任何网络回传;SSH 连接从你的机器直连目标。
关于「标准优先」
做这个项目最大的克制,是忍住不去发明自己的数据格式。私有数据库能带来更花哨的功能和更强的粘性,但那种粘性对用户不是好事。把 ~/.ssh/config 当唯一真相,意味着 Wireline 随时可以被卸载而不留痕迹——我觉得一个工具敢让你随时离开,你才会更放心地留下来。
代码在 GitHub 上,MIT 协议。要 Xcode 26+ / Swift 6.2(macOS 14+),./scripts/bundle.sh --run 就能跑起来。
还没有评论
欢迎留下你的观点,保持交流的清晰和友好。