feat: 完成 M2 mosh(LAN + tsnet 端到端验证)

- mosh(blinksh/ios C++)+protobuf-lite 交叉编译为 MoshCore.xcframework
  (CommonCrypto 后端、含 arm64 模拟器 slice;绕 autotools 用 CMake 直编 + 手写 config.h)
- tsnet 桥新增 UDP relay(StartMoshRelay:loopback↔tsnet.Dial 逐包搬运)
- MoshSession(pipe↔FILE*/pthread/SIGWINCH)+ MoshConnectScanner(TXCore,+4 单测=39)
- SSHTerminalModel 编排:SSH 引导 mosh-server→解析 MOSH CONNECT→relay→mosh 接管
- LAN 直连 + mosh-over-tsnet 均端到端验证通过,R1(tsnet UDP 数据报语义) 证伪

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
kid
2026-07-24 16:14:40 +08:00
parent aa92d0e676
commit 32520f09e0
1232 changed files with 728138 additions and 37 deletions

View File

@@ -23,6 +23,13 @@ swift test --package-path packages/TXCore # 35 tests
# 重建 SSH 库 xcframeworklibssh2+mbedTLS改 vendor/libssh2|mbedtls 后)
bash vendor/build/build-cssh.sh all # 产出 artifacts/CSSHCore.xcframework (library-only!)
# 重建 mosh 库 xcframeworkmosh C++ + protobuf-lite改 vendor/mosh|protobuf 或 build/mosh/* 后)
bash vendor/build/build-mosh.sh all # 产出 artifacts/MoshCore.xcframework (library-only!)
# 注:首次需 host protoc 生成 .pb.cc已 checkin无需重跑
# cmake -S vendor/protobuf -B vendor/protobuf/build-host -G Ninja -Dprotobuf_BUILD_TESTS=OFF && \
# cmake --build vendor/protobuf/build-host --target protoc && \
# vendor/protobuf/build-host/protoc --proto_path=vendor/mosh/src/protobufs --cpp_out=vendor/mosh/src/protobufs *.proto
# 重建 tsnet 桥(改 vendor/tsnet-bridge/tsnetbridge/bridge.go 后)
export GOROOT=$HOME/.local/go; export PATH=$GOROOT/bin:$HOME/go/bin:$PATH
cd vendor/tsnet-bridge && gomobile bind -target=ios,iossimulator \
@@ -48,17 +55,24 @@ sleep N; xcrun simctl io $UDID screenshot /tmp/x.png # 然后用 Read 工具
- 直连 SSH`-txHost H -txPort 22 -txUser U -txPass PW -txAutoCommand "echo hi"`
- tsnet SSH额外加 `-txTsnetKey <authkey>`-txHost 填 tailnet IP
- 纯 tsnet 自检(加入+对端枚举):只给 `-txTsnetKey <authkey>`(不给 -txHost
- **mosh 直连(LAN)**`-txHost H -txPort 22 -txUser U -txPass PW -txMosh 1`(登录后跑 mosh-server→解析 MOSH CONNECT→mosh_main 直连 UDP
- **mosh over tsnet**:额外加 `-txTsnetKey <authkey>`-txHost 填 tailnet IPrelay=loopback↔tsnet UDP
- 自定义 mosh-server 命令:`-txMoshServerCmd "…"`(默认 `mosh-server new -s -c 256 -l LANG=en_US.UTF-8 -l LC_ALL=en_US.UTF-8`
## 仓库结构
- `packages/TXCore` — 零依赖纯逻辑tmux 解析器/layout/`SessionMachine`(会话状态机+退避重连)/`TmuxControlSequence`(DCS 检测)。
- `packages/TXTransport``SSHSession`(libssh2, 支持外部 fd)/`Transport` 协议;`CSSH`(C shim: 头+modulemap)/`CSSHCore`(binaryTarget)。
- `apps/TerminalX/iOS``SSHTerminalModel`(连接编排+tsnet+tmux 路由)/`ContentView`/`TmuxController`(tmux 网关)/`TsnetProbe`(M1 自检)。
- `vendor/` — 所有非 Swift 依赖本地化:`libghostty-spm`(GhosttyKit)/`MSDisplayLink`/`libssh2`/`mbedtls`/`tsnet-bridge`(Go)。
- `artifacts/` — 预编译 xcframeworkgitignore`CSSHCore`/`TsnetBridge`
- `packages/TXTransport``SSHSession`(libssh2, 支持外部 fd)/`MoshSession`(mosh_main 桥)/`Transport` 协议C shim: `CSSH`+`CSSHCore`(libssh2)、`CMosh`+`MoshCore`(mosh)。
- `apps/TerminalX/iOS``SSHTerminalModel`(连接编排+tsnet+tmux 路由+mosh 编排)/`ContentView`/`TmuxController`(tmux 网关)/`TsnetProbe`(M1 自检)。
- `vendor/` — 所有非 Swift 依赖本地化:`libghostty-spm`(GhosttyKit)/`MSDisplayLink`/`libssh2`/`mbedtls`/`tsnet-bridge`(Go)/`mosh`(blinksh/ios 分支)/`protobuf`(3.21.12)`build/mosh/`(手写 config.h+CMakeLists)
- `artifacts/` — 预编译 xcframework**有意提交**,非 gitignore`CSSHCore`/`TsnetBridge`/`MoshCore`
## 约定 & 坑
- **CSSHCore 必须 library-only**(无 Headers/modulemaplibssh2 的 Swift module 由包内 `CSSH` C target 提供。否则与 GhosttyKit 撞 `include/module.modulemap`
- **CSSHCore/MoshCore 必须 library-only**(无 Headers/modulemapSwift module 由包内 `CSSH`/`CMosh` C target 提供。否则与 GhosttyKit 撞 `include/module.modulemap`
- **mosh 构建**:绕过 autotools 用 CMake 直编 `src/*.cc`(手写 `build/mosh/config.h`crypto 用 CommonCrypto(`USE_APPLE_COMMON_CRYPTO_AES=1`);用 `terminaldisplayinit_ios.cc`(无 terminfo);已 patch 3 处 vendored 源(`::bind` 消歧义 / curses include 包 `#if !IOS_CONTROLLER` / 去 iOS 禁用 `system()`)protobuf 只需 lite runtime`.pb.cc` 已 checkin。
- **protoc 装不了不是问题**:用源码 CMake 编一个 host protoc 生成 `.pb.cc` 即可(一次性,产物 checkin
- **一进程一个 Go runtime、只一次 gomobile bind**(全在 `tsnetbridge` 包)。
- **Swift `\r\n` 是单个 Character扩展字形簇**:判行尾用 `Character.isNewline`,不能 `c != "\r"``MoshConnectScanner` 曾踩)。
- **Swift6 `SendNonSendable` pass 可能崩溃**`pthread_create`+`Unmanaged` 上下文+C 入口的组合):改用 `Foundation.Thread`+线程内 `pthread_self()` 规避(见 `MoshSession`)。
- GhosttyKit 的 `InMemoryTerminalSession.receive` 在 surface 未 attach 时**丢弃**写入 → 用 `OutputGate` 缓冲到 `surfaceSize != nil` 再 flush。
- tmux `-CC attach` **不推 %window-add** → 必须主动 `list-windows` 枚举。
- SourceKit "No such module" 是索引噪声,**以 `swift build`/`xcodebuild` 为准**。