feat(mobile): add Shipyard for iPhone

Merged
PU
8d ago
+11417-6

Last of the phone app's PRs. Stacked on #206 (packages/core), so its diff shows only the app; it retargets to main once #206 merges. It uses the box API from #207 and the relay from #208, and still works with older boxes.

mobile/: Expo SDK 58, expo-router, iOS first (Android later from the same code)

  • Pair: scan the existing Settings → Phone QR code in the app, paste its link, or open berth://pair#…. Each box is asked who it is before it's kept.
  • Needs you: every box's agents, waiting first, plus runs at a gate; a badge on the tab.
  • Session: Chat (the conversation, from #207) or Screen; answer buttons (a permission reads as Allow / Always allow / Deny, keeping the option's number); Enter, Stop and arrow keys; a prompt.
  • Runs: approve, reject, pick an attempt, cancel.
  • Boxes: notifications Off / Needs you / Needs you and done (registers with the relay, then each box), Forget, Pair another box.
  • Live: a version 2 box's event stream while the app is open; older boxes are read every 4 s like the web app. Push covers the background, and a tap opens the session or run, also from a cold start.
  • Storage: tokens in the keychain (AFTER_FIRST_UNLOCK_THIS_DEVICE_ONLY).
  • ATS: NSAllowsLocalNetworking plus an exception for ts.net. No NSAllowsArbitraryLoads; raw tailnet addresses aren't subject to ATS.
  • Demo (acme data, no box), for App Review.
  • Shared code comes from @berth/core/* (tsconfig paths, Metro watchFolders, Jest moduleNameMapper).

Desktop: Settings → Phone gets a Phone apps group (the phones the boxes notify, with which boxes, what they hear and when they last got one) with Remove. The pairing steps mention the app, and a note suggests turning ntfy off when a phone uses the app. New spec e2e/phone-apps.spec.ts.

Docs: phone guide section and changelog. The guide links to the relay section added in #207.

Checks:

  • mobile: pnpm typecheck, pnpm test (12), and pnpm export (Metro bundles the iOS app, which proves packages/core resolves).
  • A new mobile CI job runs the same three.
  • The app's full checks and build pass; the new e2e spec passed 3/3.
  • The demo was driven in Chromium at iPhone size through a temporary web export (not committed).

Not verified, needs Apple setup:

  • An EAS development build on a device.
  • ATS for tailnet addresses, short names and *.ts.net.
  • Streaming the event feed over Tailscale on iOS.
  • A real APNs notification through the deployed relay.

Prerequisites:

  • An Apple Developer org account, App ID dev.berth.phone and an APNs key (the same key goes to the relay).
  • An EAS account.
  • A privacy policy URL and review notes for App Review.

Merging after #207/#208: each PR adds its own changelog bullet, CI job and AGENTS.md line in the same places, so expect small additive conflicts.

šŸ¤– Generated with Claude Code