Repository navigation
Conversation
Each local Expo module and SwiftUI call site now has a typed contract (X.types.ts), an iOS binding (X.ios.tsx) and a fallback (X.tsx) picked by Metro platform extensions. Android bundles resolve to the fallbacks and contain no @expo/ui/swift-ui or expo-apple-authentication code. Native fingerprint is unchanged (only modules/*/ios is hashed). Co-Authored-By: Claude <noreply@anthropic.com>
Composer.android.tsx implements the composer contract in React Native: draft with initialDraft/onDraftChange, submit, isSending, canStop/onStop, attachments tray, header chips, agent and launch-option pickers, the permission-mode menu with SF Symbol names mapped to lucide icons, onHeightChange, onExpandedChange and the ComposerHandle methods, plus presentImage (a viewer hosted by the mounted composer) and fileThumbnail (images only). iOS keeps its native binding unchanged. Plan and the RN-vs-Kotlin decision: apps/mobile/plans/20261029-android-composer.md
- Serve /.well-known/assetlinks.json from apps/web beside the apple-app-site-association route, public in the proxy. The cert fingerprint list (ANDROID_SIGNING_CERT_SHA256) is empty until the upload and Play App Signing keys exist; it lives in constants.ts, not app-identity.ts, because app-identity.ts is hashed into the mobile runtime fingerprint. - Add autoVerify https intent filters for /page/ and /workspaces/ on the same host as the iOS associated domain. - eas.json: apk for development, development-simulator (inherited), preview and e2e-test; app-bundle for production; submit.production .android to the internal track as a draft, using the service account key stored on EAS. EAS Metadata (store.config.js) supports only the App Store, so the Play listing stays manual. eas-dev.sh stays iOS-only: `eas simulator --egress local` supports only iOS. eas-runtime-version.test.ts and fingerprint.config.js make no iOS-only assumption. The iOS runtime fingerprint changes with this commit (eas.json, the android block of the Expo config and app-identity.ts are all hashed for every platform), so the next deploy builds and submits a new iOS binary.
… header seams - alert-prompt: RN Modal + TextInput, drawn by AlertPromptHost at the root - symbol-button: Pressable + lucide icon map, dropdown menu for items - title-press: pressableTitle() gives a tappable headerTitle where the native bar cannot report taps; iOS returns undefined (native title) - forward-swipe: right-edge pan strip (gesture-handler) that pushes - GlassSurface and glassHeaderOptions seams: expo-glass-effect is now imported only from .ios files; Android gets an opaque header and a flat tonal surface - WorkspaceScreen rename uses the alert-prompt seam, not Alert.prompt - lingui scans apps/mobile/modules Co-Authored-By: Claude <noreply@anthropic.com>
Ports the Live Activity contract to Android: one ongoing BigText notification that asks to be promoted to a Live Update on Android 16+. Same contract and caller; iOS unchanged (binding renamed .native.ts). Plan covers the gaps and push token registration for both platforms. Co-Authored-By: Claude <noreply@anthropic.com>
…droid app config Android emulator boot spike (step 1 of Android support). - intl-polyfills: Hermes on Android lists zh-Hans-CN/zh-Hant-TW but not zh-CN/zh-TW, so NumberFormat and DateTimeFormat formatted Chinese as en-US. scriptSubtagFallback.android.ts wraps both constructors and passes the maximized tag when the native one does not support the tag as written. iOS and bun resolve to a no-op. Measured on API 33 for all 17 supported locales; nothing else throws or falls back. - signInWithApple fallback (Android): surface the API error instead of failing silently. Apple web OAuth still fails server-side: the API has no Apple Services ID or client secret (CLIENT_ID_AND_SECRET_REQUIRED). - app.config android: adaptive icon background #151110 to match the icon ground, and expo-localization supportedLocales for Android (generates locales_config.xml for per-app language). Note: any app.config.ts edit changes the iOS runtime-version fingerprint. Co-Authored-By: Claude <noreply@anthropic.com>
Android has no Sign in with Apple, so the provider list is per platform
(socialProviders.ios.ts keeps Apple; the .ts fallback drops it) and the
Apple web-OAuth fallback is gone. iOS renders and calls exactly what it
did: native Apple, browser GitHub and Google.
Google on Android goes through Credential Manager (the account bottom
sheet) via modules/google-credential, a small Android-only Kotlin Expo
module on androidx.credentials + googleid. It asks for an ID token for
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID (the API's GOOGLE_CLIENT_ID) with a
nonce and signs in with signIn.social({ provider: "google", idToken }).
better-auth already verifies that token against GOOGLE_CLIENT_ID, so the
server is unchanged. With no Google account on the device, or no client
ID configured, it falls back to the browser flow; a canceled sheet does
nothing.
Chosen over @react-native-google-signin/google-signin: its free edition
uses the deprecated legacy Google Sign-In SDK on Android (Credential
Manager is in the paid edition), and its config plugin and GoogleSignIn
pod would touch the iOS build. The local module has no config plugin,
so the iOS runtime fingerprint is unchanged (333eefdb...).
Co-Authored-By: Claude <noreply@anthropic.com>
…back fixes from device - sheetHeaderOptions seam for formSheet routes: iOS is glassHeaderOptions unchanged; Android draws a JS drag handle + title (+ header items) and rounds the sheet top, since Android form sheets have no native bar - contentScrollsUnderHeader seam: Home and the chat workspace keep a transparent header on iOS only; on Android the first rows sat behind the bar and the host/sort chips took no taps - alert-prompt: KeyboardAvoidingView so the dialog stays above the IME - Input: see-through selection colour on Android (white hid the text) - symbol-button: style on the menu root, so the trigger fills its slot - forward-swipe: 1px edge view with 40dp hit slop; taps under it reach the content and the swipe starts inside the gesture-nav Back zone Verified on the Pixel 2 API 33 emulator. Co-Authored-By: Claude <noreply@anthropic.com>
…poser
- collapsable={false} on the field's wrapper: flattening it in one state and
not the other re-parented the field, and Android dropped focus.
- Lift by keyboard + bottom inset: RN reports the keyboard without the
navigation bar.
- Blur on keyboardDidHide, so Back collapses the composer as on iOS.
Verified on the Pixel_2_API_33 emulator; findings in the plan.
Holds back the Android release config; see the final commit.
Holds back the Android release config; see the final commit.
Holds back the Android release config; see the final commit.
Holds back the Android release config; see the final commit.
Holds back the Android release config; see the final commit.
- scripts/android-dev.sh boots the emulator, builds the dev client only when the installed APK is not this worktree's (owner + fingerprint on the device), starts Metro with --clear, reverses the service ports and opens the app. --doctor, --reload, --user, --shot, --stop. - .agents/skills/mobile-android-verification: Android mechanics and the traps found while porting (JDK 17, shared emulator, stale Metro cache, dev auto sign-in, iOS fingerprint files). - plans/20261029-android-launch-checklist.md: account, signing, Google sign-in, App Links and Play steps a person must do, and known gaps. - play-store.config.js + scripts/play-listing.ts: the Play listing (text reused from the App Store listing, icon, feature graphic, form answers) checked against Play's limits and pushed through the Play Developer API with --push. Co-Authored-By: Claude <noreply@anthropic.com>
…uth clients Co-Authored-By: Claude <noreply@anthropic.com>
…note Co-Authored-By: Claude <noreply@anthropic.com>
Parallel worktrees can each boot and drive their own AVD on a fixed port. Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
|
No installed development build can load this pull request as an update: its native fingerprint is |
Contributor
🚀 Preview Deployment🔗 Preview Links
Preview updates automatically with new commits |
…rage row
A persisted cache over ~2 MB could not be read back from Android's SQLite
("Row too big to fit into CursorWindow"), and AsyncStorage stops at 6 MB.
Android now writes it to a file in the cache directory and removes the old
row unread. iOS keeps AsyncStorage.
signIn.social reports a failure in res.error and does not throw, so GitHub, Google (browser) and Apple failed silently. A dismissed browser still resolves without an error.
…e link does not open the desktop app The sidebar gets an Agents item and Home an "Open in browser" button, both as full-document links because /agents is another deployment behind a rewrite. /workspaces/[id] shows "Continue in browser" (/agents/workspace/[id]) once the desktop deep link has had time to open.
deploy-agents builds apps/mobile's web export in Actions and uploads it to its own Vercel project with --prebuilt. Previews are aliased to agents-pr-<n>-superset.vercel.app and the preview web deploy rewrites /agents there; production web reads AGENTS_URL. docs/agents-web.md lists the Vercel project and secrets to create.
A next.config rewrite to another origin drops the headers() entries, so the /agents document had no CSP or security headers at all. Rewriting pages from src/proxy.ts, after the sign-in check, keeps them; assets still use the next.config rewrite.
…tays at its baseline The mobile tsconfig has no Bun types, so import.meta.dir and Bun.serve added six errors.
…xist AGENTS_URL is optional; without it the dashboard hides the Agents links and the workspace browser fallback, and deploy-agents skips when VERCEL_AGENTS_PROJECT_ID is not set, so merging before the one-time setup does not break the web deploy.
The list's minHeight assumed a transparent 44pt header the content scrolls under, which only iOS has. Under an opaque header the list already starts below it, so the content came out about 20pt taller than the list and an empty Home scrolled.
The labels read COMPANY.DOMAIN while the buttons open billingSettingsUrl on EXPO_PUBLIC_WEB_URL, so a build pointed at another web origin (dev, preview) named the wrong place. webHost() reads the same variable.
…ter and closes on Escape
…rop the drag grabber
…t a hook It calls no React hooks, so the use- name broke biome's useHookAtTopLevel rule in its test.
On the web a formSheet route replaced the page. sheetScreenOptions maps it to a transparent modal there, so the stack keeps the screen below visible, and WebScreen draws it as a centred dialog on a wide window or a bottom sheet on a narrow one: dimmed backdrop that closes on click, role=dialog with aria-modal, focus trapped inside and returned to the opener on close, Escape as before. Stack.Toolbar turns the stack header back on, so the sheet's JS header (SheetHeader, the search field) renders through SheetHeaderSlot, which portals it into the dialog on the web and renders in place elsewhere. iOS and Android keep presentation formSheet.
Opening /workspace/<id>/files-changed cold (a reload on the web, a deep link on a phone) gave the stack the anchor and the screen, so back went Home. ParentScreens, the authenticated stack's layout, puts the missing parent screens below the focused one once, from the state the stack opens with: files changed and pull request go back to their workspace, a page to Pages, a settings page to Settings. Navigation after that, and every stack that already has history, is unchanged.
showActionSheet fell back to Alert.alert on Android, which keeps an empty title band above the buttons. Android now draws the choices in a Compose ModalBottomSheet (ActionSheetHost, mounted at the root like the attachments sheet): one row per choice, the destructive one in red, no Cancel row; dismissing reports the cancel index. iOS keeps ActionSheetIOS and the web keeps the in-app dialog; their host renders nothing.
The JS search header replaces the sheet's header items there, so the toolbar ✕ never showed and only Back or Escape closed it. SearchBar takes onClose and draws a ✕ beside the field. iOS keeps its native search bar and toolbar close.
…reens The SwiftUI composer caps its tabs, quick keys and card at 720 pt on iPad. The React Native composer, which web and Android use, stretched them across the window: 1440 px of quick keys on a desktop browser. A clusterColumn seam gives the web the same 720 px centred column; Android keeps full width. The READABLE_WIDTH test now pins the RN constant too.
LegendList's web rows are absolutely positioned at left: 0 and right: 0, so the content container's side padding never reached them. At 1440 px the card grid computed a 180 px inset and drew from the window edge anyway, while the header kept its gutter. listSideInset puts the inset on the content natively and on each row and the scope bar on web.
A chat at 1440 px ran its replies across the whole window. useColumnInset is the readable inset (useReadableInset) on web and the base padding elsewhere, so the transcript and its dock chips sit in the same 720 px column as the composer. Native keeps 16 px, as before.
… while it has the keyboard On a computer the terminal takes typing directly (#5 in report 17), so the touch quick-key strip only took room while you typed there. The web shim reports when xterm's textarea holds focus; the workspace hides the keys until focus moves back to the composer or elsewhere. Wider than the readable column, the terminal iframe gets 12 px of padding instead of sitting flush against the window edge. The native WebView never reports focus, and the generated terminal page is unchanged.
Rows were divs, so ⌘-click, middle-click and Copy Link Address did nothing. RowLink wraps a row in an <a href> (display: contents) with the path under the export's base path. A plain click cancels the anchor and lets the row's own press handler navigate in the app; a modified click skips the handler and the browser opens a tab. The row's right-click menu gains Open in new tab and Copy link, since it replaces the browser's menu. Natively RowLink renders the row unchanged.
…print) app.config.ts (android block: adaptive icon, locales, App Links intent filters), eas.json (Android build and submit profiles), the mobile .gitignore and app-identity.ts all feed the iOS fingerprint. Merging this commit to main makes deploy.yml build and submit a new iOS binary, and installed iOS builds stop taking OTA updates until they update. The assetlinks.json route and its constants come along because App Links need the intent filters. Drop this commit to merge the Android work without an iOS release. Co-Authored-By: Claude <noreply@anthropic.com>
…nager mergers under R8 - withAndroidLabel sets app_name to BRAND.NAME, the Android counterpart of CFBundleDisplayName. `name` stays "Superset" because iOS derives its product and scheme names from it. - fingerprint.config.js strips the label from the hashed config, as it does for the iOS display name, so a rename does not need a new binary. - R8 full mode keeps WorkManager's InputMerger classes without their constructors (work-runtime 2.9.1 consumer rule has no members), so every job failed with NoSuchMethodException, among them expo-observe's ObservabilityBackgroundWorker. Added a keep rule with <init>() through expo-build-properties. Changes the iOS runtime fingerprint (new plugin entry); no iOS behaviour change.
react-native-web, react-dom and @expo/metro-runtime, at the versions bunx expo install picks for SDK 58. Expo adds "web" to the config platforms and bun re-hashes peer sets, so the iOS runtime fingerprint changes: 5115ae66c305 -> e42314744de3 (android bea2605d7cfe -> d26c50902269).
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
How this branch works
android/stagingcollects the work as cherry-picked commits from theandroidworkspaces (all landed). The last three commits are the release tail:chore(mobile): Android release configand twofingerprint:commits (Android label + R8 rule, Expo web dependencies). Supersedes #9118.What
apps/mobileruns on iOS, Android and web from one codebase. Each platform gets its most native UI; plain React Native is the fallback. iOS behaviour is unchanged.apps/mobile/AGENTS.md): use an@expo/uiuniversal component or community drop-in first (SwiftUI on iOS, Jetpack Compose on Android, DOM on web); otherwiseX.ios.tsx/X.android.tsx/X.web.tsxbehind anX.types.tscontract;X.tsxis a React Native fallback that must work.MenuView) for share access, file actions, composer mode and symbol buttons, Compose AlertDialog for the rename prompt, Material bottom sheet for attachments, header actions through atoolbarIconseam.HeaderToolbarseam (36 screens), chat with token streaming and bottom pinning, diffs, Pages in an iframe, voice orb fallback, browser session cookie, terminal in an iframe, browser file chooser, browser WebRTC,backdrop-filterglass, in-app alert dialog, keyboard focus rings, reload-to-update gate. API accepts origins inMOBILE_WEB_ORIGINS(unset = none)./agents: the web build is served atapp.superset.sh/agents, same-origin with the dashboard (shared sign-in cookie, no extra CORS). apps/web rewrites/agents/*in its proxy so the route keeps its own CSP; the sidebar and Home link to it, and/workspaces/[id]offers "Continue in browser". Off until set up: needs asuperset-agentsVercel project,VERCEL_AGENTS_PROJECT_IDandAGENTS_URL(production) secrets — steps indocs/agents-web.md. Without them the links stay hidden anddeploy-agentsskips.Composer.tsx(Android, web, tests); iOS keeps the SwiftUI composer.scripts/android-dev.sh,.agents/skills/mobile-android-verification,play-store.config.js,scripts/play-listing.ts,plans/20261029-android-launch-checklist.md, manualdeploy-android.ymlworkflow.They change the iOS runtime fingerprint. Merging them makes
deploy.ymlbuild and submit a new iOS binary, and installed iOS builds stop taking OTA updates until they update. Drop all three to merge the Android and web code dark (web then needs its dependency commit back before it builds); every commit before them leaves the fingerprint unchanged.Verified
tsc: mobile 188 (pre-existing), api/shared 0.check:i18n: 0 missing in 16 locales. sherif clean.expo exportfor iOS, Android and web all succeed. iOS fingerprint unchanged by everything after the release tail.MOBILE_WEB_ORIGINS.Not verified / not done
and light.
Not verified / not done
Stack.Toolbarheader controls do not render on web (~40 screens); a hosted origin needs adding to the API CORS list and better-auth trusted origins; chat sessions, the voice orb (Rive) and the Pages webview are unverified on web.Summary by cubic
Adds Android and web support to
apps/mobile; iOS behavior is unchanged. Every iOS-only API now sits behind a typed platform contract picked by Metro, so Android and web resolve to React Native fallbacks instead of@expo/ui, native Expo modules, and Sign in with Apple.Android
MenuViewmenus, a ComposeAlertDialogrename prompt, a bottom-sheet attachments picker, and a Compose host theme.android-dev.shdev setup (one emulator per worktree, no stale Metro port reuse), a verification skill, Play listing config, and App Links intent filters.Web
HeaderToolbarseam; chat markdown renders and code highlights via Shiki's JS engine; the chat list pins to the newest item only while the reader is at the bottom, streaming token by token.Alert.alertdraws in a modal with all its buttons; the browser's session cookie carries auth; glass usesbackdrop-filter. Sent attachments open in the platform viewer — QuickLook, an Android intent, or a new tab./agents, whichapps/webserves on the dashboard origin, sharing its session cookie and its own CSP; CI deploys the export to its own Vercel project./agentsstays dark untilAGENTS_URLand that project exist.Before merging
Written for commit d55d882. Summary will update on new commits.