import { opencodeClient } from '@/lib/opencode/client'; import type { RuntimeEndpointChangedDetail } from '@/lib/runtime-switch'; import { disposeTerminalInputTransport } from '@/lib/terminalApi'; import { useConfigStore } from '@/stores/useConfigStore'; import { useProjectsStore } from '@/stores/useProjectsStore'; import { useGlobalSessionsStore } from '@/stores/useGlobalSessionsStore'; import { useAutoReviewStore } from '@/stores/useAutoReviewStore'; import { useUIStore } from '@/stores/useUIStore'; import { usePermissionStore } from '@/stores/permissionStore'; import { useFileSearchStore } from '@/stores/useFileSearchStore'; import { useGitStore } from '@/stores/useGitStore'; import { useGitHubPrStatusStore } from '@/stores/useGitHubPrStatusStore'; import { useSessionFoldersStore } from '@/stores/useSessionFoldersStore'; import { useFilesViewTabsStore } from '@/stores/useFilesViewTabsStore'; import { useTerminalStore } from '@/stores/useTerminalStore'; import { useSessionUIStore } from '@/sync/session-ui-store'; import { resetStreamingState } from '@/sync/streaming'; import { useGlobalSessionStatusStore } from '@/sync/global-session-status'; import { resetSessionOrdering } from '@/sync/session-ordering'; import { resetSessionActivityTiming } from '@/sync/session-activity-timing'; import { syncDesktopSettings } from '@/lib/persistence'; // Same-device transport switch (LAN⇄relay for one paired device): rebind the SDK // to the new transport WITHOUT tearing down connection/session state or remounting // the sync layer. `reconnectToRuntimeBaseUrl` swaps in a fresh SDK client; the // caller then forces a re-render so SyncProvider receives it as a new `sdk` prop, // which re-runs its event-pipeline + bootstrap effects (keyed on `sdk`) to // reconnect over the new transport IN PLACE. Message-pagination refs, the open // session, and the whole view are preserved — no reconnecting screen, no flash, // no bounce back to the draft. export const reconnectAppForTransportSwitch = (): void => { disposeTerminalInputTransport(); opencodeClient.reconnectToRuntimeBaseUrl(); resetStreamingState(); }; export const resetAppForRuntimeEndpointChange = (detail: RuntimeEndpointChangedDetail): void => { useSessionUIStore.getState().prepareForRuntimeSwitch(detail.previousRuntimeKey); useUIStore.getState().prepareForRuntimeSwitch(detail.previousRuntimeKey); if (detail.previousRuntimeKey) { useAutoReviewStore.getState().stopRunningRunsForRuntime(detail.previousRuntimeKey); } disposeTerminalInputTransport(); useTerminalStore.getState().clearAll(); opencodeClient.reconnectToRuntimeBaseUrl(); useConfigStore.setState({ providers: [], agents: [], isConnected: false, isInitialized: false, connectionPhase: 'connecting', lastDisconnectReason: null, }); useProjectsStore.getState().resetForRuntimeSwitch(); // Cross-project session list (mobile sessions sheet & co) belongs to the // previous instance — drop it so stale sessions can't linger after a switch. useGlobalSessionsStore.getState().resetForRuntimeSwitch(); useGlobalSessionStatusStore.setState({ statusById: new Map() }); resetSessionOrdering(); // Turn timings belong to the previous instance's sessions, and the reset also // restarts the resume window so the switch is treated as a fresh load. resetSessionActivityTiming(); usePermissionStore.getState().reset(); useFileSearchStore.getState().resetForRuntimeSwitch(); useGitStore.getState().resetForRuntimeSwitch(detail.runtimeKey); useGitHubPrStatusStore.getState().resetForRuntimeSwitch(); useSessionFoldersStore.getState().resetForRuntimeSwitch(detail.runtimeKey); useFilesViewTabsStore.getState().resetForRuntimeSwitch(detail.runtimeKey); useSessionUIStore.getState().restoreForRuntimeSwitch(detail.runtimeKey); useUIStore.getState().restoreForRuntimeSwitch(detail.runtimeKey); resetStreamingState(); queueMicrotask(() => void syncDesktopSettings()); };