初始提交: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>
This commit is contained in:
kid
2026-07-24 10:20:46 +08:00
commit aa92d0e676
2761 changed files with 803505 additions and 0 deletions

View File

@@ -0,0 +1,125 @@
#!/bin/bash
set -euo pipefail
cd "$(dirname "$0")/.."
if [ ! -f .root ]; then
echo "[*] malformed project structure"
exit 1
fi
INPUT_PATH=${1:-}
if [ -z "$INPUT_PATH" ]; then
echo "Usage: $0 <xcframework_or_zip>"
exit 1
fi
if [ ! -e "$INPUT_PATH" ]; then
echo "[!] not found: $INPUT_PATH"
exit 1
fi
TEMP_DIR=
XCFRAMEWORK_PATH="$INPUT_PATH"
cleanup() {
if [ -n "$TEMP_DIR" ]; then
rm -rf "$TEMP_DIR"
fi
}
trap cleanup EXIT
if [[ "$INPUT_PATH" == *.zip ]]; then
TEMP_DIR=$(mktemp -d)
ditto -x -k "$INPUT_PATH" "$TEMP_DIR"
XCFRAMEWORK_PATH=$(find "$TEMP_DIR" -maxdepth 1 -name "*.xcframework" -type d | head -1)
fi
if [ -z "$XCFRAMEWORK_PATH" ] || [ ! -d "$XCFRAMEWORK_PATH" ]; then
echo "[!] xcframework not found in input: $INPUT_PATH"
exit 1
fi
python3 - "$XCFRAMEWORK_PATH" <<'PY'
import os
import plistlib
import subprocess
import sys
xcframework = sys.argv[1]
info_path = os.path.join(xcframework, "Info.plist")
if not os.path.isfile(info_path):
raise SystemExit(f"[!] missing xcframework Info.plist: {info_path}")
for root, dirs, _ in os.walk(xcframework):
for directory in dirs:
if directory.endswith(".framework"):
raise SystemExit(f"[!] framework wrapper is not allowed in static-library xcframework: {os.path.join(root, directory)}")
with open(info_path, "rb") as handle:
info = plistlib.load(handle)
libraries = info.get("AvailableLibraries")
if not isinstance(libraries, list) or not libraries:
raise SystemExit("[!] AvailableLibraries is empty or missing")
for library in libraries:
identifier = library.get("LibraryIdentifier")
library_path = library.get("LibraryPath")
binary_path = library.get("BinaryPath")
headers_path = library.get("HeadersPath")
platform = library.get("SupportedPlatform")
platform_variant = library.get("SupportedPlatformVariant")
declared_architectures = set(library.get("SupportedArchitectures", []))
if not identifier:
raise SystemExit("[!] library entry missing LibraryIdentifier")
if platform not in {"ios", "macos", "tvos", "watchos", "xros"}:
raise SystemExit(f"[!] unsupported platform in {identifier}: {platform}")
if library_path != "libghostty.a" or binary_path != "libghostty.a":
raise SystemExit(f"[!] {identifier} must reference libghostty.a, got LibraryPath={library_path!r} BinaryPath={binary_path!r}")
if headers_path != "Headers":
raise SystemExit(f"[!] {identifier} must use HeadersPath=Headers, got {headers_path!r}")
variant_dir = os.path.join(xcframework, identifier)
archive_path = os.path.join(variant_dir, library_path)
headers_dir = os.path.join(variant_dir, headers_path)
header_path = os.path.join(headers_dir, "ghostty.h")
modulemap_path = os.path.join(headers_dir, "module.modulemap")
for required_path in (archive_path, header_path, modulemap_path):
if not os.path.exists(required_path):
raise SystemExit(f"[!] {identifier} missing required file: {required_path}")
actual_architectures = set(
subprocess.check_output(["lipo", "-archs", archive_path], text=True).split()
)
if actual_architectures != declared_architectures:
raise SystemExit(
f"[!] {identifier} architecture metadata mismatch: "
f"plist={sorted(declared_architectures)} archive={sorted(actual_architectures)}"
)
expected_architectures = {
("macos", None): {"arm64", "arm64e", "x86_64"},
("ios", None): {"arm64", "arm64e"},
("ios", "maccatalyst"): {"arm64", "arm64e", "x86_64"},
("ios", "simulator"): {"arm64", "x86_64"},
}.get((platform, platform_variant))
if expected_architectures is not None and actual_architectures != expected_architectures:
raise SystemExit(
f"[!] {identifier} architectures must be {sorted(expected_architectures)}, "
f"got {sorted(actual_architectures)}"
)
with open(modulemap_path, "r", encoding="utf-8") as handle:
modulemap = handle.read()
if "framework module libghostty" in modulemap:
raise SystemExit(f"[!] {identifier} module map must not declare a framework module")
if "module libghostty" not in modulemap:
raise SystemExit(f"[!] {identifier} module map does not declare module libghostty")
print(f"[*] verified static-library xcframework layout and architectures: {xcframework}")
PY