feat: 修复终端换行错乱根因 + 顶带重设计 + 移除移动端分屏

- 换行错乱根因:tmux 客户端格子改以 ghostty 实测为权威(像素除法
  偏大 1 行/列 → 远端按更宽排版、本地自动换行掉字符),单 pane 实测
  格子直发 refresh-client;kickoff 用 raw surface 真实格子;顶栏
  格子数 tmux 模式读 clientGrid(模拟器连本机 sshd 端到端验证)
- 顶带落地为真实 chrome 行:✕/⌄ 独立按钮组 + 弱化标题 +
  TmuxWindowTabGroup window tab 组,pane 不再被悬浮胶囊遮内容
- 放弃移动端分屏:删 SplitMenu/分屏入口,tmux window 切换上移顶部
  tab,侧边栏改列活动会话;底部动作条合并状态行
- Info.plist 补 NSLocalNetworkUsageDescription(LAN 直连必需,
  缺失时 socket 静默超时)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
kid
2026-07-26 11:11:20 +08:00
parent 5707d70dff
commit 5d1abdc7ac
13 changed files with 411 additions and 693 deletions

View File

@@ -162,7 +162,7 @@
| UI-1 | 设计令牌地基Nocturne chrome + blurple + JetBrains Mono | 完成 |
| UI-2 | 导航与多会话状态模型AppRouter/SessionManager/SessionCanvas | 完成 |
| UI-3 | 终端主界面56pt 轨道 + 浮起双胶囊 + 侧边栏三态 | 完成pane 缝拖拽待做 |
| UI-4 | 首页会话卡 + 关闭确认 + 分屏菜单 + pane 拖拽 | 完成pane 拖拽待真机 tmux 验证 |
| UI-4 | 首页会话卡 + 关闭确认 + 分屏菜单 + pane 拖拽 | 完成分屏功能后被用户裁决整体移除 12.3k |
| UI-5 | 设置·外观 + 键盘体系GCKeyboard 检测 + 全套 快捷键 | 待做 |
| UI-6 | 竖屏参数化 + iPhone 首版 | 待做 |
@@ -359,6 +359,38 @@
- **顺带修掉暴露的旧缺陷**:标题胶囊的格子数读 `screenGrid.value` 却从不刷新(旧注释"首次布局后稳定,不必 @Published"在"开合即 resize"下不成立,表现为开合后数字停在旧值)→ `GridBox``onGridChange`(去重)、`TerminalSession` 转发 `objectWillChange`。验证:展开 135×50 / 收起 164×50 实时跟随。
- 验证:展开动画 pane 左描边逐帧 58→198.5→261→290pteaseOut 先快后慢),无硬切;收起态 Logo 位为 »、底部只剩状态点/分割线/齿轮;展开态头部仅 Logo+名称+«。
### 12.3k 放弃移动端分屏 + tmux window Tab 上移 + 状态出口合并用户裁决2026-07-26
用户判词:全面放弃移动端的分屏**操作**非核心功能tmux 的切换从侧边栏移到顶部作 Tab**活动会话(主机连接)的切换仍在侧边栏**;右上状态文字移到左下并与既有文字**合并**(原两处信息重复)。
(第一版误把「会话列表」理解成主机连接列表上移为 Tab用户纠正 + AskUser 确认Tab = **tmux window**(与 tmux -CC「window 映射为原生 tab」惯例一致非 tmux session 切换——后者需 switch-client + 窗口全量重建,未做。)
**1. 删分屏(入口 + 逻辑)**
- UI 入口:底部动作条「竖分屏」按钮、分屏菜单 `SplitMenuView`12.3d 的 3b 卡片整个删除)、`AppModal.splitMenu`
- 逻辑:`TmuxController.splitWindow/splitIntoNewSession``list-sessions` 管线(`TmuxSessionInfo`/`sessions`/`listSessions()`/`PendingKind.listSessions`——只服务分屏菜单)、`TerminalSession.tmuxSessionList`/`injectedTmuxSessions`、fixture 的 `tmuxSessions()`、无头 URL `ui/split`/`ui/split-now`
- **保留**:多 pane 的**被动渲染**与 `PaneSplitter` 拖拽/`resizePane`(别的客户端建好的分屏 attach 进来仍须按 layout 正确显示)、`ui/resize/<cols>`
- 顺带修掉 `TmuxController` 响应 switch 里重复的 `case .currentSession`(死代码)。
**2. tmux window Tab`TmuxWindowTabsBar`TerminalChrome.swift**:顶带 = 左标题胶囊 + window Tab 条(右上状态胶囊撤销)。一个 window 一个浮起胶囊 tab编号徽标 + 标题),点击 `selectWindow`(链路复用旧侧边栏 window 行);当前 window accent 高亮controller 未 attach 但有 `tmuxSummary` 时按占位渲染fixture/接回前),原生窗口不显示。三层嵌套订阅各自拆视图(`WindowTabsRow` 订阅 controller、`WindowTab` 订阅 window——title/index 是 window 自己的 @Published)。侧边栏 tmux 段(`tmuxDivider`/`tmuxLabelRow`/`tmuxRows`/`SidebarWindowRow`/`WindowRowBody`/「新建 window」行删除「新建 window」入口保留在底部动作条侧边栏 = 首页 / **活动会话(保留,主机连接切换)** / 连接新主机 / tailnet / 设置,不再要 `session` 参数。
**3. 状态出口合并(`TerminalActionBar.statusLine`**:原右上三格分层徽标(`tsnet|mosh|tmux`)与原左下上下文文字合并为左下**唯一**状态行:`[dot 链路] | 传输(重连计数) | 会话概览(tmux 名 · N windows / 原生窗口 / 无 tmux / phaseText)`。主机名不再出现(标题胶囊与当前 tab 已有)。「只染出问题的那层”规则原样保留。
- 验证fixture 三会话截图对拍window tab 高亮/占位 tab/合并状态行/侧边栏两态排版含活动会话段)+ `ui/session/2` 切换 + 开合 resize 格子数跟随164×50⇄135×50。真机 tmux 下点 tab 切 window 待验证(链路与旧侧边栏 window 行相同)。
### 12.3l 顶带落地重设计:按钮分离 / 标题弱化 / tab 组用户定稿2026-07-26
用户判词按钮、title、tab 可以在终端**外**区域按钮分离出来单独悬浮标题弱化tab 要有「组」的概念。
- **浮起胶囊废除,顶带落地为真实 chrome 行**`TerminalTopBar` 替换 `TerminalTitleCapsule`+`FloatingCapsule``stage` 从 ZStack overlay 改回 VStack 首行,终端 pane 从带下方开始 —— 86pt 预留带(`TX.Layout.capsuleInset`已删令牌与「胶囊遮内容」问题一并消失。pane 顶边现在朝 chrometopLeading 收圆角、顶描边恢复(不再 `top:-1` 推出屏外右边仍贴屏幕物理边缘不收角。pane 内容留 `TX.Space.s` 呼吸位。
- **顶带层级(一眼一个主角)**`[✕ ⌄ 独立按钮组] · 弱化标题 · [tab 组]`。按钮升到 28pt 圆角方块自成一簇(危险操作与身份信息不共容器);标题降为纯文本行(状态点 5pt + 主机名 mono12 text2 + cwd textWeak + 格子数 textFaint**当前 window title 从标题里删掉** —— 它已由 tab 组选中 chip 承担写两遍是重复tab 组是顶带唯一带容器的元素。
- **tab 组(`TmuxWindowTabGroup`**surfaceDark 圆角槽radius 11内衬 3ptwindow 是槽内段式 chip选中 = selectedBg+描边浮起,未选 = 透明贴槽底),尾部 `+` 新建 window。**坑:槽体背景必须挂在 ScrollView 的内容层** —— 挂 ScrollView 自身就是一条拖到屏幕右边的空槽ScrollView 恒占满剩余宽度。占位态controller 未 attach 但有 tmuxSummary共用 chip 本体;原生窗口不渲染 tab 组。
- 验证fixture 截图 ×3tmux 态顶带 / 原生窗口态无 tab 组 / 展开侧边栏组合态),标题去重与槽体紧贴成组均确认。
### 12.3m 换行错乱根因修复:客户端格子的权威改为 ghostty 实测真机报障2026-07-26
用户报障:无论侧边栏收起/展开终端Claude Code 等全屏 TUI换行错乱、行首冒碎片竞品完美。
- **根因**(模拟器连本机 sshd 复现实锤):`containerResized` 用「容器px ÷ 整数cell px」算 tmux 客户端格子,复刻不了 ghostty 内部取整/内边距 —— 实测算得 **164×51**、ghostty 真实 **163×50**(列差来自 `TmuxPaneView` 的 1pt padding 圈,行差来自像素除法本身)。远端按 164 列排版、surface 按 163 列自动换行 → 每条满宽行掉字符,重绘积累成花屏。
- **修复**`TmuxController` + `ContentView` + `TerminalChrome`):① pane resize 回调从「只报 cell 像素」升级为上报**完整实测格子**`paneViewportChanged`);② **单 pane window 的 pane 帧==容器帧 → 它的实测格子就是客户端格子**,据此发 `refresh-client -C`(帧只由容器决定,无反馈环);③ kickoff 初值改用 raw surface 实测格子(`setClientSize` 不再被像素换算覆盖);④ 单 pane 时去掉 pane 的 1pt padding 圈(`solo`);⑤ 像素除法只兜底「全是多 pane window」的场景⑥ 顶栏格子数 tmux 模式改读 `TmuxController.clientGrid``screenGrid` 随 RawTerminalView 卸载已冻结)。
- **验证**(模拟器 → 本机 sshd + tmux 3.7b 端到端):`tput cols` 宽字符标尺恰好一行不换行;侧边栏收起 164×50 ⇄ 展开 135×50 双态各验证;`top` 全屏重绘干净;顶栏胶囊数字随开合正确跳变。回归法已写入 CLAUDE.md模拟器 `-txPubkeyAuth 1` 连 127.0.0.1,公钥临时入 authorized_keys
### 12.4 首版明确推迟Fable 裁决,勿在 UI-3~6 里偷偷做)
`mosh <RTT>` 实时数字(需改 vendor/mosh iosclient 导出 SRTT属传输层· ⌘K 命令面板 · 无 tmux 主机的多客户端窗口(保留横幅引导)· iPad 竖屏 pane 强制上下堆叠(会推翻「路线 b」交给 tmux relayout· 缩略卡 ANSI 彩色(用 `readViewportText()` 文本镜像,**绝不做离屏 Metal/双 surface**——IOSurfaceLayer 泄漏史)· 设置页连字/CJK 开关ghostty 无运行时 mutation灰显占位
</content>