Files
terminalX/CLAUDE.md
kid aa92d0e676 初始提交:terminalX 可运行态(M0/M1/M1.5 已真机验证)
- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连
- M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire
- M1.5: tmux -CC 原生 tab(MVP)
- 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/
- 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口)
- 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名
- 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 10:20:46 +08:00

69 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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/execmacOS 支持本地 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 库 xcframeworklibssh2+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=<UDID>' \
-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 <authkey>`-txHost 填 tailnet IP
- 纯 tsnet 自检(加入+对端枚举):只给 `-txTsnetKey <authkey>`(不给 -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/` — 预编译 xcframeworkgitignore`CSSHCore`/`TsnetBridge`
## 约定 & 坑
- **CSSHCore 必须 library-only**(无 Headers/modulemaplibssh2 的 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
- 与用户始终用**简体中文**交流。
</content>