* build(mobile): upgrade to Expo SDK 58 and React Native 0.88
Expo 58 drops Zod from @expo/cli, which clears the last Zod 3 advisory
(GHSA-mrhx-c7xc-m3w5) in mobile along with its local patch and override.
- Expo 55 -> 58, React Native 0.83 -> 0.88, React 19.3, gesture-handler 3,
webview 14, reanimated 4.7, worklets 0.13 (SDK 58 bundled versions,
pinned below today's batch to respect minimumReleaseAge).
- Port the react-native and react-native-webview patches unchanged; drop
expo-constants, expo-notifications, @expo/cli, expo-router, zod and
query-string patches plus the zod/query-string/xcode>uuid overrides,
which upstream fixed or no longer need.
- iOS minimum rises to 16.4 (Expo 58 / RN 0.88 requirement).
- Migrate to RN 0.88 strict types: instance ref types, NamedStyles,
AppState.currentState, list header/footer nulls.
- Replace removed runtime APIs: InteractionManager -> idle callback with a
macrotask fallback; StyleSheet.absoluteFillObject -> absoluteFill;
FileHandle.readBytes -> readBytesSync (it became async).
- Resolve react-native/asset-registry for shared assets in Metro and alias
the old registry path for react-native-svg in the desktop mobile-web bundle.
- Reduce the iOS scene plugin to the reconnect override; Expo 58's template
now ships the scene delegate itself.
* fix(mobile): bridge react-native-svg web imports and libsodium runtime for RN 0.88
- Share react-native-svg web shims between the mobile-web build and its render
checks: map the old asset-registry path to react-native-web's registry and stub
the Android-only touch-sound TurboModule.
- Patch react-native-libsodium 1.7.0 to read the JSI runtime from the bridge proxy;
RN 0.88 removed RCTCxxBridge.runtime.
* fix(mobile): use Expo 58's legacy promise resolver for audio permissions
* fix(mobile): skip null handles in the RPC recording timer shims for RN 0.88 types
* style(mobile): format MobilePRSidebar after rebase
* fix(mobile): name RN 0.88 text input refs for declarations; allow queued back in stack render check
- Type text input refs with an exported interface so declaration emit can name hook results
(RN 0.88 aliases TextInputInstance to an unexported class).
- Expo Router 58 drains back() after a commit; check the interrupted push's exit from the
frame it starts, bounded to three frames of lag.
* chore(mobile): justify the text input handle interface for React Doctor
* chore(mobile): use a nameable intersection alias for text input refs
* fix(mobile): use sync expo-file-system writes, copies and moves on Expo 58
Expo 58 made File.write/copy/move and FileHandle.writeBytes return promises.
Our callers never awaited them, so failures escaped their try/catch and the
store's tmp-then-move and PDF writes could race their close or rename.
* build(mobile): raise the page bundle budget to 10 MiB for Expo 58
Expo 58 adds about 310 KB to the page: expo-router (+258 KB, now carrying
React Navigation, net about +110 KB) and Reanimated 4.7 (+152 KB). Main had
85 KB of headroom left. 10 MiB still stays within the 10 MiB per-asset contract.
* fix(mobile): drop the window-metrics seed RN 0.88 removed from Android
RN 0.88 no longer holds window metrics: DeviceInfoModule reads the activity's
WindowMetrics on demand and setWindowDisplayMetrics is gone, so MainActivity
no longer compiled. Layout scale still comes from the screen metrics we reseed.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* perf(mobile): let newer phone shells fetch the language catalog from the desktop instead of downloading all of them
* fix(mobile): hash only the buildId fields so phone readers can recompute it
* fix(mobile): use the catalog chunk when the generation still has it
* fix(desktop): give catalog reads their own read-slot budget
* perf(mobile): load the terminal engine and the session dock only when needed
Opening a session parsed xterm (with its WebGL addon) and the wide-layout
dock's Source Control and Files panels, even for chat sessions on phones.
The page's terminal now imports its engine when the first terminal mounts,
and the dock lazy-loads its panels behind a frame that paints at once.
The page build anchors lazy modules that share boot code the way it already
anchors routes, so the new lazy chunks don't split the boot chunks.
* fix(mobile): show the terminal start error when replaying queued commands throws
* feat(mobile): announce dictation to VoiceOver through the shell
* feat(mobile): speak dictation from the host, so leaving the session and the pill's toasts are announced too
* fix(mobile): say dictation outcomes where they are known, and re-read a repeated live message
* fix(mobile): leave a setup refusal to its setup sheet instead of reading the raw code
* fix(mobile): say cancelled when a kept recording is discarded
* perf(mobile): merge small route-shared page chunks into one
* refactor(mobile): share the merged page build with the route closure check
* build(mobile): check in the chunk sweep and drop the unused route closure helper
* refactor(mobile): count page chunks in one place
* feat(mobile): define the on-device speech contract for the native audio module and page bridge
* feat(mobile): dictate on the phone first and replay to the computer when the phone fails
* refactor(mobile): type the on-device speech module without a cast
* fix(mobile): point dictation's finish ref at the committed callback
* test(mobile): wait on the takeover request instead of a fixed sleep
* fix(mobile): release each dictation request's own share of a replayed backlog
* fix(mobile): let the computer's text replace the phone's after a fallback
* feat(mobile): let pages read and write the device store
* fix(mobile): import zod as a namespace in the page store verb
The page bundle check rejects `import { z }`: it ships zod's locale tables.
* perf(mobile): trim the page bundle back under its old budget
* build(mobile): simplify the route entry anchors and zod table guard
* fix(mobile): import zod as a type in the RPC result reader
* test(mobile): give the review note test a query client
* build(mobile): raise the page code budget to 9.75 MiB
* build(mobile): re-measure the page chunk sweep after the speed batch
* test(runtime): follow the terminal RPC module move in the output credit test
* feat(mobile): render math in Markdown with desktop chat's delimiter rules
Move the price, citation, closer and display rules plus the KaTeX settings
to src/shared/markdown-math-rules and point desktop chat at them. Mobile's
markdown-it gets the same grammar, and pages typeset formulas with KaTeX,
whose fonts ship as page assets. Mermaid's engine leaves katex external so
both share one katex chunk.
* build(mobile): count KaTeX fonts in the page budget and keep math to one chunk
Only the licensed terminal font keeps its own allowance; KaTeX's fonts
count toward the budget like code. The typesetter imports katex itself,
sharing mermaid's chunk, so math adds one chunk instead of four.
* fix(mobile): draw the PR line-count table's +/− glyphs at GitHub's size
github.com draws \Huge at \Large (1.44em), so the line-count table's
glyphs sit inline at text height. Cap the larger size commands the same
way, and let inline math take its height from KaTeX's struts so rows keep
normal height and numbers stay on the text baseline.
* test(mobile): pin math delimiters to desktop chat's results
* refactor(mobile): drop type assertions from the math tree nodes
* chore(mobile): register the math mdast nodes beside <details>
* fix(mobile): read bracket math only in chat, keep math parsing linear
GitHub text (PRs, Tasks, files) reads $ and $$ only, so \[Bug\] stays a
bracket; chat rows opt into desktop chat's \( and \[ too. Remember failed
block scans and skip dollar-run tails so hostile input stays linear, leave
unfinished math out of remend like desktop, bound the formula cache by bytes,
retry a failed KaTeX load, and count symbol commands in table widths.
* fix(mobile): copy formulas as TeX and keep GitHub's unclosed $$ as text
Share desktop's selection-to-TeX reader so a copied selection carries each
formula once, as its source. An unclosed $$ in GitHub text stays a
paragraph, chat's math delimiters reach HTML-derived Markdown and summaries,
failed block scans only skip openers inside the lines they read, unfinished
math anywhere in the streaming tail skips remend, and table widths no
longer spread every command into Math.max.
* refactor(mobile): share the formula copy handler and cap sizes only in GitHub text
Desktop and mobile copy through one shared handler. GitHub surfaces draw
\Huge as github.com does while chat keeps desktop chat's sizes, PR and file
text skip bracket scanning entirely, and the dollar-run scan and token
alias live in one place.
* chore(mobile): stop tracking the generated KaTeX stylesheet
#38611 committed it by mistake; postinstall writes it and .gitignore now
lists it.
* fix(mobile): follow desktop chat's new dollar rule through the shared module
#38651 changed desktop chat's inline $ rule (shell variables and prices stay
text, a single $ can span lines, $5+2$ is math). Move those checks into
src/shared/markdown-math-rules, point desktop at them, and give mobile's
markdown-it rule the same behaviour.
* feat(mobile): copy, save and share an image from the chat image viewer
* refactor(mobile): pass image viewer actions in so diagrams skip them
* fix(mobile): name the image verb native.image.act and serialize image actions
* fix(mobile): queue image actions per page and skip SVG links
* refactor(mobile): share the cache-folder helper and table the viewer's image actions
* fix(mobile): keep the toast's live region mounted so screen readers hear it
* test(mobile): re-record agent history goldens for the always-mounted toast region
* test(mobile): import the declared routes in the moved routes test