diff --git a/packages/app/src/app/_layout.tsx b/packages/app/src/app/_layout.tsx index ddd192c8d..b17164fcb 100644 --- a/packages/app/src/app/_layout.tsx +++ b/packages/app/src/app/_layout.tsx @@ -23,7 +23,7 @@ import { getHostRuntimeStore, useHosts, useHostMutations, - useHostRuntimeSession, + useHostRuntimeClient, } from "@/runtime/host-runtime"; import { SessionProvider } from "@/contexts/session-context"; import type { HostProfile } from "@/types/host-connection"; @@ -176,7 +176,7 @@ function PushNotificationRouter() { } function ManagedDaemonSession({ daemon }: { daemon: HostProfile }) { - const { client } = useHostRuntimeSession(daemon.serverId); + const client = useHostRuntimeClient(daemon.serverId); if (!client) { return null; diff --git a/packages/app/src/app/h/[serverId]/agent/[agentId].tsx b/packages/app/src/app/h/[serverId]/agent/[agentId].tsx index 4b7fb7401..54ef75896 100644 --- a/packages/app/src/app/h/[serverId]/agent/[agentId].tsx +++ b/packages/app/src/app/h/[serverId]/agent/[agentId].tsx @@ -1,7 +1,7 @@ import { useEffect, useRef } from "react"; import { useLocalSearchParams, useRouter } from "expo-router"; import { useSessionStore } from "@/stores/session-store"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { buildHostRootRoute, buildHostWorkspaceAgentRoute, @@ -16,7 +16,8 @@ export default function HostAgentReadyRoute() { const redirectedRef = useRef(false); const serverId = typeof params.serverId === "string" ? params.serverId : ""; const agentId = typeof params.agentId === "string" ? params.agentId : ""; - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const agentCwd = useSessionStore((state) => { if (!serverId || !agentId) { return null; diff --git a/packages/app/src/components/agent-input-area.tsx b/packages/app/src/components/agent-input-area.tsx index 7ccc059c9..b0c922ec4 100644 --- a/packages/app/src/components/agent-input-area.tsx +++ b/packages/app/src/components/agent-input-area.tsx @@ -28,7 +28,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip import { Shortcut } from '@/components/ui/shortcut' import { Autocomplete } from '@/components/ui/autocomplete' import { useAgentAutocomplete } from '@/hooks/use-agent-autocomplete' -import { useHostRuntimeSession } from '@/runtime/host-runtime' +import { useHostRuntimeAgentDirectoryStatus, useHostRuntimeClient, useHostRuntimeIsConnected } from '@/runtime/host-runtime' import { deleteAttachments, persistAttachmentFromBlob, @@ -100,14 +100,16 @@ export function AgentInputArea({ const insets = useSafeAreaInsets() const isScreenFocused = useIsFocused() - const { client, isConnected, snapshot } = useHostRuntimeSession(serverId) + const client = useHostRuntimeClient(serverId) + const isConnected = useHostRuntimeIsConnected(serverId) + const agentDirectoryStatus = useHostRuntimeAgentDirectoryStatus(serverId) const toast = useToast() const voice = useVoiceOptional() const isDictationReady = isConnected && - (snapshot?.agentDirectoryStatus === 'ready' || - snapshot?.agentDirectoryStatus === 'revalidating' || - snapshot?.agentDirectoryStatus === 'error_after_ready') + (agentDirectoryStatus === 'ready' || + agentDirectoryStatus === 'revalidating' || + agentDirectoryStatus === 'error_after_ready') const agent = useSessionStore((state) => state.sessions[serverId]?.agents?.get(agentId)) diff --git a/packages/app/src/components/project-picker-modal.tsx b/packages/app/src/components/project-picker-modal.tsx index a1547ae43..c9ee903b3 100644 --- a/packages/app/src/components/project-picker-modal.tsx +++ b/packages/app/src/components/project-picker-modal.tsx @@ -15,7 +15,7 @@ import { usePathname } from "expo-router"; import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store"; import { shortenPath } from "@/utils/shorten-path"; import { useSessionStore } from "@/stores/session-store"; -import { useHosts, useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHosts, useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { useOpenProject } from "@/hooks/use-open-project"; import { parseServerIdFromPathname } from "@/utils/host-routes"; import { buildWorkingDirectorySuggestions } from "@/utils/working-directory-suggestions"; @@ -34,7 +34,8 @@ export function ProjectPickerModal() { return daemons[0]?.serverId ?? null; }, [pathname, daemons]); - const { client, isConnected } = useHostRuntimeSession(serverId ?? ""); + const client = useHostRuntimeClient(serverId ?? ""); + const isConnected = useHostRuntimeIsConnected(serverId ?? ""); const workspaces = useSessionStore((state) => serverId ? state.sessions[serverId]?.workspaces : undefined ); diff --git a/packages/app/src/components/terminal-pane.tsx b/packages/app/src/components/terminal-pane.tsx index f106b17e5..ada1657a8 100644 --- a/packages/app/src/components/terminal-pane.tsx +++ b/packages/app/src/components/terminal-pane.tsx @@ -19,7 +19,7 @@ import Svg, { import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles"; import type { ListTerminalsResponse } from "@server/shared/messages"; import { encodeTerminalKeyInput } from "@server/shared/terminal-key-input"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { useKeyboardShiftStyle } from "@/hooks/use-keyboard-shift-style"; import { hasPendingTerminalModifiers, @@ -150,7 +150,8 @@ export function TerminalPane({ }); const queryClient = useQueryClient(); - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const scopeKey = useMemo(() => terminalScopeKey({ serverId, cwd }), [serverId, cwd]); const terminalsQueryKey = useMemo(() => ["terminals", serverId, cwd] as const, [cwd, serverId]); diff --git a/packages/app/src/hooks/use-agent-autocomplete.ts b/packages/app/src/hooks/use-agent-autocomplete.ts index eac27074c..491e0fe1a 100644 --- a/packages/app/src/hooks/use-agent-autocomplete.ts +++ b/packages/app/src/hooks/use-agent-autocomplete.ts @@ -5,7 +5,7 @@ import { useAgentCommandsQuery, type DraftCommandConfig } from './use-agent-comm import { orderAutocompleteOptions } from '@/components/ui/autocomplete-utils' import { useAutocomplete } from './use-autocomplete' import { useSessionStore } from '@/stores/session-store' -import { useHostRuntimeSession } from '@/runtime/host-runtime' +import { useHostRuntimeClient, useHostRuntimeIsConnected } from '@/runtime/host-runtime' import { applyFileMentionReplacement, findActiveFileMention, @@ -138,7 +138,8 @@ export function useAgentAutocomplete(input: UseAgentAutocompleteInput): AgentAut return agentCwd.trim() }, [agentCwd, isDraftContext, queryDraftConfig]) - const { client, isConnected } = useHostRuntimeSession(serverId) + const client = useHostRuntimeClient(serverId) + const isConnected = useHostRuntimeIsConnected(serverId) const mode: 'command' | 'file' | null = showFileAutocomplete ? 'file' diff --git a/packages/app/src/hooks/use-agent-commands-query.ts b/packages/app/src/hooks/use-agent-commands-query.ts index e77ab7d34..63c16e5d0 100644 --- a/packages/app/src/hooks/use-agent-commands-query.ts +++ b/packages/app/src/hooks/use-agent-commands-query.ts @@ -1,5 +1,5 @@ import { useQuery } from "@tanstack/react-query"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import type { AgentProvider } from "@server/server/agent/agent-sdk-types"; const COMMANDS_STALE_TIME = 60_000; // Commands rarely change, cache for 1 minute @@ -48,7 +48,8 @@ export function useAgentCommandsQuery({ enabled = true, draftConfig, }: UseAgentCommandsQueryOptions) { - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const query = useQuery({ queryKey: commandsQueryKey(serverId, agentId, draftConfig), diff --git a/packages/app/src/hooks/use-agent-form-state.ts b/packages/app/src/hooks/use-agent-form-state.ts index 82c68a532..829ecfa8b 100644 --- a/packages/app/src/hooks/use-agent-form-state.ts +++ b/packages/app/src/hooks/use-agent-form-state.ts @@ -10,7 +10,7 @@ import type { AgentProvider, } from "@server/server/agent/agent-sdk-types"; import { useHosts } from "@/runtime/host-runtime"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { useFormPreferences, type FormPreferences } from "./use-form-preferences"; // Explicit overrides from URL params or "New Agent" button @@ -367,7 +367,8 @@ export function useAgentFormState( }, [isVisible]); // Session state for provider model listing - const { client, isConnected } = useHostRuntimeSession(formState.serverId ?? ""); + const client = useHostRuntimeClient(formState.serverId ?? ""); + const isConnected = useHostRuntimeIsConnected(formState.serverId ?? ""); const availableProvidersQuery = useQuery({ queryKey: ["availableProviders", formState.serverId], diff --git a/packages/app/src/hooks/use-all-agents-list.ts b/packages/app/src/hooks/use-all-agents-list.ts index 5c4ab7dce..77cd21fee 100644 --- a/packages/app/src/hooks/use-all-agents-list.ts +++ b/packages/app/src/hooks/use-all-agents-list.ts @@ -3,8 +3,8 @@ import { useHosts } from "@/runtime/host-runtime"; import { useSessionStore, type Agent } from "@/stores/session-store"; import { getHostRuntimeStore, - isHostRuntimeDirectoryLoading, - useHostRuntimeSession, + useHostRuntimeConnectionStatus, + useHostRuntimeIsDirectoryLoading, } from "@/runtime/host-runtime"; import type { AggregatedAgent, @@ -88,14 +88,14 @@ export function useAllAgentsList(options?: { const liveAgents = useSessionStore((state) => serverId ? state.sessions[serverId]?.agents ?? null : null ); - const { snapshot } = useHostRuntimeSession(serverId ?? ""); + const connectionStatus = useHostRuntimeConnectionStatus(serverId ?? ""); const refreshAll = useCallback(() => { - if (!serverId || snapshot?.connectionStatus !== "online") { + if (!serverId || connectionStatus !== "online") { return; } void runtime.refreshAgentDirectory({ serverId }).catch(() => undefined); - }, [runtime, serverId, snapshot?.connectionStatus]); + }, [runtime, serverId, connectionStatus]); const agents = useMemo(() => { if (!serverId || !liveAgents) { @@ -111,7 +111,7 @@ export function useAllAgentsList(options?: { }); }, [daemons, includeArchived, liveAgents, serverId]); - const isDirectoryLoading = Boolean(serverId && isHostRuntimeDirectoryLoading(snapshot)); + const isDirectoryLoading = useHostRuntimeIsDirectoryLoading(serverId ?? ""); const isInitialLoad = isDirectoryLoading && agents.length === 0; const isRevalidating = isDirectoryLoading && agents.length > 0; diff --git a/packages/app/src/hooks/use-checkout-diff-query.ts b/packages/app/src/hooks/use-checkout-diff-query.ts index d5d0c57ee..4e088e1db 100644 --- a/packages/app/src/hooks/use-checkout-diff-query.ts +++ b/packages/app/src/hooks/use-checkout-diff-query.ts @@ -2,7 +2,7 @@ import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useCallback, useEffect, useId, useMemo } from "react"; import { UnistylesRuntime } from "react-native-unistyles"; import { usePanelStore } from "@/stores/panel-store"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import type { SubscribeCheckoutDiffResponse } from "@server/shared/messages"; import { orderCheckoutDiffFiles } from "./checkout-diff-order"; @@ -56,7 +56,8 @@ export function useCheckoutDiffQuery({ enabled = true, }: UseCheckoutDiffQueryOptions) { const queryClient = useQueryClient(); - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm"; const mobileView = usePanelStore((state) => state.mobileView); diff --git a/packages/app/src/hooks/use-checkout-pr-status-query.ts b/packages/app/src/hooks/use-checkout-pr-status-query.ts index e4283505d..dcdfa2957 100644 --- a/packages/app/src/hooks/use-checkout-pr-status-query.ts +++ b/packages/app/src/hooks/use-checkout-pr-status-query.ts @@ -1,5 +1,5 @@ import { useQuery } from "@tanstack/react-query"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import type { CheckoutPrStatusResponse } from "@server/shared/messages"; const CHECKOUT_PR_STATUS_STALE_TIME = 20_000; @@ -21,7 +21,8 @@ export function useCheckoutPrStatusQuery({ cwd, enabled = true, }: UseCheckoutPrStatusQueryOptions) { - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const query = useQuery({ queryKey: checkoutPrStatusQueryKey(serverId, cwd), diff --git a/packages/app/src/hooks/use-checkout-status-query.ts b/packages/app/src/hooks/use-checkout-status-query.ts index dea647ea3..f1046c89e 100644 --- a/packages/app/src/hooks/use-checkout-status-query.ts +++ b/packages/app/src/hooks/use-checkout-status-query.ts @@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { useEffect, useMemo, useRef } from "react"; import { UnistylesRuntime } from "react-native-unistyles"; import { usePanelStore } from "@/stores/panel-store"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import type { CheckoutStatusResponse } from "@server/shared/messages"; import { checkoutStatusRevalidationKey, @@ -30,7 +30,8 @@ function fetchCheckoutStatus( } export function useCheckoutStatusQuery({ serverId, cwd }: UseCheckoutStatusQueryOptions) { - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const isMobile = UnistylesRuntime.breakpoint === "xs" || UnistylesRuntime.breakpoint === "sm"; const mobileView = usePanelStore((state) => state.mobileView); @@ -87,7 +88,7 @@ export function useCheckoutStatusQuery({ serverId, cwd }: UseCheckoutStatusQuery * only the visible agents. */ export function useCheckoutStatusCacheOnly({ serverId, cwd }: UseCheckoutStatusQueryOptions) { - const { client } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); return useQuery({ queryKey: checkoutStatusQueryKey(serverId, cwd), diff --git a/packages/app/src/hooks/use-open-project.ts b/packages/app/src/hooks/use-open-project.ts index 8cad27f3b..2582e0552 100644 --- a/packages/app/src/hooks/use-open-project.ts +++ b/packages/app/src/hooks/use-open-project.ts @@ -1,7 +1,7 @@ import { router } from "expo-router"; import { useCallback } from "react"; import { useToast } from "@/contexts/toast-context"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient } from "@/runtime/host-runtime"; import { normalizeWorkspaceDescriptor, useSessionStore, @@ -13,7 +13,7 @@ export function useOpenProject( ): (path: string) => Promise { const normalizedServerId = serverId?.trim() ?? ""; const toast = useToast(); - const { client } = useHostRuntimeSession(normalizedServerId); + const client = useHostRuntimeClient(normalizedServerId); const mergeWorkspaces = useSessionStore((state) => state.mergeWorkspaces); const setHasHydratedWorkspaces = useSessionStore( (state) => state.setHasHydratedWorkspaces diff --git a/packages/app/src/hooks/use-project-icon-query.ts b/packages/app/src/hooks/use-project-icon-query.ts index f34d98e42..6a5b5bbb9 100644 --- a/packages/app/src/hooks/use-project-icon-query.ts +++ b/packages/app/src/hooks/use-project-icon-query.ts @@ -1,5 +1,5 @@ import { useQuery } from "@tanstack/react-query"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import type { ProjectIcon } from "@server/shared/messages"; export function projectIconQueryKey(serverId: string, cwd: string) { @@ -12,7 +12,8 @@ interface UseProjectIconQueryOptions { } export function useProjectIconQuery({ serverId, cwd }: UseProjectIconQueryOptions) { - const { client, isConnected } = useHostRuntimeSession(serverId); + const client = useHostRuntimeClient(serverId); + const isConnected = useHostRuntimeIsConnected(serverId); const query = useQuery({ queryKey: projectIconQueryKey(serverId, cwd), diff --git a/packages/app/src/panels/agent-panel.tsx b/packages/app/src/panels/agent-panel.tsx index 2c4f545be..a2c17e684 100644 --- a/packages/app/src/panels/agent-panel.tsx +++ b/packages/app/src/panels/agent-panel.tsx @@ -23,7 +23,10 @@ import { useKeyboardShiftStyle } from "@/hooks/use-keyboard-shift-style"; import { usePaneContext } from "@/panels/pane-context"; import type { PanelDescriptor, PanelRegistration } from "@/panels/panel-registry"; import { - useHostRuntimeSession, + useHostRuntimeClient, + useHostRuntimeConnectionStatus, + useHostRuntimeIsConnected, + useHostRuntimeLastError, useHosts, type HostRuntimeConnectionStatus, } from "@/runtime/host-runtime"; @@ -154,11 +157,10 @@ function AgentPanelContent({ const resolvedServerId = serverId.trim() || undefined; const daemons = useHosts(); const runtimeServerId = resolvedServerId ?? ""; - const { - snapshot: runtimeSnapshot, - client: runtimeClient, - isConnected: runtimeIsConnected, - } = useHostRuntimeSession(runtimeServerId); + const runtimeClient = useHostRuntimeClient(runtimeServerId); + const runtimeIsConnected = useHostRuntimeIsConnected(runtimeServerId); + const runtimeConnectionStatus = useHostRuntimeConnectionStatus(runtimeServerId); + const runtimeLastError = useHostRuntimeLastError(runtimeServerId); const connectionServerId = resolvedServerId ?? null; const daemon = connectionServerId @@ -168,9 +170,10 @@ function AgentPanelContent({ daemon?.label ?? connectionServerId ?? "Selected host"; const isUnknownDaemon = Boolean(connectionServerId && !daemon); const connectionStatus: HostRuntimeConnectionStatus = - runtimeSnapshot?.connectionStatus ?? - (isUnknownDaemon ? "offline" : "connecting"); - const lastConnectionError = runtimeSnapshot?.lastError ?? null; + isUnknownDaemon && runtimeConnectionStatus === "connecting" + ? "offline" + : runtimeConnectionStatus; + const lastConnectionError = runtimeLastError; if (!resolvedServerId || !runtimeClient) { return ( @@ -208,7 +211,7 @@ function AgentPanelBody({ serverId: string; agentId?: string; isPaneFocused: boolean; - client: NonNullable["client"]>; + client: NonNullable>; isConnected: boolean; connectionStatus: HostRuntimeConnectionStatus; onOpenWorkspaceFile?: (input: { filePath: string }) => void; diff --git a/packages/app/src/runtime/host-runtime.ts b/packages/app/src/runtime/host-runtime.ts index fb31126f7..7db45073d 100644 --- a/packages/app/src/runtime/host-runtime.ts +++ b/packages/app/src/runtime/host-runtime.ts @@ -1755,17 +1755,13 @@ export function useHostRuntimeSnapshot( ); } -export function useHostRuntimeSession(serverId: string): { - snapshot: HostRuntimeSnapshot | null; - client: DaemonClient | null; - isConnected: boolean; -} { - const snapshot = useHostRuntimeSnapshot(serverId); - return { - snapshot, - client: snapshot?.client ?? null, - isConnected: isHostRuntimeConnected(snapshot), - }; +export function useHostRuntimeClient(serverId: string): DaemonClient | null { + const store = getHostRuntimeStore(); + return useSyncExternalStore( + (onStoreChange) => store.subscribe(serverId, onStoreChange), + () => store.getSnapshot(serverId)?.client ?? null, + () => store.getSnapshot(serverId)?.client ?? null + ); } export function useHostRuntimeIsConnected(serverId: string): boolean { @@ -1777,6 +1773,46 @@ export function useHostRuntimeIsConnected(serverId: string): boolean { ); } +export function useHostRuntimeConnectionStatus( + serverId: string +): HostRuntimeConnectionStatus { + const store = getHostRuntimeStore(); + return useSyncExternalStore( + (onStoreChange) => store.subscribe(serverId, onStoreChange), + () => store.getSnapshot(serverId)?.connectionStatus ?? "connecting", + () => store.getSnapshot(serverId)?.connectionStatus ?? "connecting" + ); +} + +export function useHostRuntimeLastError(serverId: string): string | null { + const store = getHostRuntimeStore(); + return useSyncExternalStore( + (onStoreChange) => store.subscribe(serverId, onStoreChange), + () => store.getSnapshot(serverId)?.lastError ?? null, + () => store.getSnapshot(serverId)?.lastError ?? null + ); +} + +export function useHostRuntimeAgentDirectoryStatus( + serverId: string +): HostRuntimeAgentDirectoryStatus { + const store = getHostRuntimeStore(); + return useSyncExternalStore( + (onStoreChange) => store.subscribe(serverId, onStoreChange), + () => store.getSnapshot(serverId)?.agentDirectoryStatus ?? "idle", + () => store.getSnapshot(serverId)?.agentDirectoryStatus ?? "idle" + ); +} + +export function useHostRuntimeIsDirectoryLoading(serverId: string): boolean { + const store = getHostRuntimeStore(); + return useSyncExternalStore( + (onStoreChange) => store.subscribe(serverId, onStoreChange), + () => isHostRuntimeDirectoryLoading(store.getSnapshot(serverId)), + () => isHostRuntimeDirectoryLoading(store.getSnapshot(serverId)) + ); +} + export function useHosts(): HostProfile[] { const store = getHostRuntimeStore(); return useSyncExternalStore( diff --git a/packages/app/src/screens/agent/draft-agent-screen.tsx b/packages/app/src/screens/agent/draft-agent-screen.tsx index 01e042361..cc902d188 100644 --- a/packages/app/src/screens/agent/draft-agent-screen.tsx +++ b/packages/app/src/screens/agent/draft-agent-screen.tsx @@ -33,7 +33,7 @@ import { buildWorkingDirectorySuggestions } from '@/utils/working-directory-sugg import { useExplorerOpenGesture } from '@/hooks/use-explorer-open-gesture' import { useSessionStore } from '@/stores/session-store' import { generateDraftId } from '@/stores/draft-keys' -import { getHostRuntimeStore, useHostRuntimeSession } from '@/runtime/host-runtime' +import { getHostRuntimeStore, useHostRuntimeClient, useHostRuntimeIsConnected } from '@/runtime/host-runtime' import { ExplorerSidebarAnimationProvider } from '@/contexts/explorer-sidebar-animation-context' import { usePanelStore, type ExplorerCheckoutContext } from '@/stores/panel-store' import { MAX_CONTENT_WIDTH } from '@/constants/layout' @@ -317,9 +317,8 @@ function DraftAgentScreenContent({ return collectAgentWorkingDirectorySuggestions([...liveSources, ...fetchedSources]) }, [allAgents, sessionAgents]) - const { client: runtimeClient, isConnected: isHostOnline } = useHostRuntimeSession( - selectedServerId ?? '' - ) + const runtimeClient = useHostRuntimeClient(selectedServerId ?? '') + const isHostOnline = useHostRuntimeIsConnected(selectedServerId ?? '') const sessionClient = runtimeClient const trimmedWorkingDir = workingDir.trim() const shouldInspectRepo = trimmedWorkingDir.length > 0 diff --git a/packages/app/src/screens/settings-screen.tsx b/packages/app/src/screens/settings-screen.tsx index 9d04fdd9b..2d9d1a9ef 100644 --- a/packages/app/src/screens/settings-screen.tsx +++ b/packages/app/src/screens/settings-screen.tsx @@ -24,7 +24,9 @@ import { useSessionStore } from "@/stores/session-store"; import { getHostRuntimeStore, isHostRuntimeConnected, - useHostRuntimeSession, + useHostRuntimeClient, + useHostRuntimeIsConnected, + useHostRuntimeSnapshot, } from "@/runtime/host-runtime"; import { AddHostMethodModal } from "@/components/add-host-method-modal"; import { AddHostModal } from "@/components/add-host-modal"; @@ -992,9 +994,9 @@ function HostDetailModal({ const connections = host?.connections ?? []; // Restart logic (moved from DaemonCard) - const { snapshot: runtimeSnapshot, client: runtimeClient, isConnected } = useHostRuntimeSession( - host?.serverId ?? "" - ); + const runtimeSnapshot = useHostRuntimeSnapshot(host?.serverId ?? ""); + const runtimeClient = useHostRuntimeClient(host?.serverId ?? ""); + const isConnected = useHostRuntimeIsConnected(host?.serverId ?? ""); const runtime = getHostRuntimeStore(); const daemonClient = runtimeClient; const daemonVersion = useSessionStore((state) => host ? (state.sessions[host.serverId]?.serverInfo?.version ?? null) : null); @@ -1389,7 +1391,7 @@ function DaemonCard({ onOpenSettings, }: DaemonCardProps) { const { theme } = useUnistyles(); - const { snapshot } = useHostRuntimeSession(daemon.serverId); + const snapshot = useHostRuntimeSnapshot(daemon.serverId); const connectionStatus = snapshot?.connectionStatus ?? "connecting"; const activeConnection = snapshot?.activeConnection ?? null; const lastError = snapshot?.lastError ?? null; diff --git a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx index 721417b99..3669d68e3 100644 --- a/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx +++ b/packages/app/src/screens/workspace/workspace-draft-agent-tab.tsx @@ -7,7 +7,7 @@ import { AgentStreamView } from '@/components/agent-stream-view' import type { ImageAttachment } from '@/components/message-input' import { useAgentFormState } from '@/hooks/use-agent-form-state' import { useDraftAgentCreateFlow } from '@/hooks/use-draft-agent-create-flow' -import { useHostRuntimeSession } from '@/runtime/host-runtime' +import { useHostRuntimeClient, useHostRuntimeIsConnected } from '@/runtime/host-runtime' import type { Agent } from '@/stores/session-store' import { encodeImages } from '@/utils/encode-images' import type { AgentCapabilityFlags, AgentSessionConfig } from '@server/server/agent/agent-sdk-types' @@ -40,7 +40,8 @@ export function WorkspaceDraftAgentTab({ onCreated, onOpenWorkspaceFile, }: WorkspaceDraftAgentTabProps) { - const { client, isConnected } = useHostRuntimeSession(serverId) + const client = useHostRuntimeClient(serverId) + const isConnected = useHostRuntimeIsConnected(serverId) const addImagesRef = useRef<((images: ImageAttachment[]) => void) | null>(null) const { diff --git a/packages/app/src/screens/workspace/workspace-screen.tsx b/packages/app/src/screens/workspace/workspace-screen.tsx index 103abb5ec..a61eb9a5c 100644 --- a/packages/app/src/screens/workspace/workspace-screen.tsx +++ b/packages/app/src/screens/workspace/workspace-screen.tsx @@ -70,7 +70,7 @@ import { normalizeWorkspaceTabTarget, workspaceTabTargetsEqual, } from "@/utils/workspace-tab-identity"; -import { useHostRuntimeSession } from "@/runtime/host-runtime"; +import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime"; import { useWorkspaceTerminalSessionRetention } from "@/terminal/hooks/use-workspace-terminal-session-retention"; import { checkoutStatusQueryKey, @@ -579,7 +579,8 @@ function WorkspaceScreenContent({ }); const queryClient = useQueryClient(); - const { client, isConnected } = useHostRuntimeSession(normalizedServerId); + const client = useHostRuntimeClient(normalizedServerId); + const isConnected = useHostRuntimeIsConnected(normalizedServerId); const sessionAgents = useSessionStore( (state) => state.sessions[normalizedServerId]?.agents