Keep explicitly reopened archived agent tabs open

This commit is contained in:
Mohamed Boudra
2026-03-21 13:01:23 +07:00
parent ee5577c2da
commit a042fbbe43
3 changed files with 188 additions and 16 deletions
@@ -218,7 +218,11 @@ describe("workspace-layout-store tree transforms", () => {
describe("workspace-layout-store actions", () => {
beforeEach(() => {
useWorkspaceLayoutStore.setState({ layoutByWorkspace: {} });
useWorkspaceLayoutStore.setState({
layoutByWorkspace: {},
splitSizesByWorkspace: {},
pinnedAgentIdsByWorkspace: {},
});
vi.restoreAllMocks();
});
@@ -634,4 +638,40 @@ describe("workspace-layout-store actions", () => {
expect(layout).toEqual(createDefaultLayout());
});
it("keeps pinned archived agents in memory per workspace without persisting them", () => {
const workspaceKey = createWorkspaceKey();
const otherWorkspaceKey = buildWorkspaceTabPersistenceKey({
serverId: SERVER_ID,
workspaceId: "/repo/other-worktree",
});
expect(otherWorkspaceKey).toBeTruthy();
const store = useWorkspaceLayoutStore.getState();
store.pinAgent(workspaceKey, "agent-1");
store.pinAgent(workspaceKey, "agent-1");
store.pinAgent(otherWorkspaceKey as string, "agent-2");
let state = useWorkspaceLayoutStore.getState();
expect(Array.from(state.pinnedAgentIdsByWorkspace[workspaceKey] ?? [])).toEqual(["agent-1"]);
expect(Array.from(state.pinnedAgentIdsByWorkspace[otherWorkspaceKey as string] ?? [])).toEqual([
"agent-2",
]);
store.unpinAgent(workspaceKey, "agent-1");
state = useWorkspaceLayoutStore.getState();
expect(state.pinnedAgentIdsByWorkspace[workspaceKey]).toBeUndefined();
expect(Array.from(state.pinnedAgentIdsByWorkspace[otherWorkspaceKey as string] ?? [])).toEqual([
"agent-2",
]);
const partialize = useWorkspaceLayoutStore.persist.getOptions().partialize;
expect(partialize).toBeTypeOf("function");
expect(partialize?.(state)).toEqual({
layoutByWorkspace: {},
splitSizesByWorkspace: {},
});
});
});
@@ -53,6 +53,7 @@ export type { SplitGroup, SplitNode, SplitPane, WorkspaceLayout };
interface WorkspaceLayoutStore {
layoutByWorkspace: Record<string, WorkspaceLayout>;
splitSizesByWorkspace: Record<string, Record<string, number[]>>;
pinnedAgentIdsByWorkspace: Record<string, Set<string>>;
openTab: (workspaceKey: string, target: WorkspaceTabTarget) => string | null;
closeTab: (workspaceKey: string, tabId: string) => void;
focusTab: (workspaceKey: string, tabId: string) => void;
@@ -78,6 +79,8 @@ interface WorkspaceLayoutStore {
focusPane: (workspaceKey: string, paneId: string) => void;
resizeSplit: (workspaceKey: string, groupId: string, sizes: number[]) => void;
reorderTabsInPane: (workspaceKey: string, paneId: string, tabIds: string[]) => void;
pinAgent: (workspaceKey: string, agentId: string) => void;
unpinAgent: (workspaceKey: string, agentId: string) => void;
}
const MAX_TREE_DEPTH = 4;
@@ -99,6 +102,7 @@ export const useWorkspaceLayoutStore = create<WorkspaceLayoutStore>()(
(set, get) => ({
layoutByWorkspace: {},
splitSizesByWorkspace: {},
pinnedAgentIdsByWorkspace: {},
openTab: (workspaceKey, target) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
const normalizedTarget = normalizeWorkspaceTabTarget(target);
@@ -385,6 +389,66 @@ export const useWorkspaceLayoutStore = create<WorkspaceLayoutStore>()(
};
});
},
pinAgent: (workspaceKey, agentId) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
const normalizedAgentId = trimNonEmpty(agentId);
if (!normalizedWorkspaceKey || !normalizedAgentId) {
return;
}
set((state) => {
const currentPinnedAgentIds =
state.pinnedAgentIdsByWorkspace[normalizedWorkspaceKey] ?? null;
if (currentPinnedAgentIds?.has(normalizedAgentId)) {
return state;
}
const nextPinnedAgentIds = new Set(currentPinnedAgentIds ?? []);
nextPinnedAgentIds.add(normalizedAgentId);
return {
pinnedAgentIdsByWorkspace: {
...state.pinnedAgentIdsByWorkspace,
[normalizedWorkspaceKey]: nextPinnedAgentIds,
},
};
});
},
unpinAgent: (workspaceKey, agentId) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
const normalizedAgentId = trimNonEmpty(agentId);
if (!normalizedWorkspaceKey || !normalizedAgentId) {
return;
}
set((state) => {
const currentPinnedAgentIds =
state.pinnedAgentIdsByWorkspace[normalizedWorkspaceKey] ?? null;
if (!currentPinnedAgentIds?.has(normalizedAgentId)) {
return state;
}
if (currentPinnedAgentIds.size === 1) {
const nextPinnedAgentIdsByWorkspace = {
...state.pinnedAgentIdsByWorkspace,
};
delete nextPinnedAgentIdsByWorkspace[normalizedWorkspaceKey];
return {
pinnedAgentIdsByWorkspace: nextPinnedAgentIdsByWorkspace,
};
}
const nextPinnedAgentIds = new Set(currentPinnedAgentIds);
nextPinnedAgentIds.delete(normalizedAgentId);
return {
pinnedAgentIdsByWorkspace: {
...state.pinnedAgentIdsByWorkspace,
[normalizedWorkspaceKey]: nextPinnedAgentIds,
},
};
});
},
}),
{
name: "workspace-layout-state",