Add hidden agent tab intent to prevent reconciliation from re-adding closed tabs

When bulk-closing tabs (e.g. "Close to the left"), the reconciliation
useEffect would re-add tabs for still-active agents before the server
archived them, causing tabs to flicker back then disappear one by one.

Adds hiddenAgentIdsByWorkspace as the inverse of pinnedAgentIds: a
local, in-memory-only override that prevents reconciliation from
re-opening tabs for agents the user just closed. Hidden intent is
automatically cleared when explicitly opening, retargeting, or pinning
an agent tab.
This commit is contained in:
Mohamed Boudra
2026-04-12 12:01:14 +07:00
parent dbc525c2ad
commit b9269df3e4
3 changed files with 198 additions and 1 deletions
@@ -224,6 +224,7 @@ describe("workspace-layout-store actions", () => {
layoutByWorkspace: {},
splitSizesByWorkspace: {},
pinnedAgentIdsByWorkspace: {},
hiddenAgentIdsByWorkspace: {},
});
vi.restoreAllMocks();
});
@@ -702,4 +703,80 @@ describe("workspace-layout-store actions", () => {
splitSizesByWorkspace: {},
});
});
it("keeps hidden agent intents 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.hideAgent(workspaceKey, "agent-1");
store.hideAgent(workspaceKey, "agent-1");
store.hideAgent(otherWorkspaceKey as string, "agent-2");
let state = useWorkspaceLayoutStore.getState();
expect(Array.from(state.hiddenAgentIdsByWorkspace[workspaceKey] ?? [])).toEqual(["agent-1"]);
expect(Array.from(state.hiddenAgentIdsByWorkspace[otherWorkspaceKey as string] ?? [])).toEqual([
"agent-2",
]);
store.unhideAgent(workspaceKey, "agent-1");
state = useWorkspaceLayoutStore.getState();
expect(state.hiddenAgentIdsByWorkspace[workspaceKey]).toBeUndefined();
expect(Array.from(state.hiddenAgentIdsByWorkspace[otherWorkspaceKey as string] ?? [])).toEqual([
"agent-2",
]);
const partialize = useWorkspaceLayoutStore.persist.getOptions().partialize;
expect(partialize).toBeTypeOf("function");
expect(partialize?.(state)).toEqual({
layoutByWorkspace: {},
splitSizesByWorkspace: {},
});
});
it("explicitly opening an agent tab clears hidden intent", () => {
const workspaceKey = createWorkspaceKey();
const store = useWorkspaceLayoutStore.getState();
store.hideAgent(workspaceKey, "agent-1");
store.openTab(workspaceKey, { kind: "agent", agentId: "agent-1" });
const state = useWorkspaceLayoutStore.getState();
expect(state.hiddenAgentIdsByWorkspace[workspaceKey]).toBeUndefined();
expect(state.getWorkspaceTabs(workspaceKey).map((tab) => tab.tabId)).toEqual(["agent_agent-1"]);
});
it("pinning an agent clears hidden intent", () => {
const workspaceKey = createWorkspaceKey();
const store = useWorkspaceLayoutStore.getState();
store.hideAgent(workspaceKey, "agent-1");
expect(
useWorkspaceLayoutStore.getState().hiddenAgentIdsByWorkspace[workspaceKey],
).toBeDefined();
store.pinAgent(workspaceKey, "agent-1");
const state = useWorkspaceLayoutStore.getState();
expect(state.hiddenAgentIdsByWorkspace[workspaceKey]).toBeUndefined();
expect(Array.from(state.pinnedAgentIdsByWorkspace[workspaceKey] ?? [])).toEqual(["agent-1"]);
});
it("retargeting a tab to an agent clears hidden intent", () => {
const workspaceKey = createWorkspaceKey();
const store = useWorkspaceLayoutStore.getState();
store.hideAgent(workspaceKey, "agent-1");
const tabId = store.openTab(workspaceKey, { kind: "file", path: "/repo/worktree/a.ts" });
store.retargetTab(workspaceKey, tabId!, { kind: "agent", agentId: "agent-1" });
const state = useWorkspaceLayoutStore.getState();
expect(state.hiddenAgentIdsByWorkspace[workspaceKey]).toBeUndefined();
});
});