fix(mobile): preserve hosted resume and reconnect

This commit is contained in:
Jinwoo-H
2026-08-30 23:20:49 -04:00
parent 7aa09a2ee7
commit ef39227895
5 changed files with 24 additions and 10 deletions
+12 -4
View File
@@ -316,6 +316,9 @@ type SessionScreenProps = {
sessionChatPendingDeliveryOperations?: HostSessionChatPendingDeliveryOperations
connectionState?: ConnectionState
nativeHostBinding?: boolean
reconnect?: () => Promise<void>
reconnectAttempts?: number
lastConnectedAt?: number | null
}
export { SessionScreen as default }
@@ -334,7 +337,10 @@ export function SessionScreen({
sessionChatDraftOperations: sessionChatDraftOperationsProp,
sessionChatPendingDeliveryOperations: sessionChatPendingDeliveryOperationsProp,
connectionState: connectionStateProp,
nativeHostBinding = true
nativeHostBinding = true,
reconnect: reconnectProp,
reconnectAttempts: reconnectAttemptsProp,
lastConnectedAt: lastConnectedAtProp
}: SessionScreenProps = {}) {
const {
hostId,
@@ -441,8 +447,10 @@ export function SessionScreen({
},
[sessionDeviceOperations]
)
const reconnectAttempts = useReconnectAttempt(hostId)
const lastConnectedAt = useLastConnectedAt(hostId)
const nativeReconnectAttempts = useReconnectAttempt(hostId)
const nativeLastConnectedAt = useLastConnectedAt(hostId)
const reconnectAttempts = reconnectAttemptsProp ?? nativeReconnectAttempts
const lastConnectedAt = lastConnectedAtProp ?? nativeLastConnectedAt
const relayRecovery = useRelayRecoveryStatus(hostId)
const forceReconnectHost = useForceReconnect()
const { name: worktreeName, resolution: worktreeResolution } = useLiveWorktreeName({
@@ -3973,7 +3981,7 @@ export function SessionScreen({
disabled={!showConnectionRetry}
onPress={() => {
if (hostId) {
void forceReconnectHost(hostId)
void (reconnectProp ? reconnectProp() : forceReconnectHost(hostId))
}
}}
accessibilityRole={showConnectionRetry ? 'button' : undefined}
@@ -101,6 +101,13 @@ export default function HostMobileWebSessionRoute() {
sessionChatPendingDeliveryOperations={sessionChatPendingDeliveryOperations}
connectionState={connectionState}
nativeHostBinding={false}
reconnect={() =>
shell.client
? shell.client.navigationReconnect().then(() => undefined)
: Promise.reject(new Error('Native shell channel unavailable'))
}
reconnectAttempts={shell.reconnectAttempts}
lastConnectedAt={shell.lastConnectedAt}
/>
)
}
+1 -6
View File
@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react'
import { useMemo } from 'react'
import { usePathname, useRouter } from 'expo-router'
import { HostScreen } from '../app/h/[hostId]/index'
import { HostProtocolGatesProvider } from '../src/components/host-protocol-gates-context'
@@ -16,11 +16,6 @@ export default function HostMobileWebRoute() {
const shell = useMobileWebNativeShell()
const router = useRouter()
const pathname = usePathname()
useEffect(() => {
if (shell.context) {
shell.rememberRoute({ kind: 'workspaceList' })
}
}, [shell.context, shell.rememberRoute])
const workspaceOperations = useMemo(
() => (shell.client ? webHostWorkspaceOperations(shell.client) : undefined),
[shell.client]
@@ -40,6 +40,9 @@ describe('mobile web session screen binding', () => {
expect(hostedSessionRoute).toContain(
'sessionNativeChatOperations={sessionNativeChatOperations}'
)
expect(hostedSessionRoute).toContain('reconnect={() =>')
expect(hostedSessionRoute).toContain('reconnectAttempts={shell.reconnectAttempts}')
expect(hostedSessionRoute).toContain('lastConnectedAt={shell.lastConnectedAt}')
expect(hostedSessionRoute).toContain('<SessionScreen')
expect(nativeSessionRoute).toContain('export function SessionScreen(')
expect(nativeSessionRoute).not.toContain('Clipboard.setStringAsync')
@@ -43,6 +43,7 @@ describe('mobile web host screen bindings', () => {
expect(hostedRouteSource).toContain('nativeHostBinding={false}')
expect(hostedRouteSource).toContain('useWebHostStatusGates({')
expect(hostedRouteSource).toContain('value={hostStatusGates}')
expect(hostedRouteSource).not.toContain("rememberRoute({ kind: 'workspaceList' })")
expect(hostedRouteSource).not.toContain('hostCapabilities: []')
expect(hostedRouteSource).not.toContain('floatingWorkspaceEnabled: false')
expect(hostedRouteSource).not.toContain('hostDisplayName=')