Keep forked chats focused in new tabs (#2038)

* fix(app): focus explicitly opened workspace tabs

Explicit tab navigation could be overwritten by attention-aware workspace
navigation when the visible agent had just finished. Make workspace navigation
own both normal attention selection and explicit targets so callers cannot
sequence them inconsistently.

* test(app): strengthen forked tab focus assertion
This commit is contained in:
Mohamed Boudra
2026-07-13 15:38:09 +02:00
committed by GitHub
parent fe9a486ac1
commit f350c716b9
18 changed files with 156 additions and 139 deletions
@@ -2,7 +2,7 @@ import { router, type Href } from "expo-router";
import { useSessionStore } from "@/stores/session-store";
import { getHostRuntimeStore, isHostRuntimeConnected } from "@/runtime/host-runtime";
import { resolveNavigateToAgent, type NavigateToAgentInput } from "./resolve";
import { navigateToPreparedWorkspaceTab } from "@/utils/workspace-navigation";
import { navigateToWorkspace } from "@/stores/navigation-active-workspace-store";
export type { NavigateToAgentInput } from "./resolve";
@@ -69,7 +69,7 @@ export function navigateToAgent(input: NavigateToAgentInput): string {
navigateToHostAgent: (route) => {
router.navigate(route as Href);
},
navigateToPreparedWorkspaceTab,
navigateToWorkspace,
restoreArchivedWorkspace: ({ serverId, agentId, workspaceId }) => {
restoreArchivedWorkspace(serverId, agentId, workspaceId);
},
@@ -4,7 +4,7 @@ import {
type AgentNavTarget,
type NavigateToAgentDeps,
} from "@/utils/navigate-to-agent/resolve";
import type { NavigateToPreparedWorkspaceTabInput } from "@/utils/prepare-workspace-tab";
import type { NavigateToWorkspaceInput } from "@/stores/navigation-active-workspace-store";
const SERVER_ID = "server-1";
const WORKSPACE_ID = "workspace-1";
@@ -14,7 +14,7 @@ interface RecordedHostNav {
route: string;
}
interface RecordedTabNav extends NavigateToPreparedWorkspaceTabInput {}
interface RecordedTabNav extends NavigateToWorkspaceInput {}
interface RecordedRestore {
serverId: string;
@@ -40,7 +40,7 @@ function createFakeNavigators(target: AgentNavTarget): {
navigateToHostAgent: (route) => {
hostNavigations.push({ route });
},
navigateToPreparedWorkspaceTab: (input) => {
navigateToWorkspace: (input) => {
tabNavigations.push(input);
return `/h/${input.serverId}/workspace/${input.workspaceId}`;
},
@@ -1,6 +1,6 @@
import { buildHostAgentDetailRoute } from "@/utils/host-routes";
import { normalizeWorkspaceOpaqueId } from "@/utils/workspace-identity";
import type { NavigateToPreparedWorkspaceTabInput } from "@/utils/prepare-workspace-tab";
import type { NavigateToWorkspaceInput } from "@/stores/navigation-active-workspace-store";
export interface NavigateToAgentInput {
serverId: string;
@@ -18,7 +18,7 @@ export interface AgentNavTarget {
export interface NavigateToAgentDeps {
readAgentNavTarget: (input: { serverId: string; agentId: string }) => AgentNavTarget;
navigateToHostAgent: (route: string) => void;
navigateToPreparedWorkspaceTab: (input: NavigateToPreparedWorkspaceTabInput) => string;
navigateToWorkspace: (input: NavigateToWorkspaceInput) => string;
restoreArchivedWorkspace: (input: {
serverId: string;
agentId: string;
@@ -49,7 +49,7 @@ export function resolveNavigateToAgent(
workspaceId,
});
return deps.navigateToPreparedWorkspaceTab({
return deps.navigateToWorkspace({
serverId: input.serverId,
workspaceId,
target: { kind: "agent", agentId: input.agentId },
@@ -9,8 +9,8 @@ vi.mock("expo-router", () => ({
router: { navigate: vi.fn() },
}));
vi.mock("@/utils/workspace-navigation", () => ({
navigateToPreparedWorkspaceTab: vi.fn(() => ""),
vi.mock("@/stores/navigation-active-workspace-store", () => ({
navigateToWorkspace: vi.fn(() => ""),
}));
vi.mock("@/runtime/host-runtime", () => ({