Commit Graph
3 Commits
Author SHA1 Message Date
abkslmandClaude Fable 5 61e11572b8 Add Tailscale (Tailnet) as a sync transport between Mac and iPhone
Settings ▸ Remote gains a "Connect via" picker — LAN (default), Tailscale
(tailnet), or Relay (disabled, coming soon). On Tailnet, both devices run an
embedded tsnet node via TailscaleKit (tailscale/libtailscale) and sync frames
flow over the user's tailnet, so the phone can connect from anywhere the
tailnet reaches; Noise E2EE runs above the transport unchanged.

- NucleicTailnet (new target, macOS + iOS): TailnetNode wraps TailscaleKit's
  node lifecycle (auth-key login, generation-fenced start/stop since up() is
  un-cancellable) and drops to the framework's public C API for the data path
  — tailscale_dial/listen/accept hand back full-duplex socketpair fds, wrapped
  by FDFrameChannel (DispatchIO) into the shared FrameChannel seam. The Swift
  wrapper's one-way connection actors can't carry a bidirectional stream.
- Host: TailnetListener adopts SyncListener; startSyncServer is single-flight
  and honors toggle-off/picker changes at the commit point; pairing QRs carry
  transport + tailnet IP/port hints (PairingPayload additive optional fields,
  forward/backward compatible over CBOR).
- iPhone: pair/reconnect dial over whichever transport the pairing recorded;
  Settings gains a Tailscale auth-key field (Keychain, committed on editing
  end); connectivity chip shows "Connected · Tailnet".
- TailscaleKit has no SwiftPM distribution: scripts/build-tailscalekit.sh
  builds a pinned libtailscale commit into an untracked local xcframework;
  Package.swift links it only when present (everything builds without it, the
  picker then reports Tailscale support as not built in), and the script
  clears SwiftPM's content-keyed manifest cache so the toggle is picked up.
- iOS floor 17.0 → 18.1 (TailscaleKit requires the iOS 18 Swift runtime);
  package-app.sh embeds the framework in the .app like Sparkle.

703-test suite: no new failures (the 7 fake-claude/fake-grok staging issues
reproduce identically on an untouched checkout — pre-existing, tracked
separately). New coverage: FDFrameChannel over socketpairs, pairing-payload
version-skew both directions, transport-setting resolution.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-03 03:50:45 -07:00
abkslmandClaude Opus 4.8 99d9cea5a3 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]>
2026-06-13 01:12:55 -07:00
abkslmandClaude Opus 4.8 e3940efa36 M4: Noise SecureChannel — XXpsk0 pairing + IK reconnect over CryptoKit
A focused, correct Noise Protocol Framework implementation for the two patterns
the sync layer needs (SYNC_PROTOCOL §4), all on CryptoKit (X25519/ChaChaPoly/
SHA256/HMAC), no third-party crypto:

- NoisePrimitives: CipherState (ChaChaPoly + 64-bit Noise nonce), SymmetricState
  (ck/h chaining, MixKey/MixHash/MixKeyAndHash, Noise-HKDF, Split).
- NoiseHandshake: token-driven HandshakeState for XXpsk0 (QR-bound mutual auth)
  and IK (reconnect against a pinned host static), role-aware DH mixing,
  pre-message handling.
- SecureChannel: DeviceIdentity (X25519 static + Ed25519 signing, raw persistence
  + fingerprint), SecureSession (per-direction transport ciphers; seal/open CBOR
  app messages), PairingPayload (QR string codec), NoiseSession initiator/responder
  helpers + HandshakeDriver.

Tests: both handshakes complete with matching channel-binding hash + correct peer
static keys; bidirectional encrypted ClientMsg/HostMsg exchange; wrong-PSK and
tampered-frame both fail closed; identity/QR round-trips; Ed25519 sign/verify.

167 tests green (was 148; +19 NucleicProtocol).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-13 00:39:48 -07:00