feat(ios): W0 scaffold + day-1 spike + WireProtocol frozen contract + TestSupport doubles

T-iOS-1: ios/ XcodeGen project (iOS 17, Swift 6 strict concurrency, ATS per PLAN §5.2), 5 SPM package shells, CI skeleton
T-iOS-2: Origin spike vs real server — URLSessionWebSocketTask custom Origin CONFIRMED (no Starscream); 16MiB replay + EMSGSIZE(40) errno correction written back to plan
T-iOS-3: WireProtocol frozen contract, 59 tests, 100% line coverage, cross-impl vectors vs src/protocol.ts via tsx
T-iOS-4: FakeTransport/FakeClock/FakeHTTPTransport doubles
Verify: independent agent re-ran all acceptance — 6/6 PASS
This commit is contained in:
Yaojia Wang
2026-07-04 21:19:30 +02:00
parent 9b41ffa574
commit cbaa08daba
46 changed files with 3203 additions and 3 deletions

View File

@@ -0,0 +1,89 @@
//
// SpikeTerminalScreen.swift T-iOS-2 Day-1 spike W4/T-iOS-15
//
// SwiftTerm TerminalView /IME smoke plan §7 T-iOS-2
// - / first-responder
// - IME keydown
// - inputAccessoryView Esc/Ctrl-C SwiftTerm iOS
// TerminalAccessory esc/ctrl/tab iOSAccessoryView.swift
// spike key-bar public/keybar.ts T-iOS-11
// - SwiftTerm
//
// 线typed bytes send() feed()
// CR CRLF SessionEngine 线 W2/W3
//
// 2026-07-04 DEFERRED() PROGRESS_LOG
// App target xcodebuild
import SwiftTerm
import SwiftUI
/// Day-1 spike SwiftUI WebTermApp WebTermApp.swift
/// T-iOS-1/T-iOS-15 App target Swift 6 strict
/// concurrency SwiftTerm TerminalView
struct SpikeTerminalScreen: View {
var body: some View {
LocalEchoTerminal()
.ignoresSafeArea(.container, edges: .bottom)
.navigationTitle("SwiftTerm spike")
}
}
/// SwiftTerm UIKit `TerminalView` UIViewRepresentable
/// T-iOS-11 TerminalScreen SessionEngine
private struct LocalEchoTerminal: UIViewRepresentable {
func makeCoordinator() -> LocalEchoCoordinator {
LocalEchoCoordinator()
}
func makeUIView(context: Context) -> TerminalView {
let view = TerminalView(frame: .zero)
view.terminalDelegate = context.coordinator
view.feed(text: SpikeGreeting.text)
return view
}
func updateUIView(_ uiView: TerminalView, context: Context) {
//
}
}
private enum SpikeGreeting {
/// CRLFPTY LF
static let text = "SwiftTerm local-echo spike (T-iOS-2)\r\n"
+ "Typed bytes are echoed locally; CR -> CRLF.\r\n"
+ "真机清单: 键盘弹出 / 中文 IME / accessory esc·ctrl / 文本选择\r\n\r\n> "
}
/// delegateSwiftTerm "宿"
/// Enter CR0x0D LF
@MainActor
private final class LocalEchoCoordinator: NSObject, @preconcurrency TerminalViewDelegate {
private static let carriageReturn: UInt8 = 0x0D
private static let lineFeed: UInt8 = 0x0A
func send(source: TerminalView, data: ArraySlice<UInt8>) {
var echoed: [UInt8] = []
echoed.reserveCapacity(data.count + 1)
for byte in data {
echoed.append(byte)
if byte == Self.carriageReturn {
echoed.append(Self.lineFeed)
}
}
source.feed(byteArray: echoed[...])
}
func sizeChanged(source: TerminalView, newCols: Int, newRows: Int) {}
func setTerminalTitle(source: TerminalView, title: String) {}
func hostCurrentDirectoryUpdate(source: TerminalView, directory: String?) {}
func scrolled(source: TerminalView, position: Double) {}
func requestOpenLink(source: TerminalView, link: String, params: [String: String]) {}
func clipboardCopy(source: TerminalView, content: Data) {}
func rangeChanged(source: TerminalView, startY: Int, endY: Int) {}
// bell / iTermContent SwiftTerm
}
#Preview {
SpikeTerminalScreen()
}

View File

@@ -0,0 +1,24 @@
import SwiftUI
/// T-iOS-1 scaffold: empty-window placeholder. Navigation assembly
/// (Pairing SessionList Terminal) is wired in T-iOS-15.
@main
struct WebTermApp: App {
var body: some Scene {
WindowGroup {
HelloPlaceholderView()
}
}
}
private struct HelloPlaceholderView: View {
var body: some View {
VStack(spacing: 12) {
Image(systemName: "terminal")
.font(.largeTitle)
Text("Hello WebTerm")
.font(.title2)
}
.padding()
}
}