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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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<boolean> {
|
||||
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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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<ReturnType<typeof useHostRuntimeSession>["client"]>;
|
||||
client: NonNullable<ReturnType<typeof useHostRuntimeClient>>;
|
||||
isConnected: boolean;
|
||||
connectionStatus: HostRuntimeConnectionStatus;
|
||||
onOpenWorkspaceFile?: (input: { filePath: string }) => void;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user