authorgravatar for jakeleventhal@me.comJake Leventhal <jakeleventhal@me.com> 2026-09-11 12:01:23-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-11 09:01:23-07:00
log2ebc9fa4ed24e389eef24039f27c73ae6633858f
treed6f97e4189584d8b925dc54820d0e5b98c986638
parent5eecc24a10013be14e496b485f8d1d9491c75f6a
signature Signed by PGP key B5690EEEBB952194

fix(mobile): prevent Hermes crashes when opening threads (#11233)


3 files changed, 21 insertions(+), 3 deletions(-)

apps/mobile/src/lib/threadActivity.test.ts+16-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1import { derivePendingRequests } from "@t3tools/client-runtime/pending-requests";1import { derivePendingRequests } from "@t3tools/client-runtime/pending-requests";
2import { describe, expect, it } from "vite-plus/test";2import { beforeEach, describe, expect, it } from "vite-plus/test";
33
4import {4import {
5 ApprovalRequestId,5 ApprovalRequestId,
...@@ -27,6 +27,21 @@ import {...@@ -27,6 +27,21 @@ import {
27 type WorkLogEntry,27 type WorkLogEntry,
28} from "./threadActivity";28} from "./threadActivity";
2929
30// Match Hermes: these ES2023 array methods are absent on mobile.
31beforeEach(() => {
32 const methods = ["toSorted", "toReversed"] as const;
33 const descriptors = methods.map((method) =>
34 Object.getOwnPropertyDescriptor(Array.prototype, method),
35 );
36 for (const method of methods) Reflect.deleteProperty(Array.prototype, method);
37 return () => {
38 for (const [index, method] of methods.entries()) {
39 const descriptor = descriptors[index];
40 if (descriptor) Reflect.defineProperty(Array.prototype, method, descriptor);
41 }
42 };
43});
44
30const singleSelectQuestion = {45const singleSelectQuestion = {
31 id: "runtime",46 id: "runtime",
32 header: "Runtime",47 header: "Runtime",
packages/client-runtime/src/work-log/presentation.ts+3-1
...@@ -658,7 +658,9 @@ export function omitSupersededLifecycleMarkers<T>(...@@ -658,7 +658,9 @@ export function omitSupersededLifecycleMarkers<T>(
658 }658 }
659 }659 }
660660
661 return reversedEntries.toReversed();661 // Hermes lacks toReversed; this array is local, so reversing it cannot mutate the input.
662 // oxlint-disable-next-line unicorn/no-array-reverse
663 return reversedEntries.reverse();
662}664}
663665
664export function toolGroupSummaryKind(666export function toolGroupSummaryKind(
packages/client-runtime/src/work-log/userInput.ts+2-1
...@@ -27,8 +27,9 @@ function questionFingerprint(...@@ -27,8 +27,9 @@ function questionFingerprint(
27 questions: ReadonlyArray<unknown>,27 questions: ReadonlyArray<unknown>,
28): string | undefined {28): string | undefined {
29 const texts = questions.map((question) => (typeof question === "string" ? question.trim() : ""));29 const texts = questions.map((question) => (typeof question === "string" ? question.trim() : ""));
30 // Sort the fresh array in place because Hermes does not provide toSorted.
30 return texts.length > 0 && texts.every(Boolean)31 return texts.length > 0 && texts.every(Boolean)
31 ? JSON.stringify([turnId, texts.toSorted()])32 ? JSON.stringify([turnId, texts.sort()])
32 : undefined;33 : undefined;
33}34}
3435