Commit Graph
3 Commits
Author SHA1 Message Date
weishu 3510a0f4f1 fix(ios): Linux compile + full package test round — fixtures green locally (A-CI-local)
ios/scripts/linux-test.sh stages HapiKit + shared/fixtures at repo depth
into a persistent tmp dir and runs swift test in swift:6.1-noble; the
manifest drops HapiUI (SwiftUI/swift-markdown/Highlightr) under
#if os(Linux). 458 tests green, including all 48 chat and 11 pagination
golden fixtures.

Fixes that fell out of the first real compile of the blind-written port:
- ChatTypes.CodexReview.wireValue + SummaryPatching legacy id fallback:
  split expressions that exceeded the Swift 6 type-checker budget
- FileEndpointsTests: raw string containing "# terminated the literal
  early (never compiled anywhere) — now ##-delimited
- SSEClient.backoffSleep: Task { try? ... } inferred Task<()?, Never>
- Darwin gates: Security/Keychain behind canImport(Security) (tests use
  InMemoryCredentialStore via CredentialStoring), CryptoKit digest with
  FNV-1a filename fallback, FoundationNetworking imports for URLSession
  types, corelibs URLCache diskPath: initializer, get-only
  waitsForConnectivity, delegate-based SSE transport where
  URLSession.bytes(for:) does not exist
2026-08-18 11:51:57 +08:00
weishu 3363d1c75b feat(ios): pairing flow, deep link, app session wiring (A-M1d)
- HapiProtocol/Pairing/BindLink: parses the companion deeplink
  (hapicompanion://bind?hub=&code=) and the web direct-access QR
  (?hub=&token=) with URLSearchParams form-decoding semantics, in
  lockstep with the Android port (tests mirror BindLinkTest.kt).
- HapiClient/Auth/HubPairingService: normalize -> GET /health
  (reachability + protocolVersion) -> POST /api/auth -> persist
  Keychain + registry + active hub; unpair with fallback. Covered by
  PairingLogicTests through the HTTPPerforming seam.
- App layer: AppModel (@Observable @MainActor pairing state machine:
  restore, pair, switch, sign out, deep-link routing, scenePhase,
  terminal-auth-failure banner) + HubSession (per-active-hub APIClient/
  AuthManager/global SSEClient with suspend-resume and a connection
  state for the UI; store routing is TODO(M2)).
- Pairing UI: welcome flow, VisionKit QR scanner (with Simulator/
  permission fallbacks), manual entry (paste-friendly), shared confirm
  sheet with per-PairingFailure error states.
- HapiApp routes hapicompanion:// through AppModel (paired hubs switch
  with a notice, never log the token); RootView switches unpaired/
  paired and hosts the deep-link confirm sheet; HomePlaceholderView
  shows hub, connection dot, hub switcher (M2a replaces it with the
  session list).
- Info.plist: NSCameraUsageDescription; README: pairing guide + manual
  test pass.
2026-08-17 15:58:17 +08:00
weishu 1f0ec6184d feat(ios): HapiClient API transport + auth (A-M1b)
APIClient (final class, Sendable) with typed endpoints for the M2/M3 REST
surface behind an HTTPPerforming seam; actor AuthManager with single-flight
JWT refresh (POST /api/auth), proactive refresh 10 min before exp, terminal
authFailed state, and 401 -> refresh -> retry-once wiring per
docs/api/client-contract/auth.md; Keychain credential store (per-hub records
under run.hapi.companion) with CredentialStoring seam + in-memory double;
HubRegistry (ordered hubs + active hub in injectable UserDefaults, origin
normalization); payload-only JWT decoding; APIError {status, code, body}
parsing per errors.md; minimal multipart builder for M4c dictation; 256 MB
URLCache session for generated images.

Request/response wire models (SendMessageRequest, PermissionApproveRequest,
SpawnRequest/SpawnResponse, MessagesQuery, envelopes, RPC-wrapped shapes)
join HapiProtocol/Models mirroring shared/src/apiTypes.ts.

swift-testing coverage: JWT decode (padding/garbage/hostile exp), auth
single-flight (8 concurrent callers -> one exchange), 401 retry-once and
terminal paths, APIError body parsing, endpoint request construction
byte-checks (cursor queries, deliveryMode body, answers formats, explicit
null model reset) via a recording performer, hub URL normalization,
multipart bytes.
2026-08-17 15:20:03 +08:00