mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 16:02:03 +00:00
* feat(mobile): tell users when a newer app binary is installable With OTA page updates, store releases get rare and users stop looking. The shell now asks the channel that installed it. Android sideload reads GitHub's mobile-android-v* tag refs and proves the release has an APK. iOS reads the App Store lookup. A home card above Desktops, dismissible per version, and Settings rows surface the result. The check runs on the desktop updater's cadence: cold start, foreground once 24 h have passed, and a 1 h retry after a failure. The releases atom feed was not used because it lists only the 10 newest releases, which are all desktop builds, so it never carries a mobile tag. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(mobile): parse update replies with zod schemas The anti-slop gate refuses Reflect.get on dynamic input. The GitHub refs, the release, the App Store lookup and the stored update record are now parsed into named schemas before they are read. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * docs(mobile): say why the Android update source reads tag refs Record why the Android source reads tag refs. The releases atom feed and /releases?per_page=100 are both newest-first windows that desktop releases fill. Either would silently report "current" once a run of desktop builds pushes the newest mobile release out. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(mobile): load update state once and apply review rulings Every check and dismissal now awaits one shared store load. This replaces the merge that guessed whether a check had landed during the load. A manual check that fails while the store loads therefore keeps its 1 h retry instead of re-checking at once. - checking is derived from the in-flight check. - start() uses a per-start flag, so a StrictMode double start applies one load. - A check that finishes after stop() writes nothing. - A corrupt stored update record loses only itself. - Tag refs are parsed with a single schema. - The runtime wiring is folded into one file, and the card moves to home/. - The recorded App Store fixture is oxfmt-formatted, with the same parsed value. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): keep the update timer armed across a stop and restart A check that stayed in flight across stop and restart returned 'failed' without rescheduling. The restart skipped arming because a check was in flight, which left a live checker with no timer until the next foreground. The stop counter is removed. schedule() already arms nothing while no start is active, and saving a real result after a stop is harmless. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * chore: retrigger CI after the RPC recording repin (#23757) landed on main Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * refactor(mobile): trim the update checker and Settings rows - The load sets prefs and the due time only. start() re-arms the schedule after it. - The Settings result hides through one effect keyed on the result. - onUpdate receives the URL. - The version row is bound once. - The retry and timeout constants are no longer exported. - The unused AppUpdateChecker type is deleted. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): run the update check when its timer fires The armed timer is the due time. Re-checking the wall clock when the timer fired meant a clock stepped back skipped the check and re-armed nothing. The due-time guard now applies only on foreground. The binary version still comes from expoConfig.version. SDK 55 removed Constants.nativeAppVersion, so the no-expo-updates invariant is now named in the comment. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * fix(mobile): recover from a future check time and use Apple's page URL If the device clock was ahead when a check ran and was corrected later, the stored check time is in the future. Cold starts then armed a timer for the whole skew, and foreground never came due. The stored state now reads as never checked in that case. The iOS link is the lookup's trackViewUrl instead of a URL built from trackId. Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb * style(mobile): fit the future-check-time comment in the print width Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb