M4: NucleicRemote iPhone app — SwiftUI client over the shared protocol

A real iOS Xcode app (ios/NucleicRemote) linking the NucleicProtocol SwiftPM
library as a local package. Builds for the iOS 27 simulator and launches to the
pairing screen.

- Transport: NWFrameChannel (NWConnection) + LANDiscovery (Bonjour _nucleic._tcp).
- Engine: drives NucleicProtocol.SyncClient (Noise XXpsk0 pair / IK reconnect,
  hello/welcome, HostMsg→Event stream).
- State: RemoteStore (ObservableObject) — the single on-device projection of host
  state; IdentityStore persists the device identity (Keychain) + pinned host.
- UI (UX_IOS): attention-first SessionsView, SessionDetailView (transcript/diff +
  status-driven action area / composer), ApprovalCardView with Face ID gate on
  high-risk approvals + allow-always menu, PairingScannerView (AVFoundation QR),
  SettingsView, connection chip. Same status glyphs/semantics as the Mac.

Add-iPhone QR display + server start live on the macOS side (follow-up); push /
Live Activity are M5 (needs the relay). gitignore keeps this .xcodeproj despite
the blanket *.xcodeproj rule.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
2026-06-13 01:12:55 -07:00
co-authored by Claude Opus 4.8
commit 6f24b42004
20 changed files with 1494 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
# NucleicRemote (iPhone client)
The thin iOS remote client for Nucleic (PLAN milestone **M4**). It's a pure projection of the
Mac host over LAN: monitor sessions, read transcripts/diffs, **answer approvals**, and send
follow-up input — scope `approve`. No local git or CLI; the Mac is the single authority
(see [`docs/UX_IOS.md`](../../docs/UX_IOS.md) and [`docs/SYNC_PROTOCOL.md`](../../docs/SYNC_PROTOCOL.md)).
## Architecture
All wire/crypto logic is shared with the Mac via the **`NucleicProtocol`** SwiftPM library
(this Xcode project links it as a local package at `../..`):
- **Transport** — `NWFrameChannel` (NWConnection) + `LANDiscovery` (Bonjour `_nucleic._tcp`).
- **Engine** — `NucleicProtocol.SyncClient` runs the Noise handshake (XXpsk0 to pair, IK to
reconnect), exchanges hello/welcome, and turns `HostMsg`s into a `SyncClient.Event` stream.
- **State** — `RemoteStore` (`ObservableObject`) is the single on-device UI state, a pure
projection of the host. Identity + pinned host live in `IdentityStore` (Keychain + UserDefaults).
- **UI** — SwiftUI: `SessionsView` (attention-first list), `SessionDetailView`
(transcript/diff + status-driven action area), `ApprovalCardView` (Face ID gate on
high-risk), `PairingScannerView` (QR), `SettingsView`.
## Build & run
```sh
# Resolves the local NucleicProtocol package automatically.
xcodebuild -project ios/NucleicRemote/NucleicRemote.xcodeproj \
-scheme NucleicRemote \
-destination 'platform=iOS Simulator,name=iPhone 17 Pro' build
```
Or open `NucleicRemote.xcodeproj` in Xcode and run. To pair, start the sync server on the Mac
(Nucleic ▸ Settings ▸ Add iPhone shows the QR), then scan it. On a real device, both must be
on the same Wi‑Fi.
## Status
The full pair → list → subscribe → approve → reconnect path is implemented and the protocol/
server side is covered by tests in `Tests/NucleicProtocolTests` and `Tests/NucleicCoreTests`.
Push notifications / Live Activity (UX_IOS §5.1/§5.3) are the M5 follow-up (needs the relay).