我一直觉得,菜单栏应用最适合做两类事情:把经常用的小功能放在手边,以及替自己照看那些需要长期运行的任务。于是我做了 OmniPilot——一个常驻 macOS 菜单栏的个人助手。
它不是想取代某个成熟工具,也不打算做成什么都管的“大杂烩”。OmniPilot 只收纳那些确实贴合我自己日常习惯的功能。目前,它主要做两件事:管理 SSH 隧道,以及保存文本剪贴板历史。
从 SSH 隧道开始
我在 ~/.ssh/config 里已经配置好了服务器和端口转发,但每次开机、待机或网络切换之后,都需要手动启动隧道,还得留意连接有没有断。
OmniPilot 直接读取 SSH 配置,找出声明了 LocalForward 或 RemoteForward 或 DynamicForward 的 Host,并为每个 Host 启动一个 ssh -N <alias> 进程。隧道意外退出时,应用会按 1、2、5、10、30 秒的间隔自动重连;连续失败则通过系统通知提醒我。整个过程不修改 SSH 配置,也不接管密钥或认证,仍然使用系统已有的 ssh-agent。
这种设计的好处是,连接信息仍由 OpenSSH 管理,OmniPilot 只负责“启动、监督和展示状态”。菜单栏里可以查看每条隧道及其转发信息,也可以单独或批量启停。
再加一个常见的小功能
剪贴板历史是我后来加入的第二个功能。它每 0.8 秒检查一次系统剪贴板的变化,只有内容变化时才读取,并且当前只保存文本。
菜单栏面板里可以查看历史、删除单条记录,或清空全部内容。历史条数可以选择 10、20、30、50 或 100 条,默认 30 条。点击一条历史记录会把文本写回系统剪贴板,之后我可以在目标应用里按 ⌘V 粘贴;它不会替我模拟键盘输入。
剪贴板内容保存在 ~/Library/Application Support/OmniPilot/clipboard-history.json,条数设置则通过 UserDefaults 保存。历史文件是普通 JSON,没有加密,所以它可能包含敏感文本;应用会过滤常见的隐藏、临时和密码管理器标记,并提供单条删除和清空操作,但这不等于安全存储。
菜单栏之外的代码结构
这个项目是我学习 Xcode 和 Swift 开发时逐步搭起来的。代码按“应用外壳”和“可测试的核心逻辑”分成两层:
Sources/OmniPilot是 macOS App 本身,放菜单栏界面、剪贴板监控、通知和登录项等系统集成。Packages/OmniPilotKit是本地 Swift Package,放 SSH 配置解析、隧道进程管理,以及剪贴板历史模型和持久化逻辑。project.yml描述 Xcode 工程,由 XcodeGen 生成OmniPilot.xcodeproj。
把逻辑放进 Swift Package 的一个直接收益是可以独立测试。例如剪贴板历史的去重、条数限制、持久化和清空行为,都可以通过 swift test 验证,不需要启动菜单栏界面。
构建和试用
项目面向 Apple Silicon,最低支持 macOS 13。安装 Xcode 和 XcodeGen 后,可以这样构建:
brew install xcodegen
Scripts/build-app.sh
open build/OmniPilot.app
运行核心逻辑测试:
cd Packages/OmniPilotKit
swift test
应用日志写入 ~/Library/Logs/OmniPilot/omnipilot.log。打包脚本支持生成 zip 或 dmg;更完整的签名、公证和 Gatekeeper 说明可以查看 Docs/distribution.md。
一个只为自己服务的小工具
OmniPilot 的方向不是“菜单栏里还能塞什么”,而是“我自己的工作流里,有什么值得放到这里”。它不试图替代其他成熟,常见的菜单栏应用,也不追求功能数量;它只把 SSH 隧道和剪贴板历史这类我确实需要的东西,放到一个随手可用的位置。
后续要不要增加新功能,我也会沿用同一个标准:只有它能解决我自己的真实麻烦,且具备个性化的需求,才值得进入 OmniPilot。
发表评论