Skip to content

Add opt-in iOS Live Activities and managed reference relay - #97

Draft
yuv41 wants to merge 8 commits into
alvarolorentedev:mainfrom
yuv41:feat/ios-live-activities
Draft

yuv41 wants to merge 8 commits into
alvarolorentedev:mainfrom
yuv41:feat/ios-live-activities

Conversation

@yuv41

@yuv41 yuv41 commented Nov 2, 2026 •

Copy link
Copy Markdown

Summary

Adds an experimental, opt-in iOS Live Activity for OpenCode 2 work, reusing the existing notification coordinator and native OpencodeActivity module. Default store builds and Android behavior remain unchanged.

  • Native Lock Screen and Dynamic Island presentations with safe work-phase icons, elapsed time, active-agent/running-tool counts, and actual task-list progress when known.
  • Last-known work state remains visible when observations are paused or stale; freshness is secondary and never presented as proof that the server job stopped.
  • No invented progress percentages, private prompts/titles/commands/replies, Lock Screen mutations, App Group, background keepalive, or parallel query owner.
  • Preserves scoped routing, opaque aggregate cycles, dismissal suppression across relaunch, queued-write freshness guards, and independent completion notifications.
  • Adds native rendering checks and explicitly requested unsigned iPhone test builds, with compiler/download caching where applicable.
  • Includes a separately committed fix for a device-confirmed startup assertion: the TLS module's Expo fetch-provider setter is main-actor isolated and must not run on the React Native JS thread.

This is a draft contribution, not a request to enable the feature in store builds immediately. See ADRs 0024/0025/0026 and docs/product/parity/ios-widget.md for boundaries.

Remote delivery: implemented managed reference relay

Adds services/live-activity-relay/: authenticated registration, persistent revision/token/lease handling, operator-scoped V2 observation, localized complete-state aggregation, and an HTTP/2 APNs sender. The native consumer registers ActivityKit update tokens, observes rotations, restores observation on adoption, and keeps remote content under a single relay writer. No Cloud Link endpoint is assumed and app connection credentials are not forwarded.

Scope limitation: remote mode tracks explicit operator-allowlisted {source, sessionID} pairs, not the app's connected-server aggregate. New sessions require operator configuration and relay restart. It requires MDM managed-app enrollment; there is no self-service enrollment UI for unmanaged personal devices. Remote taps open the app root, and optional progress metrics remain absent when unverified.

Setup requires more than Apple credentials: deploy and supervise the single-process relay with protected persistent state, HTTPS reverse proxy, explicit V2 source credentials/session allowlists, unique per-installation enrollment credentials via MDM, a paid-team push-enabled app profile, matching APNs environment/topic, and a build configured with EXPO_IOS_ACTIVITY_RELAY_URL. Full setup and limitations are in docs/engineering/ios-live-activity-remote-delivery.md. The relay is not deployed and real-device APNs delivery is unverified. Maintainer feedback on this deliberately narrow managed mode is welcome.

Screenshots

Lock Screen card rendered by the production SwiftUI view in the iOS Simulator, from native preview run 41373085725 on merged 531f1ee (45 cases in total; full set in the run artifact). These are harness captures, not system Lock Screen / Dynamic Island hosting.

Running commands (dark) Reading files (light)
Running commands (dark) Reading files (light)
Needs your input (light) Finished, tasks 6 of 6 (dark)
Needs your input (light) Finished, tasks 6 of 6 (dark)
Paused with last-known progress (dark) Hebrew right-to-left (light)
Paused with last-known progress (dark) Hebrew right-to-left (light)
Long French text at accessibility size
Long French text at accessibility size

Verification

  • Latest npm run validate:commit on Node 24.21.0: passed — lint, app/test typechecks, 1,033 tests across 156 suites.
  • Latest focused notification/native-config/preview/docs Vitest run: 170 tests across 14 suites passed.
  • Latest npm run test:fake-server:self: both V1 and V2 passed.
  • Latest npm run test:e2e:web:isolated -- tests/e2e/chat.spec.mjs: fresh web export and 18/18 chat flows passed.
  • npm run build:storybook: passed on the combined 1.0.121 source; dependency use client bundler warnings remain non-fatal.
  • npm run gen:i18n: passed; every supported locale includes the new strings.
  • Affected chat/session/settings/onboarding/V2 Playwright flows: 58/58 passed after upstream alignment.
  • Earlier implementation plus TLS startup correction: installed, launched, and displayed Live Activities on a contributor's iPhone 17 / iOS 27.2. The richer dashboard is not yet physically accepted.
  • Aligned with upstream ae31093 / 1.0.121 using merge commit aa433c4; no branch-history rewrite or release tag.
  • Merged upstream 165f5e6 / 1.0.124 in 2476c59 (no history rewrite). The only conflict was the TLS fix that upstream landed independently in 0aa15a2; upstream's version is kept. Live Activity ADRs were renumbered 0024/0025/0026 because upstream took 0023 for focused extension editors. Post-merge npm run validate:commit on 531f1ee: lint, both typechecks, 1,046 tests / 156 suites passed; npm run test:fake-server:self V1/V2 passed; chat + sessions Playwright 27/27 passed.
  • GitHub reports merge conflicts against current main (mergeable_state: dirty). Resolving and validating the upstream integration is required before this draft can become merge-ready.
  • Prior native run 41350471769 succeeded on e2d48c15c37b679712ef01ae9fd0de710a628d2c: Apple-SDK typecheck, 45 production-view Simulator harness previews, and an unsigned iPhoneOS Release IPA. This includes intrinsic layout sizing, bounded visual fallbacks and atomic UIKit PNG capture. It predates the managed relay additions.
  • Final native preview and unsigned IPA build for merged 531f1ee: run 41373085725 passed — Apple-SDK typecheck (including OpencodeActivityRemote.swift), 45 Simulator previews, and unsigned Release archive (1.0.124 / 124, checksum and bundle contents verified). The preview separately SDK-typechecks OpencodeActivityRemote.swift with its attributes; the archive compiles all module Swift files through the podspec. Earlier native success does not certify the new relay code.

Native SDK compilation, synthetic rendering, full-app startup, Personal Team device checks, and real APNs delivery are distinct results. No remote APNs delivery is claimed.

Test decision

  • Unit/contract coverage exercises current-turn plan derivation, incomplete transcript windows, root/scope aggregation, privacy redaction, stale-write cancellation, lifecycle metadata, optional Codable compatibility, payload bounds, CNG target membership/idempotence, and unsigned packaging.
  • Relay tests cover installed-SDK decoding, authorization/scope isolation, revisions and rotation, restart enrollment invalidation, terminal ordering, lease expiry, payload epochs/localization/budgets, and HTTP/2 headers/JWT signatures using an isolated test server.
  • Native rendering checks reuse the production SwiftUI view rather than a visual copy. They do not claim actual system Lock Screen/Dynamic Island hosting or full React Native app startup.
  • Existing chat/session flows cover unaffected navigation, prompt lifecycle, and scoped links; no browser/fake-server fixtures are changed.
  • New strings are supplied in every supported locale.

Documentation

  • Updated product parity, functional behavior, native integration and test-build documentation.
  • Added ADR 0025 for richer progress/freshness and ADR 0026 for the managed reference relay; documented actual setup and remaining acceptance.
  • No additional JavaScript dependencies or application version bump.

Risk and remaining acceptance

  • Feature remains behind EXPO_IOS_LIVE_ACTIVITIES=1; default/FOSS/E2E configurations do not enable it.
  • Local updates cannot promise fresh progress after iOS suspends the app. The implemented remote path requires operator infrastructure, MDM enrollment and paid push provisioning; APNs acceptance does not prove delivery/display, and device validation remains outstanding.
  • Rich task progress is shown only from confirmed current-run task lists. Missing history is unknown, not zero; file totals are not inferred from an incomplete window.
  • Physical-device layout, VoiceOver, text scaling, interrupted/foreground lifecycle, multiple connections and long-running sessions need continued acceptance testing.
  • The unsigned test IPA requires external signing/provisioning; it is not a TestFlight or App Store release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant