终端与 Shell 会话
NetShuttle 不把终端绑定到单一界面。共享层使用 ShellSession 与 ShellSessionManager 管理远程 PTY,展示层根据平台选择外部终端或应用内终端。
Shell 生命周期
Section titled “Shell 生命周期”creating → running ←→ detached → closing → closed ↓ lost关闭终端窗口默认只执行 detach,远程 Shell 继续运行。只有用户明确结束会话、SSH 连接销毁或连接断开时,才会 destroy 对应 Shell。
一个 SSH 连接可以创建多个独立 Shell。ShellID 与 ConnectionID 分离,Bridge 和终端展示路由只依赖具体 ShellID。
macOS:外部终端 + TTY Bridge
Section titled “macOS:外部终端 + TTY Bridge”macOS 菜单栏中的「打开终端」会优先附加该连接最近 detached 的 Shell;没有可恢复会话时再创建新 Shell。
执行链如下:
- NetShuttle 启动当前终端的
NetShuttle.app/Contents/MacOS/NetShuttle tty <sessionID>。 - CLI 连接本地 Unix Domain Socket,并发送包含尺寸、
TERM和LANG的 HELLO。 - TTY Bridge 附加已有 Shell,或通过 SSH 引擎创建新的 PTY Channel。
- READY 返回 shellID 后,CLI 进入原始终端模式并开始双向转发。
- 终端尺寸变化通过
SIGWINCH转换为 RESIZE;关闭终端只 detach。
内置终端适配
Section titled “内置终端适配”| 终端 | 启动策略顺序 |
|---|---|
| Terminal.app | commandFile → appleScriptDoScript |
| iTerm2 | appleScriptWriteText → commandFile |
| Ghostty | appleScriptSurfaceCommand → commandFile |
应用还支持选择一个未知 .app。终端品牌与启动策略由内置 TerminalProfiles.json 描述,Swift 代码不包含品牌枚举。
READY 与回退
Section titled “READY 与回退”终端 App 启动成功不等于 Shell 已可交互。每个已提交策略最多等待 6 秒 READY;超时后按顺序回退。一个 Connection 同时只允许一条探测链,防止快速重复点击创建多个终端窗口。
iPhone / iPad:应用内终端
Section titled “iPhone / iPad:应用内终端”移动端不启动 TTY Bridge,也不经过 Unix Socket。MobileTerminalLauncher 直接附加 ShellSessionManager 中的 Shell,MobileTerminalView 使用 SwiftTerm 展示:
- 键盘输入写入 Shell。
- 远端输出显示在终端。
- 尺寸变化转发为 PTY resize。
- 页面消失时 detach,点击「结束会话」时 destroy。
移动端首版只保证前台会话。应用进入后台后系统可能暂停连接,不能把移动端当作常驻后台隧道或终端服务器。