fix(app): open new tabs in the focused pane

Preserve ambient placement for reconciliation and background opens while routing user-directed tab creation through the focused visible pane. Defer terminal reconciliation during creates so a push cannot preempt the intended pane placement.
This commit is contained in:
Mohamed Boudra
2026-08-19 15:52:51 +02:00
parent 133c38c5c3
commit ce905d9483
12 changed files with 267 additions and 51 deletions
@@ -0,0 +1,33 @@
import { expect, test } from "../support/fixtures";
import { gotoWorkspace, pressDirectNewTabShortcut } from "../support/helpers/launcher";
import { seedWorkspace } from "../support/helpers/seed-client";
import { openChangesPanel, waitForWorkspaceTabsVisible } from "../support/helpers/workspace-tabs";
test.describe("Direct terminal shortcut pane placement", () => {
test("opens a terminal in the focused pane", async ({ page }) => {
const workspace = await seedWorkspace({ repoPrefix: "direct-terminal-shortcut-pane-" });
try {
await gotoWorkspace(page, workspace.workspaceId);
await waitForWorkspaceTabsVisible(page);
await openChangesPanel(page);
const focusedPane = page
.getByTestId("workspace-tabs-row")
.filter({ has: page.getByTestId("workspace-tab-working_diff") })
.first();
const primaryPane = page
.getByTestId("workspace-tabs-row")
.filter({ hasNot: page.getByTestId("workspace-tab-working_diff") })
.first();
await pressDirectNewTabShortcut(page, "t");
await expect(focusedPane.locator('[data-testid^="workspace-tab-terminal_"]')).toHaveCount(1, {
timeout: 30_000,
});
await expect(primaryPane.locator('[data-testid^="workspace-tab-terminal_"]')).toHaveCount(0);
} finally {
await workspace.cleanup();
}
});
});
@@ -132,7 +132,7 @@ export function useWorkspaceFileSearch(input: { enabled: boolean; query: string
filePath: path,
persistenceKey: buildWorkspaceTabPersistenceKey({ serverId, workspaceId }),
showMobileAgent: usePanelStore.getState().showMobileAgent,
openWorkspaceTabFocused: useWorkspaceLayoutStore.getState().openTabFocused,
openWorkspaceTabInFocusedPane: useWorkspaceLayoutStore.getState().openTabInFocusedPane,
focusWorkspaceTab: useWorkspaceLayoutStore.getState().focusTab,
});
},
@@ -101,7 +101,9 @@ export function CompactExplorerSidebarHost({ children, enabled }: CompactExplore
const model = useActiveCompactExplorerSidebarModel(enabled);
const openFileExplorerForCheckout = usePanelStore((state) => state.openFileExplorerForCheckout);
const showMobileAgent = usePanelStore((state) => state.showMobileAgent);
const openWorkspaceTabFocused = useWorkspaceLayoutStore((state) => state.openTabFocused);
const openWorkspaceTabInFocusedPane = useWorkspaceLayoutStore(
(state) => state.openTabInFocusedPane,
);
const focusWorkspaceTab = useWorkspaceLayoutStore((state) => state.focusTab);
const handleOpenExplorer = useCallback(() => {
@@ -127,11 +129,11 @@ export function CompactExplorerSidebarHost({ children, enabled }: CompactExplore
filePath,
persistenceKey: model.persistenceKey,
showMobileAgent,
openWorkspaceTabFocused,
openWorkspaceTabInFocusedPane,
focusWorkspaceTab,
});
},
[focusWorkspaceTab, model, openWorkspaceTabFocused, showMobileAgent],
[focusWorkspaceTab, model, openWorkspaceTabInFocusedPane, showMobileAgent],
);
return (
+7 -5
View File
@@ -1019,7 +1019,9 @@ function useDiffTabNavigation({
cwd: string;
isMobile: boolean;
}) {
const openWorkspaceTabFocused = useWorkspaceLayoutStore((state) => state.openTabFocused);
const openWorkspaceTabInFocusedPane = useWorkspaceLayoutStore(
(state) => state.openTabInFocusedPane,
);
const closeWorkspaceTab = useWorkspaceLayoutStore((state) => state.closeTab);
const persistenceKey = useMemo(
() => buildWorkspaceTabPersistenceKey({ serverId, workspaceId: workspaceId ?? cwd }),
@@ -1040,12 +1042,12 @@ function useDiffTabNavigation({
if (!persistenceKey || isMobile) {
return;
}
openWorkspaceTabFocused(persistenceKey, {
openWorkspaceTabInFocusedPane(persistenceKey, {
kind: "working_diff",
...(path ? { focusPath: path, focusRequestId: Date.now() } : {}),
});
},
[isMobile, openWorkspaceTabFocused, persistenceKey],
[isMobile, openWorkspaceTabInFocusedPane, persistenceKey],
);
const toggleChanges = useCallback(() => {
if (!persistenceKey || isMobile) {
@@ -1060,10 +1062,10 @@ function useDiffTabNavigation({
const openCommit = useCallback(
(sha: string) => {
if (persistenceKey) {
openWorkspaceTabFocused(persistenceKey, { kind: "commit_diff", sha });
openWorkspaceTabInFocusedPane(persistenceKey, { kind: "commit_diff", sha });
}
},
[openWorkspaceTabFocused, persistenceKey],
[openWorkspaceTabInFocusedPane, persistenceKey],
);
return {
changesTabOpen,
@@ -8,7 +8,10 @@ interface OpenWorkspaceFileFromExplorerInput {
filePath: string;
persistenceKey: string | null;
showMobileAgent: () => void;
openWorkspaceTabFocused: (workspaceKey: string, target: WorkspaceTabTarget) => string | null;
openWorkspaceTabInFocusedPane: (
workspaceKey: string,
target: WorkspaceTabTarget,
) => string | null;
focusWorkspaceTab: (workspaceKey: string, tabId: string) => void;
}
@@ -21,7 +24,7 @@ export function openWorkspaceFileFromExplorer(input: OpenWorkspaceFileFromExplor
if (!location) {
return;
}
const tabId = input.openWorkspaceTabFocused(
const tabId = input.openWorkspaceTabInFocusedPane(
input.persistenceKey,
createWorkspaceFileTabTarget(location),
);
@@ -1466,6 +1466,10 @@ interface WorkspaceTerminalTabActionsInput {
target: WorkspaceTabTarget,
options?: WorkspaceTabOpenOptions,
) => string | null;
openWorkspaceTabInFocusedPane: (
workspaceKey: string,
target: WorkspaceTabTarget,
) => string | null;
labels: {
workspacePathUnavailable: string;
terminalQueued: string;
@@ -1487,6 +1491,7 @@ interface WorkspaceTerminalTabActions {
function useWorkspaceTerminalTabActions({
persistenceKey,
openWorkspaceTabFocused,
openWorkspaceTabInFocusedPane,
labels,
toast,
}: WorkspaceTerminalTabActionsInput): WorkspaceTerminalTabActions {
@@ -1495,18 +1500,22 @@ function useWorkspaceTerminalTabActions({
if (!persistenceKey) {
return;
}
openWorkspaceTabFocused(persistenceKey, { kind: "terminal", terminalId }, { paneId });
if (paneId) {
openWorkspaceTabFocused(persistenceKey, { kind: "terminal", terminalId }, { paneId });
} else {
openWorkspaceTabInFocusedPane(persistenceKey, { kind: "terminal", terminalId });
}
},
[openWorkspaceTabFocused, persistenceKey],
[openWorkspaceTabFocused, openWorkspaceTabInFocusedPane, persistenceKey],
);
const handleScriptTerminalSelected = useCallback(
(terminalId: string) => {
if (!persistenceKey) {
return;
}
openWorkspaceTabFocused(persistenceKey, { kind: "terminal", terminalId });
openWorkspaceTabInFocusedPane(persistenceKey, { kind: "terminal", terminalId });
},
[openWorkspaceTabFocused, persistenceKey],
[openWorkspaceTabInFocusedPane, persistenceKey],
);
const handleWorkspacePathUnavailable = useCallback(() => {
toast.error(labels.workspacePathUnavailable);
@@ -1608,9 +1617,15 @@ function WorkspaceScreenContent({
[normalizedServerId, normalizedWorkspaceId],
);
const openWorkspaceTabFocused = useWorkspaceLayoutStore((state) => state.openTabFocused);
const openWorkspaceTabInFocusedPane = useWorkspaceLayoutStore(
(state) => state.openTabInFocusedPane,
);
const openWorkspaceChildTabFocused = useWorkspaceLayoutStore(
(state) => state.openChildTabFocused,
);
const openWorkspaceChildTabInFocusedPane = useWorkspaceLayoutStore(
(state) => state.openChildTabInFocusedPane,
);
// File targets stay identity-stable so the same path reuses its tab. Keep navigation
// requests separate so clicking an unchanged path:line can still recenter the pane.
const [fileNavigationRevisionByTabId, setFileNavigationRevisionByTabId] = useState<
@@ -1657,6 +1672,7 @@ function WorkspaceScreenContent({
} = useWorkspaceTerminalTabActions({
persistenceKey,
openWorkspaceTabFocused,
openWorkspaceTabInFocusedPane,
labels: {
workspacePathUnavailable: t("workspace.header.toasts.workspacePathUnavailable"),
terminalQueued: t("workspace.header.toasts.terminalQueued"),
@@ -1951,6 +1967,7 @@ function WorkspaceScreenContent({
const openWorkspaceDraftTab = useCallback(
function openWorkspaceDraftTab(input?: {
ambient?: boolean;
draftId?: string;
focus?: boolean;
paneId?: string | null;
@@ -1964,13 +1981,25 @@ function WorkspaceScreenContent({
draftId: trimNonEmpty(input?.draftId) ?? generateDraftId(),
});
invariant(target?.kind === "draft", "Draft tab target must be valid");
const placement = { paneId: input?.paneId };
if (input?.focus === false) {
return openWorkspaceTabInBackground(persistenceKey, target, placement);
if (input?.ambient) {
return openWorkspaceTabFocused(persistenceKey, target);
}
return openWorkspaceTabFocused(persistenceKey, target, placement);
if (input?.focus === false) {
return openWorkspaceTabInBackground(persistenceKey, target, {
paneId: input?.paneId,
});
}
if (input?.paneId) {
return openWorkspaceTabFocused(persistenceKey, target, { paneId: input.paneId });
}
return openWorkspaceTabInFocusedPane(persistenceKey, target);
},
[openWorkspaceTabFocused, openWorkspaceTabInBackground, persistenceKey],
[
openWorkspaceTabFocused,
openWorkspaceTabInBackground,
openWorkspaceTabInFocusedPane,
persistenceKey,
],
);
useEffect(() => {
@@ -2000,12 +2029,16 @@ function WorkspaceScreenContent({
terminalsHydrated: terminalsQuery.isSuccess,
knownTerminalIds,
standaloneTerminalIds,
hasActivePendingTerminalCreate:
createTerminalMutation.isPending || pendingTerminalCreateInput !== null,
hasActivePendingDraftCreate: hasActivePendingDraftCreateInWorkspace,
}),
);
}, [
hasHydratedAgents,
hasHydratedWorkspaceLayoutStore,
pendingTerminalCreateInput,
createTerminalMutation.isPending,
isRouteFocused,
normalizedServerId,
normalizedWorkspaceId,
@@ -2047,12 +2080,12 @@ function WorkspaceScreenContent({
if (!persistenceKey) {
return;
}
const tabId = openWorkspaceTabFocused(persistenceKey, { kind: "agent", agentId });
const tabId = openWorkspaceTabInFocusedPane(persistenceKey, { kind: "agent", agentId });
if (tabId) {
navigateToTabId(tabId);
}
},
[navigateToTabId, openWorkspaceTabFocused, persistenceKey],
[navigateToTabId, openWorkspaceTabInFocusedPane, persistenceKey],
);
const emptyWorkspaceSeedRef = useRef<string | null>(null);
@@ -2155,7 +2188,7 @@ function WorkspaceScreenContent({
return;
}
emptyWorkspaceSeedRef.current = workspaceKey;
openWorkspaceDraftTab();
openWorkspaceDraftTab({ ambient: true });
}, [
normalizedServerId,
normalizedWorkspaceId,
@@ -2180,12 +2213,15 @@ function WorkspaceScreenContent({
if (!location) {
return;
}
const tabId = openWorkspaceTabFocused(persistenceKey, createWorkspaceFileTabTarget(location));
const tabId = openWorkspaceTabInFocusedPane(
persistenceKey,
createWorkspaceFileTabTarget(location),
);
if (tabId) {
navigateToTabId(tabId);
}
},
[navigateToTabId, openWorkspaceTabFocused, persistenceKey],
[navigateToTabId, openWorkspaceTabInFocusedPane, persistenceKey],
);
const handleOpenFileFromChat = useCallback(
@@ -2202,8 +2238,8 @@ function WorkspaceScreenContent({
}
const target = createWorkspaceFileTabTarget(normalizedLocation);
const tabId = options?.parentTabId
? openWorkspaceChildTabFocused(persistenceKey, target, options.parentTabId)
: openWorkspaceTabFocused(persistenceKey, target);
? openWorkspaceChildTabInFocusedPane(persistenceKey, target, options.parentTabId)
: openWorkspaceTabInFocusedPane(persistenceKey, target);
if (tabId) {
requestFileNavigation(tabId);
navigateToTabId(tabId);
@@ -2212,8 +2248,8 @@ function WorkspaceScreenContent({
[
isMobile,
navigateToTabId,
openWorkspaceChildTabFocused,
openWorkspaceTabFocused,
openWorkspaceChildTabInFocusedPane,
openWorkspaceTabInFocusedPane,
persistenceKey,
requestFileNavigation,
showMobileAgent,
@@ -2379,13 +2415,19 @@ function WorkspaceScreenContent({
return;
}
const { browserId } = createWorkspaceBrowser();
openWorkspaceTabFocused(
persistenceKey,
{ kind: "browser", browserId },
{ paneId: input?.paneId },
);
if (input?.paneId) {
openWorkspaceTabFocused(
persistenceKey,
{ kind: "browser", browserId },
{
paneId: input.paneId,
},
);
} else {
openWorkspaceTabInFocusedPane(persistenceKey, { kind: "browser", browserId });
}
},
[openWorkspaceTabFocused, persistenceKey],
[openWorkspaceTabFocused, openWorkspaceTabInFocusedPane, persistenceKey],
);
const handleOpenUrlInBrowserTab = useCallback(
@@ -2746,14 +2788,14 @@ function WorkspaceScreenContent({
return;
}
if (isMobile || !supportsDesktopPaneSplits()) {
openWorkspaceTabFocused(persistenceKey, target);
openWorkspaceTabInFocusedPane(persistenceKey, target);
return;
}
openWorkspaceTabInExplorerPaneFocused(persistenceKey, { target });
}, [
isMobile,
normalizedWorkspaceId,
openWorkspaceTabFocused,
openWorkspaceTabInFocusedPane,
openWorkspaceTabInExplorerPaneFocused,
persistenceKey,
]);
@@ -213,6 +213,7 @@ export interface WorkspaceTabSnapshot {
knownAgentIds: Iterable<string>;
knownTerminalIds?: Iterable<string>;
standaloneTerminalIds: Iterable<string>;
hasActivePendingTerminalCreate?: boolean;
hasActivePendingDraftCreate?: boolean;
}
@@ -1866,6 +1867,7 @@ function addMissingEntityTabs(input: {
autoOpenAgentIds: Set<string>;
representedAgentIds: Set<string>;
standaloneTerminalIds: Set<string>;
hasActivePendingTerminalCreate: boolean;
hasActivePendingDraftCreate: boolean;
explorerPaneId: string | null;
}): WorkspaceLayout {
@@ -1873,6 +1875,7 @@ function addMissingEntityTabs(input: {
autoOpenAgentIds,
representedAgentIds,
standaloneTerminalIds,
hasActivePendingTerminalCreate,
hasActivePendingDraftCreate,
explorerPaneId,
} = input;
@@ -1902,16 +1905,18 @@ function addMissingEntityTabs(input: {
}
const sortedTerminalIds = [...standaloneTerminalIds].sort();
for (const terminalId of sortedTerminalIds) {
if (currentTerminalIds.has(terminalId)) {
continue;
if (!hasActivePendingTerminalCreate) {
for (const terminalId of sortedTerminalIds) {
if (currentTerminalIds.has(terminalId)) {
continue;
}
nextLayout = openEntityTabWithoutFocusing({
layout: nextLayout,
target: { kind: "terminal", terminalId },
explorerPaneId,
});
currentTerminalIds.add(terminalId);
}
nextLayout = openEntityTabWithoutFocusing({
layout: nextLayout,
target: { kind: "terminal", terminalId },
explorerPaneId,
});
currentTerminalIds.add(terminalId);
}
return nextLayout;
}
@@ -1999,6 +2004,7 @@ export function reconcileWorkspaceTabs(
autoOpenAgentIds: autoOpenSet,
representedAgentIds,
standaloneTerminalIds,
hasActivePendingTerminalCreate: snapshot.hasActivePendingTerminalCreate ?? false,
hasActivePendingDraftCreate: snapshot.hasActivePendingDraftCreate ?? false,
explorerPaneId: state.explorerPaneId,
});
@@ -585,6 +585,35 @@ describe("workspace-layout-store actions", () => {
expect(layout.focusedPaneId).toBe("explorer");
});
it("keeps ambient browser opens out of the focused explorer pane", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
store.openTabFocused(workspaceKey, { kind: "browser", browserId: "browser-1" });
store.focusPane(workspaceKey, "explorer");
const browserTabId = store.openTabFocused(workspaceKey, {
kind: "browser",
browserId: "browser-2",
});
const layout = workspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
expect(findPaneContainingTab(layout.root, browserTabId as string)?.id).toBe("main");
expect(layout.focusedPaneId).toBe("main");
});
it("keeps ambient draft opens out of the focused explorer pane", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
store.openTabFocused(workspaceKey, { kind: "agent", agentId: "agent-1" });
store.focusPane(workspaceKey, "explorer");
const draftTabId = store.openTabFocused(workspaceKey, { kind: "draft", draftId: "draft-1" });
const layout = workspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
expect(findPaneContainingTab(layout.root, draftTabId as string)?.id).toBe("main");
expect(layout.focusedPaneId).toBe("main");
});
it("honours an explicit pane id over the explorer reroute", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
@@ -601,6 +630,76 @@ describe("workspace-layout-store actions", () => {
expect(layout.focusedPaneId).toBe("explorer");
});
it("opens user-created entity tabs in the focused explorer pane", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
store.openTabFocused(workspaceKey, { kind: "agent", agentId: "agent-1" });
store.focusPane(workspaceKey, "explorer");
const terminalTabId = store.openTabInFocusedPane(workspaceKey, {
kind: "terminal",
terminalId: "terminal-1",
});
const layout = workspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
expect(findPaneContainingTab(layout.root, terminalTabId as string)?.id).toBe("explorer");
expect(layout.focusedPaneId).toBe("explorer");
});
it("keeps an existing user-created entity tab in its original pane", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
const terminalTabId = store.openTabInBackground(workspaceKey, {
kind: "terminal",
terminalId: "terminal-1",
});
store.showPane(workspaceKey, "explorer");
store.focusPane(workspaceKey, "explorer");
store.openTabInFocusedPane(workspaceKey, {
kind: "terminal",
terminalId: "terminal-1",
});
const layout = workspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
expect(findPaneContainingTab(layout.root, terminalTabId as string)?.id).toBe("main");
expect(findPaneById(layout.root, "main")).toBeTruthy();
expect(layout.focusedPaneId).toBe("main");
});
it("defers terminal reconciliation while a user terminal is being created", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
store.focusPane(workspaceKey, "explorer");
store.reconcileTabs(workspaceKey, {
agentsHydrated: true,
terminalsHydrated: true,
activeAgentIds: [],
autoOpenAgentIds: [],
knownAgentIds: [],
knownTerminalIds: ["terminal-1"],
standaloneTerminalIds: ["terminal-1"],
hasActivePendingTerminalCreate: true,
});
let layout = workspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
expect(findPaneContainingTab(layout.root, "terminal_terminal-1")).toBeNull();
store.reconcileTabs(workspaceKey, {
agentsHydrated: true,
terminalsHydrated: true,
activeAgentIds: [],
autoOpenAgentIds: [],
knownAgentIds: [],
knownTerminalIds: ["terminal-1"],
standaloneTerminalIds: ["terminal-1"],
});
layout = workspaceLayoutStore.getState().layoutByWorkspace[workspaceKey];
expect(findPaneContainingTab(layout.root, "terminal_terminal-1")?.id).toBe("main");
});
it("keeps non-entity tabs in the focused explorer pane", () => {
const workspaceKey = createWorkspaceKey();
const store = workspaceLayoutStore.getState();
@@ -86,12 +86,18 @@ interface WorkspaceLayoutStore {
target: WorkspaceTabTarget,
options?: WorkspaceTabOpenOptions,
) => string | null;
openTabInFocusedPane: (workspaceKey: string, target: WorkspaceTabTarget) => string | null;
openChildTabFocused: (
workspaceKey: string,
target: WorkspaceTabTarget,
parentTabId: string,
options?: WorkspaceTabOpenOptions,
) => string | null;
openChildTabInFocusedPane: (
workspaceKey: string,
target: WorkspaceTabTarget,
parentTabId: string,
) => string | null;
openTabInBackground: (
workspaceKey: string,
target: WorkspaceTabTarget,
@@ -146,11 +152,7 @@ interface WorkspaceLayoutStore {
purgeWorkspace: (workspaceKey: string) => void;
}
/**
* `paneId` states which pane the user acted in — the `+` menu of a pane's tab rail,
* a subagent link inside a pane. Without it the open is ambient (sidebar click,
* reconcile auto-open) and the store decides the pane.
*/
/** `paneId` is explicit placement for a pane-local affordance; omitted opens use policy. */
export interface WorkspaceTabOpenOptions {
paneId?: string | null;
}
@@ -463,6 +465,17 @@ export function createWorkspaceLayoutStore(
return result.tabId;
},
openTabInFocusedPane: (workspaceKey, target) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
if (!normalizedWorkspaceKey) {
return null;
}
const layout = getWorkspaceLayout(get().layoutByWorkspace, normalizedWorkspaceKey);
const focusedPane = findPaneById(layout.root, layout.focusedPaneId);
return get().openTabFocused(normalizedWorkspaceKey, target, {
paneId: focusedPane?.hidden === true ? null : focusedPane?.id,
});
},
openChildTabFocused: (workspaceKey, target, parentTabId, options) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
const normalizedParentTabId = trimNonEmpty(parentTabId);
@@ -502,6 +515,17 @@ export function createWorkspaceLayoutStore(
return result.tabId;
},
openChildTabInFocusedPane: (workspaceKey, target, parentTabId) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
if (!normalizedWorkspaceKey) {
return null;
}
const layout = getWorkspaceLayout(get().layoutByWorkspace, normalizedWorkspaceKey);
const focusedPane = findPaneById(layout.root, layout.focusedPaneId);
return get().openChildTabFocused(normalizedWorkspaceKey, target, parentTabId, {
paneId: focusedPane?.hidden === true ? null : focusedPane?.id,
});
},
openTabInBackground: (workspaceKey, target, options) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
const normalizedTarget = normalizeWorkspaceTabTarget(target);
@@ -108,6 +108,7 @@ function reconcileWorkspaceTabs(workspaceKey: string, visibility: WorkspaceAgent
terminalsHydrated: true,
knownTerminalIds: [],
standaloneTerminalIds: [],
hasActivePendingTerminalCreate: false,
hasActivePendingDraftCreate: false,
}),
);
@@ -333,6 +333,7 @@ describe("workspace agent visibility", () => {
terminalsHydrated: true,
knownTerminalIds: ["terminal-1", "script-terminal"],
standaloneTerminalIds: ["terminal-1"],
hasActivePendingTerminalCreate: false,
hasActivePendingDraftCreate: false,
}),
).toEqual({
@@ -343,6 +344,7 @@ describe("workspace agent visibility", () => {
knownAgentIds: agentVisibility.knownAgentIds,
knownTerminalIds: ["terminal-1", "script-terminal"],
standaloneTerminalIds: ["terminal-1"],
hasActivePendingTerminalCreate: false,
hasActivePendingDraftCreate: false,
});
});
@@ -64,6 +64,7 @@ export function buildWorkspaceTabSnapshot(input: {
terminalsHydrated: boolean;
knownTerminalIds: Iterable<string>;
standaloneTerminalIds: Iterable<string>;
hasActivePendingTerminalCreate: boolean;
hasActivePendingDraftCreate: boolean;
}): WorkspaceTabSnapshot {
return {
@@ -74,6 +75,7 @@ export function buildWorkspaceTabSnapshot(input: {
knownAgentIds: input.agentVisibility.knownAgentIds,
knownTerminalIds: input.knownTerminalIds,
standaloneTerminalIds: input.standaloneTerminalIds,
hasActivePendingTerminalCreate: input.hasActivePendingTerminalCreate,
hasActivePendingDraftCreate: input.hasActivePendingDraftCreate,
};
}