Files
web-terminal/ios/Packages/WireProtocol/Sources/WireProtocol/ClientMessage.swift
Yaojia Wang cbaa08daba 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
2026-07-04 21:19:30 +02:00

42 lines
2.1 KiB
Swift

import Foundation
/// Client server WS frames (frozen contract, plan §3.1; mirrors
/// `src/types.ts:87-92` `ClientMessage`). Immutable value type.
///
/// Server-side validation the caller must respect (the server SILENTLY DISCARDS
/// invalid frames, `src/protocol.ts:45-86` no error reply comes back):
/// - `attach` must be the FIRST frame on a connection (src/server.ts:707-711).
/// - `resize` cols/rows must be integers in `WireConstants.resizeRange` (1...1000).
/// - `attach.cwd`, when present, must be an absolute path (`Validation.isAbsoluteCwd`).
/// - `input.data` is raw keyboard bytes, passed through verbatim never filtered.
public enum ClientMessage: Sendable, Equatable {
/// First frame. `sessionId == nil` spawns a new session (encoded as an
/// explicit JSON `"sessionId":null` the key is REQUIRED by the server,
/// src/protocol.ts:132-134). `cwd` = "new tab here" spawn directory (M6).
case attach(sessionId: UUID?, cwd: String?)
/// Raw keyboard bytes, verbatim (invariant #9 no content filtering).
case input(data: String)
/// Own message type so the server can `ioctl(TIOCSWINSZ)` SIGWINCH.
case resize(cols: Int, rows: Int)
/// Resolve a held permission gate with allow. `mode` is only meaningful for
/// a `plan` gate and is encoded as a TOP-LEVEL `mode` key the server's WS
/// wiring re-parses the raw frame for it (src/server.ts:91-102).
case approve(mode: ApproveMode?)
/// Resolve a held permission gate with deny.
case reject
}
/// Permission mode written back when resolving a `plan` gate. Raw values mirror
/// the server whitelist `PERMISSION_MODES` (src/server.ts:76 / src/types.ts:365).
///
/// Note: the plan-gate three-way UI only ever sends `.acceptEdits` / `.default`
/// (mirroring public/tabs.ts:345-347). Raw `.auto` is gated by ALLOW_AUTO_MODE
/// (default false) and is server-downgraded to `default` otherwise
/// (src/server.ts:765-766); it is reserved for a future permission-mode switcher.
public enum ApproveMode: String, Sendable, CaseIterable {
case `default`
case acceptEdits
case plan
case auto
}