# CLAUDE.md — terminalX 原生苹果生态终端工具,解决 iPad/iPhone 远程运维 macOS/Linux + vibe coding 痛点。 平台优先级 **iPadOS > iOS > macOS(Apple Silicon)**。四大核心:**libghostty** 引擎 · **mosh** · **Tailscale(tsnet 用户态)** · **tmux control-mode hook**。 iOS/iPadOS 只做远程(沙盒禁 fork/exec);macOS 支持本地 PTY。 > **新会话必读**:先读 `docs/HANDOFF.md`(项目全貌 + 里程碑状态 + 如何继续)。本文件只讲操作规范。 ## ⚠️ 铁律:绝不臆想工具结果 调用任何工具后,在**真实结果返回前**绝不预测/编造/续写其输出(不写假想的 `BUILD SUCCEEDED`、日志、`ls`、截图内容)。一次调用→停→读真实返回→再推理。想说预期只在调用**之前**用将来时。发现自己编造要**硬停**重新核实。(曾因此误诊,教训见 git 历史 / HANDOFF。) ## 环境约束(关键,决定一切构建方式) - 构建机走**带认证的 HTTPS 代理**(疑似国内网)。规律:`github.com` release blob 可经 `curl` 下;**`go.dev`/`ghcr.io`(brew bottle) 被代理 abort**;**SwiftPM 不支持带认证代理** → 所有 SPM 依赖必须 **vendor 本地化**(见 `vendor/`)。Go 模块走 `goproxy.cn`。 - **Go 1.26.5 在 `~/.local/go`**(不在默认 PATH!经 aliyun 镜像 curl 装);**gomobile/gobind 在 `~/go/bin`**。`go env` 已固化 `GOPROXY=https://goproxy.cn GOSUMDB=off`。 - 工具链:Xcode 26.6 / Swift 6.3 / xcodegen 2.46 / zig 0.15.2 / cmake 4.4 / ninja 1.13。 ## 构建 & 验证命令 ```sh # 纯逻辑单测(无需 Xcode/模拟器) swift test --package-path packages/TXCore # 35 tests # 重建 SSH 库 xcframework(libssh2+mbedTLS,改 vendor/libssh2|mbedtls 后) bash vendor/build/build-cssh.sh all # 产出 artifacts/CSSHCore.xcframework (library-only!) # 重建 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 \ -o ../../artifacts/TsnetBridge.xcframework ./tsnetbridge # 构建 app(改 project.yml 后先 xcodegen generate) cd apps/TerminalX && xcodegen generate --spec project.yml xcodebuild -project TerminalX.xcodeproj -scheme TerminalX \ -destination 'platform=iOS Simulator,id=' \ -clonedSourcePackagesDirPath /tmp/tx-spm build ``` ## 无头验证(本环境无 GUI,用 simctl 截图取证) iPad Pro 13(M5) 模拟器 UDID:`2EA9055E-4557-4B20-82AF-56A68AC1D454`(变了用 `xcrun simctl list devices`)。 ```sh UDID=2EA9055E-4557-4B20-82AF-56A68AC1D454 APP=$(find ~/Library/Developer/Xcode/DerivedData/TerminalX-*/Build/Products/Debug-iphonesimulator -maxdepth 1 -name TerminalX.app | head -1) xcrun simctl boot $UDID; xcrun simctl install $UDID "$APP" xcrun simctl launch $UDID ai.athom.terminalx --args <见下> sleep N; xcrun simctl io $UDID screenshot /tmp/x.png # 然后用 Read 工具看 /tmp/x.png ``` **启动参数(NSUserDefaults 参数域,自动连接,供无头验证)**: - 直连 SSH:`-txHost H -txPort 22 -txUser U -txPass PW -txAutoCommand "echo hi"` - tsnet SSH:额外加 `-txTsnetKey `(-txHost 填 tailnet IP) - 纯 tsnet 自检(加入+对端枚举):只给 `-txTsnetKey `(不给 -txHost) ## 仓库结构 - `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/` — 预编译 xcframework(gitignore):`CSSHCore`/`TsnetBridge`。 ## 约定 & 坑 - **CSSHCore 必须 library-only**(无 Headers/modulemap);libssh2 的 Swift module 由包内 `CSSH` C target 提供。否则与 GhosttyKit 撞 `include/module.modulemap`。 - **一进程一个 Go runtime、只一次 gomobile bind**(全在 `tsnetbridge` 包)。 - GhosttyKit 的 `InMemoryTerminalSession.receive` 在 surface 未 attach 时**丢弃**写入 → 用 `OutputGate` 缓冲到 `surfaceSize != nil` 再 flush。 - tmux `-CC attach` **不推 %window-add** → 必须主动 `list-windows` 枚举。 - SourceKit "No such module" 是索引噪声,**以 `swift build`/`xcodebuild` 为准**。 - 密钥/密码**绝不写进仓库**;测试主机凭据由用户即时提供。 - 提交/推送 git 只在用户明确要求时(当前已 `git init`,尚无 commit)。 - 与用户始终用**简体中文**交流。