fix(app): replace greedy host runtime subscriptions with targeted hooks

useHostRuntimeSession returned the full HostRuntimeSnapshot, causing
every consumer to rerender on any internal state change (probe cycles,
client generation bumps). Replace with targeted hooks that return
primitives/stable references so useSyncExternalStore skips rerenders
when the subscribed value hasn't actually changed.

New hooks: useHostRuntimeClient, useHostRuntimeConnectionStatus,
useHostRuntimeLastError, useHostRuntimeAgentDirectoryStatus,
useHostRuntimeIsDirectoryLoading. Existing useHostRuntimeIsConnected
already followed this pattern.

useHostRuntimeSnapshot kept only for settings-screen where probe
data is legitimately needed.
This commit is contained in:
Mohamed Boudra
2026-03-20 19:16:06 +07:00
parent e0f9b33d23
commit 72ea9b7a72
20 changed files with 124 additions and 70 deletions
@@ -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
+7 -5
View File
@@ -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;
@@ -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 {
@@ -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