refactor(app): unified navigateToAgent (#841)
* refactor(app): unify agent navigation * fix(app): resolve archived agent navigation
This commit is contained in:
@@ -59,7 +59,6 @@ import { useLatchedBoolean } from "@/hooks/use-latched-boolean";
|
|||||||
import { useOpenProject } from "@/hooks/use-open-project";
|
import { useOpenProject } from "@/hooks/use-open-project";
|
||||||
import { useAppSettings } from "@/hooks/use-settings";
|
import { useAppSettings } from "@/hooks/use-settings";
|
||||||
import { useStableEvent } from "@/hooks/use-stable-event";
|
import { useStableEvent } from "@/hooks/use-stable-event";
|
||||||
import { navigateToWorkspace } from "@/hooks/use-workspace-navigation";
|
|
||||||
import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher";
|
import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher";
|
||||||
import { polyfillCrypto } from "@/polyfills/crypto";
|
import { polyfillCrypto } from "@/polyfills/crypto";
|
||||||
import { queryClient } from "@/query/query-client";
|
import { queryClient } from "@/query/query-client";
|
||||||
@@ -72,7 +71,6 @@ import {
|
|||||||
} from "@/runtime/host-runtime";
|
} from "@/runtime/host-runtime";
|
||||||
import { getDaemonStartService } from "@/runtime/daemon-start-service";
|
import { getDaemonStartService } from "@/runtime/daemon-start-service";
|
||||||
import { usePanelStore } from "@/stores/panel-store";
|
import { usePanelStore } from "@/stores/panel-store";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
|
||||||
import { THEME_TO_UNISTYLES, type ThemeName } from "@/styles/theme";
|
import { THEME_TO_UNISTYLES, type ThemeName } from "@/styles/theme";
|
||||||
import type { HostProfile } from "@/types/host-connection";
|
import type { HostProfile } from "@/types/host-connection";
|
||||||
import { resolveActiveHost } from "@/utils/active-host";
|
import { resolveActiveHost } from "@/utils/active-host";
|
||||||
@@ -85,13 +83,12 @@ import {
|
|||||||
parseWorkspaceOpenIntent,
|
parseWorkspaceOpenIntent,
|
||||||
} from "@/utils/host-routes";
|
} from "@/utils/host-routes";
|
||||||
import { buildNotificationRoute, resolveNotificationTarget } from "@/utils/notification-routing";
|
import { buildNotificationRoute, resolveNotificationTarget } from "@/utils/notification-routing";
|
||||||
|
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||||
import {
|
import {
|
||||||
ensureOsNotificationPermission,
|
ensureOsNotificationPermission,
|
||||||
WEB_NOTIFICATION_CLICK_EVENT,
|
WEB_NOTIFICATION_CLICK_EVENT,
|
||||||
type WebNotificationClickDetail,
|
type WebNotificationClickDetail,
|
||||||
} from "@/utils/os-notifications";
|
} from "@/utils/os-notifications";
|
||||||
import { resolveWorkspaceIdByExecutionDirectory } from "@/utils/workspace-execution";
|
|
||||||
import { prepareWorkspaceTab } from "@/utils/workspace-navigation";
|
|
||||||
|
|
||||||
polyfillCrypto();
|
polyfillCrypto();
|
||||||
|
|
||||||
@@ -118,25 +115,8 @@ function PushNotificationRouter() {
|
|||||||
const serverId = target.serverId;
|
const serverId = target.serverId;
|
||||||
const agentId = target.agentId;
|
const agentId = target.agentId;
|
||||||
if (serverId && agentId) {
|
if (serverId && agentId) {
|
||||||
const session = useSessionStore.getState().sessions[serverId];
|
navigateToAgent({ serverId, agentId, currentPathname: pathname, pin: true });
|
||||||
const agent = session?.agents.get(agentId);
|
return;
|
||||||
const workspaceId =
|
|
||||||
target.workspaceId ??
|
|
||||||
resolveWorkspaceIdByExecutionDirectory({
|
|
||||||
workspaces: session?.workspaces.values(),
|
|
||||||
workspaceDirectory: agent?.cwd,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (workspaceId) {
|
|
||||||
prepareWorkspaceTab({
|
|
||||||
serverId,
|
|
||||||
workspaceId,
|
|
||||||
target: { kind: "agent", agentId },
|
|
||||||
pin: true,
|
|
||||||
});
|
|
||||||
navigateToWorkspace(serverId, workspaceId, { currentPathname: pathname });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
router.navigate(buildNotificationRoute(data));
|
router.navigate(buildNotificationRoute(data));
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
} from "react-native";
|
} from "react-native";
|
||||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||||
import { useCallback, useMemo, useState, type ReactElement } from "react";
|
import { useCallback, useMemo, useState, type ReactElement } from "react";
|
||||||
import { router, type Href } from "expo-router";
|
|
||||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||||
import { useIsCompactFormFactor } from "@/constants/layout";
|
import { useIsCompactFormFactor } from "@/constants/layout";
|
||||||
import { formatTimeAgo } from "@/utils/time";
|
import { formatTimeAgo } from "@/utils/time";
|
||||||
@@ -19,9 +18,7 @@ import { type AggregatedAgent } from "@/hooks/use-aggregated-agents";
|
|||||||
import { useSessionStore } from "@/stores/session-store";
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
import { Archive } from "lucide-react-native";
|
import { Archive } from "lucide-react-native";
|
||||||
import { getProviderIcon } from "@/components/provider-icons";
|
import { getProviderIcon } from "@/components/provider-icons";
|
||||||
import { buildHostAgentDetailRoute } from "@/utils/host-routes";
|
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||||
import { resolveWorkspaceIdByExecutionDirectory } from "@/utils/workspace-execution";
|
|
||||||
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
|
|
||||||
import type { Agent } from "@/stores/session-store";
|
import type { Agent } from "@/stores/session-store";
|
||||||
import { useArchiveAgent } from "@/hooks/use-archive-agent";
|
import { useArchiveAgent } from "@/hooks/use-archive-agent";
|
||||||
|
|
||||||
@@ -312,23 +309,13 @@ export function AgentList({
|
|||||||
|
|
||||||
const serverId = agent.serverId;
|
const serverId = agent.serverId;
|
||||||
const agentId = agent.id;
|
const agentId = agent.id;
|
||||||
const workspaceId = resolveWorkspaceIdByExecutionDirectory({
|
|
||||||
workspaces: useSessionStore.getState().sessions[serverId]?.workspaces?.values(),
|
|
||||||
workspaceDirectory: agent.cwd,
|
|
||||||
});
|
|
||||||
|
|
||||||
onAgentSelect?.();
|
onAgentSelect?.();
|
||||||
|
|
||||||
if (!workspaceId) {
|
|
||||||
router.navigate(buildHostAgentDetailRoute(serverId, agentId) as Href);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rememberArchivedAgentDetail(agent);
|
rememberArchivedAgentDetail(agent);
|
||||||
navigateToPreparedWorkspaceTab({
|
navigateToAgent({
|
||||||
serverId,
|
serverId,
|
||||||
workspaceId,
|
agentId,
|
||||||
target: { kind: "agent", agentId },
|
|
||||||
pin: Boolean(agent.archivedAt),
|
pin: Boolean(agent.archivedAt),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { splitComposerAttachmentsForSubmit } from "@/components/composer-attachm
|
|||||||
import type { CreateAgentRequestOptions, DaemonClient } from "@server/client/daemon-client";
|
import type { CreateAgentRequestOptions, DaemonClient } from "@server/client/daemon-client";
|
||||||
import { projectIconPlaceholderLabelFromDisplayName } from "@/utils/project-display-name";
|
import { projectIconPlaceholderLabelFromDisplayName } from "@/utils/project-display-name";
|
||||||
import { requireWorkspaceExecutionAuthority } from "@/utils/workspace-execution";
|
import { requireWorkspaceExecutionAuthority } from "@/utils/workspace-execution";
|
||||||
|
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||||
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
|
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
|
||||||
import type { ImageAttachment, MessagePayload } from "./message-input";
|
import type { ImageAttachment, MessagePayload } from "./message-input";
|
||||||
|
|
||||||
@@ -190,6 +191,14 @@ export function WorkspaceSetupDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearWorkspaceSetup();
|
clearWorkspaceSetup();
|
||||||
|
if (target.kind === "agent") {
|
||||||
|
navigateToAgent({
|
||||||
|
serverId: pendingWorkspaceSetup.serverId,
|
||||||
|
agentId: target.agentId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
navigateToPreparedWorkspaceTab({
|
navigateToPreparedWorkspaceTab({
|
||||||
serverId: pendingWorkspaceSetup.serverId,
|
serverId: pendingWorkspaceSetup.serverId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|||||||
import type { TextInput } from "react-native";
|
import type { TextInput } from "react-native";
|
||||||
import { router, usePathname, type Href } from "expo-router";
|
import { router, usePathname, type Href } from "expo-router";
|
||||||
import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store";
|
import { useKeyboardShortcutsStore } from "@/stores/keyboard-shortcuts-store";
|
||||||
import { useSessionStore } from "@/stores/session-store";
|
|
||||||
import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher";
|
import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher";
|
||||||
import { useAllAgentsList } from "@/hooks/use-all-agents-list";
|
import { useAllAgentsList } from "@/hooks/use-all-agents-list";
|
||||||
import type { AggregatedAgent } from "@/hooks/use-aggregated-agents";
|
import type { AggregatedAgent } from "@/hooks/use-aggregated-agents";
|
||||||
@@ -11,15 +10,14 @@ import {
|
|||||||
clearCommandCenterFocusRestoreElement,
|
clearCommandCenterFocusRestoreElement,
|
||||||
takeCommandCenterFocusRestoreElement,
|
takeCommandCenterFocusRestoreElement,
|
||||||
} from "@/utils/command-center-focus-restore";
|
} from "@/utils/command-center-focus-restore";
|
||||||
import { buildHostAgentDetailRoute, buildSettingsRoute } from "@/utils/host-routes";
|
import { buildSettingsRoute } from "@/utils/host-routes";
|
||||||
import type { ShortcutKey } from "@/utils/format-shortcut";
|
import type { ShortcutKey } from "@/utils/format-shortcut";
|
||||||
import { chordStringToShortcutKeys } from "@/keyboard/shortcut-string";
|
import { chordStringToShortcutKeys } from "@/keyboard/shortcut-string";
|
||||||
import { getBindingIdForAction, getDefaultKeysForAction } from "@/keyboard/keyboard-shortcuts";
|
import { getBindingIdForAction, getDefaultKeysForAction } from "@/keyboard/keyboard-shortcuts";
|
||||||
import { useKeyboardShortcutOverrides } from "@/hooks/use-keyboard-shortcut-overrides";
|
import { useKeyboardShortcutOverrides } from "@/hooks/use-keyboard-shortcut-overrides";
|
||||||
import { getShortcutOs } from "@/utils/shortcut-platform";
|
import { getShortcutOs } from "@/utils/shortcut-platform";
|
||||||
import { getIsElectronRuntime } from "@/constants/layout";
|
import { getIsElectronRuntime } from "@/constants/layout";
|
||||||
import { resolveWorkspaceIdByExecutionDirectory } from "@/utils/workspace-execution";
|
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||||
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
|
|
||||||
import { focusWithRetries } from "@/utils/web-focus";
|
import { focusWithRetries } from "@/utils/web-focus";
|
||||||
import { useActiveServerId } from "@/hooks/use-active-server-id";
|
import { useActiveServerId } from "@/hooks/use-active-server-id";
|
||||||
|
|
||||||
@@ -204,18 +202,9 @@ export function useCommandCenter() {
|
|||||||
// Don't restore focus back to the prior element after we navigate.
|
// Don't restore focus back to the prior element after we navigate.
|
||||||
clearCommandCenterFocusRestoreElement();
|
clearCommandCenterFocusRestoreElement();
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
const workspaceId = resolveWorkspaceIdByExecutionDirectory({
|
navigateToAgent({
|
||||||
workspaces: useSessionStore.getState().sessions[agent.serverId]?.workspaces?.values(),
|
|
||||||
workspaceDirectory: agent.cwd,
|
|
||||||
});
|
|
||||||
if (!workspaceId) {
|
|
||||||
router.navigate(buildHostAgentDetailRoute(agent.serverId, agent.id) as Href);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
navigateToPreparedWorkspaceTab({
|
|
||||||
serverId: agent.serverId,
|
serverId: agent.serverId,
|
||||||
workspaceId,
|
agentId: agent.id,
|
||||||
target: { kind: "agent", agentId: agent.id },
|
|
||||||
currentPathname: pathname,
|
currentPathname: pathname,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import type { StreamItem } from "@/types/stream";
|
|||||||
import { getInitDeferred, getInitKey } from "@/utils/agent-initialization";
|
import { getInitDeferred, getInitKey } from "@/utils/agent-initialization";
|
||||||
import { derivePendingPermissionKey, normalizeAgentSnapshot } from "@/utils/agent-snapshots";
|
import { derivePendingPermissionKey, normalizeAgentSnapshot } from "@/utils/agent-snapshots";
|
||||||
import { mergePendingCreateImages } from "@/utils/pending-create-images";
|
import { mergePendingCreateImages } from "@/utils/pending-create-images";
|
||||||
|
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||||
import { deriveSidebarStateBucket } from "@/utils/sidebar-agent-state";
|
import { deriveSidebarStateBucket } from "@/utils/sidebar-agent-state";
|
||||||
|
|
||||||
interface ChatAgentStateShape {
|
interface ChatAgentStateShape {
|
||||||
@@ -1258,14 +1259,14 @@ function ActiveAgentComposer({
|
|||||||
const paneContext = usePaneContext();
|
const paneContext = usePaneContext();
|
||||||
const { workspaceId } = paneContext;
|
const { workspaceId } = paneContext;
|
||||||
const subagentRows = useSubagentsForParent({
|
const subagentRows = useSubagentsForParent({
|
||||||
serverId: paneContext.serverId,
|
serverId,
|
||||||
parentAgentId: agentId,
|
parentAgentId: agentId,
|
||||||
});
|
});
|
||||||
const handleOpenSubagent = useCallback(
|
const handleOpenSubagent = useCallback(
|
||||||
(subagentId: string) => {
|
(subagentId: string) => {
|
||||||
paneContext.openTab({ kind: "agent", agentId: subagentId });
|
navigateToAgent({ serverId, agentId: subagentId });
|
||||||
},
|
},
|
||||||
[paneContext],
|
[serverId],
|
||||||
);
|
);
|
||||||
const handleArchiveSubagent = useArchiveSubagent({ serverId });
|
const handleArchiveSubagent = useArchiveSubagent({ serverId });
|
||||||
const agentInputDraft = useAgentInputDraft({
|
const agentInputDraft = useAgentInputDraft({
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
const { routerMock } = vi.hoisted(() => ({
|
||||||
|
routerMock: {
|
||||||
|
dismissTo: vi.fn(),
|
||||||
|
navigate: vi.fn(),
|
||||||
|
replace: vi.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("expo-router", () => ({
|
||||||
|
router: routerMock,
|
||||||
|
useLocalSearchParams: () => ({}),
|
||||||
|
usePathname: () => "/",
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("@react-native-async-storage/async-storage", () => {
|
||||||
|
const storage = new Map<string, string>();
|
||||||
|
return {
|
||||||
|
default: {
|
||||||
|
getItem: vi.fn(async (key: string) => storage.get(key) ?? null),
|
||||||
|
setItem: vi.fn(async (key: string, value: string) => {
|
||||||
|
storage.set(key, value);
|
||||||
|
}),
|
||||||
|
removeItem: vi.fn(async (key: string) => {
|
||||||
|
storage.delete(key);
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
import type { DaemonClient } from "@server/client/daemon-client";
|
||||||
|
import { useSessionStore, type Agent, type WorkspaceDescriptor } from "@/stores/session-store";
|
||||||
|
import { useWorkspaceLayoutStore } from "@/stores/workspace-layout-store";
|
||||||
|
import { navigateToAgent } from "@/utils/navigate-to-agent";
|
||||||
|
|
||||||
|
const SERVER_ID = "server-1";
|
||||||
|
const WORKSPACE_ID = "workspace-1";
|
||||||
|
const AGENT_ID = "agent-1";
|
||||||
|
|
||||||
|
function createWorkspace(): WorkspaceDescriptor {
|
||||||
|
return {
|
||||||
|
id: WORKSPACE_ID,
|
||||||
|
projectId: "project-1",
|
||||||
|
projectDisplayName: "Project",
|
||||||
|
projectRootPath: "/repo",
|
||||||
|
workspaceDirectory: "/repo/worktree",
|
||||||
|
projectKind: "git",
|
||||||
|
workspaceKind: "local_checkout",
|
||||||
|
name: "worktree",
|
||||||
|
status: "done",
|
||||||
|
archivingAt: null,
|
||||||
|
diffStat: null,
|
||||||
|
scripts: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAgent(input: Partial<Agent> = {}): Agent {
|
||||||
|
return {
|
||||||
|
serverId: SERVER_ID,
|
||||||
|
id: AGENT_ID,
|
||||||
|
provider: "codex",
|
||||||
|
status: "closed",
|
||||||
|
createdAt: new Date("2026-05-09T00:00:00.000Z"),
|
||||||
|
updatedAt: new Date("2026-05-09T00:00:00.000Z"),
|
||||||
|
lastUserMessageAt: null,
|
||||||
|
lastActivityAt: new Date("2026-05-09T00:00:00.000Z"),
|
||||||
|
capabilities: {
|
||||||
|
supportsStreaming: false,
|
||||||
|
supportsSessionPersistence: false,
|
||||||
|
supportsDynamicModes: false,
|
||||||
|
supportsMcpServers: false,
|
||||||
|
supportsReasoningStream: false,
|
||||||
|
supportsToolInvocations: false,
|
||||||
|
},
|
||||||
|
currentModeId: null,
|
||||||
|
availableModes: [],
|
||||||
|
pendingPermissions: [],
|
||||||
|
persistence: null,
|
||||||
|
title: "Archived agent",
|
||||||
|
cwd: "/repo/worktree",
|
||||||
|
model: null,
|
||||||
|
thinkingOptionId: null,
|
||||||
|
archivedAt: new Date("2026-05-09T00:00:00.000Z"),
|
||||||
|
parentAgentId: null,
|
||||||
|
labels: {},
|
||||||
|
...input,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("navigateToAgent", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
routerMock.dismissTo.mockReset();
|
||||||
|
routerMock.navigate.mockReset();
|
||||||
|
routerMock.replace.mockReset();
|
||||||
|
useSessionStore.getState().clearSession(SERVER_ID);
|
||||||
|
useSessionStore.getState().initializeSession(SERVER_ID, null as unknown as DaemonClient);
|
||||||
|
useSessionStore
|
||||||
|
.getState()
|
||||||
|
.setWorkspaces(SERVER_ID, new Map([[WORKSPACE_ID, createWorkspace()]]));
|
||||||
|
useWorkspaceLayoutStore.setState({
|
||||||
|
layoutByWorkspace: {},
|
||||||
|
splitSizesByWorkspace: {},
|
||||||
|
pinnedAgentIdsByWorkspace: {},
|
||||||
|
hiddenAgentIdsByWorkspace: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("opens archived agent details through the resolved workspace", () => {
|
||||||
|
useSessionStore.getState().setAgentDetails(SERVER_ID, new Map([[AGENT_ID, createAgent()]]));
|
||||||
|
|
||||||
|
const route = navigateToAgent({ serverId: SERVER_ID, agentId: AGENT_ID, pin: true });
|
||||||
|
|
||||||
|
expect(route).toBe("/h/server-1/workspace/workspace-1");
|
||||||
|
expect(routerMock.navigate).not.toHaveBeenCalled();
|
||||||
|
expect(routerMock.dismissTo).toHaveBeenCalledWith("/h/server-1/workspace/workspace-1");
|
||||||
|
const key = `${SERVER_ID}:${WORKSPACE_ID}`;
|
||||||
|
expect(useWorkspaceLayoutStore.getState().getWorkspaceTabs(key)).toEqual([
|
||||||
|
expect.objectContaining({ target: { kind: "agent", agentId: AGENT_ID } }),
|
||||||
|
]);
|
||||||
|
expect(useWorkspaceLayoutStore.getState().pinnedAgentIdsByWorkspace[key]).toEqual(
|
||||||
|
new Set([AGENT_ID]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to the host agent route when the workspace is unknown", () => {
|
||||||
|
const route = navigateToAgent({ serverId: SERVER_ID, agentId: "missing-agent" });
|
||||||
|
|
||||||
|
expect(route).toBe("/h/server-1/agent/missing-agent");
|
||||||
|
expect(routerMock.navigate).toHaveBeenCalledWith("/h/server-1/agent/missing-agent");
|
||||||
|
expect(routerMock.dismissTo).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { router, type Href } from "expo-router";
|
||||||
|
import { useSessionStore } from "@/stores/session-store";
|
||||||
|
import { buildHostAgentDetailRoute } from "@/utils/host-routes";
|
||||||
|
import { resolveWorkspaceIdByExecutionDirectory } from "@/utils/workspace-execution";
|
||||||
|
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
|
||||||
|
|
||||||
|
interface NavigateToAgentInput {
|
||||||
|
serverId: string;
|
||||||
|
agentId: string;
|
||||||
|
currentPathname?: string | null;
|
||||||
|
pin?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function navigateToAgent(input: NavigateToAgentInput): string {
|
||||||
|
const session = useSessionStore.getState().sessions[input.serverId];
|
||||||
|
const agent = session?.agents.get(input.agentId) ?? session?.agentDetails.get(input.agentId);
|
||||||
|
const workspaceId = resolveWorkspaceIdByExecutionDirectory({
|
||||||
|
workspaces: session?.workspaces.values(),
|
||||||
|
workspaceDirectory: agent?.cwd,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!workspaceId) {
|
||||||
|
const route = buildHostAgentDetailRoute(input.serverId, input.agentId);
|
||||||
|
router.navigate(route as Href);
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
|
||||||
|
return navigateToPreparedWorkspaceTab({
|
||||||
|
serverId: input.serverId,
|
||||||
|
workspaceId,
|
||||||
|
target: { kind: "agent", agentId: input.agentId },
|
||||||
|
currentPathname: input.currentPathname,
|
||||||
|
pin: input.pin,
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user