fix(server): harden worktree archive with parallel teardown

Fan out agent close + terminal kill concurrently with Promise.allSettled
so one failure never leaves the worktree half-dead. Await real PTY exit
with SIGHUP→SIGKILL escalation before rm to avoid EBUSY races. Tolerate
missing repoRoot and retry directory removal with backoff. Purge stale
client workspace layout/tab state after successful archive.
This commit is contained in:
Mohamed Boudra
2026-04-17 15:50:48 +07:00
parent ed2dc08443
commit d6585f7c3a
9 changed files with 537 additions and 65 deletions
@@ -99,6 +99,7 @@ interface WorkspaceLayoutStore {
unpinAgent: (workspaceKey: string, agentId: string) => void;
hideAgent: (workspaceKey: string, agentId: string) => void;
unhideAgent: (workspaceKey: string, agentId: string) => void;
purgeWorkspace: (workspaceKey: string) => void;
}
const MAX_TREE_DEPTH = 4;
@@ -669,6 +670,37 @@ export const useWorkspaceLayoutStore = create<WorkspaceLayoutStore>()(
};
});
},
purgeWorkspace: (workspaceKey) => {
const normalizedWorkspaceKey = trimNonEmpty(workspaceKey);
if (!normalizedWorkspaceKey) {
return;
}
set((state) => {
const hasAny =
normalizedWorkspaceKey in state.layoutByWorkspace ||
normalizedWorkspaceKey in state.splitSizesByWorkspace ||
normalizedWorkspaceKey in state.pinnedAgentIdsByWorkspace ||
normalizedWorkspaceKey in state.hiddenAgentIdsByWorkspace;
if (!hasAny) {
return state;
}
const { [normalizedWorkspaceKey]: _layout, ...layoutByWorkspace } =
state.layoutByWorkspace;
const { [normalizedWorkspaceKey]: _splits, ...splitSizesByWorkspace } =
state.splitSizesByWorkspace;
const { [normalizedWorkspaceKey]: _pinned, ...pinnedAgentIdsByWorkspace } =
state.pinnedAgentIdsByWorkspace;
const { [normalizedWorkspaceKey]: _hidden, ...hiddenAgentIdsByWorkspace } =
state.hiddenAgentIdsByWorkspace;
return {
layoutByWorkspace,
splitSizesByWorkspace,
pinnedAgentIdsByWorkspace,
hiddenAgentIdsByWorkspace,
};
});
},
}),
{
name: "workspace-layout-state",