fix(terminal): key project action state by one canonical directory

The terminal store keyed its directories by trimming trailing slashes,
while the new sidebar activity indicator and the whole-server session
grouping keyed the same folder with the project-action normalizer, which
also rewrites backslashes. On Windows that split one project into two
namespaces: the sidebar reconciled server sessions under "C:/repo" while
the terminal panel and the project actions button worked under "C:\repo",
so the running-action indicator never lit up, adopted tabs were duplicated
and a stop recorded in one namespace did not guard reconciliation in the
other. The project actions button also read the store map directly with a
path normalized somewhere else, missing its own directory entry.

All terminal directory keys now come from normalizeTerminalDirectory in
lib/pathNormalization, and store reads go through getDirectoryState.
This commit is contained in:
Bohdan Triapitsyn
2026-09-05 14:48:25 +03:00
parent 74b8c77d49
commit 03e14b61cd
10 changed files with 62 additions and 26 deletions
@@ -602,3 +602,16 @@ test('a listing started before closing an action cannot resurrect its tab', () =
store.reconcileServerSessions('/repo', [session], { startedActionMutationRevisions });
expect(store.getDirectoryState('/repo')?.tabs.some(tab => tab.purpose.type === 'project-action')).toBe(false);
});
test('a Windows directory keys one store entry however the caller spells it', () => {
useTerminalStore.getState().clearAll();
const store = useTerminalStore.getState();
const session: TerminalServerSession = { sessionId: 'run', cwd: 'c:\\repo', status: 'running', createdAt: 1, purpose: { type: 'project-action', actionId: 'dev', executionId: 'run' } };
// The sidebar reconciles from the server's `cwd`; the terminal panel and the
// project actions button pass the directory they were handed.
store.reconcileServerSessions('c:\\repo', [session]);
expect(useTerminalStore.getState().sessions.size).toBe(1);
expect(directoryMayHaveActiveProjectAction(store.getDirectoryState('C:/repo/'))).toBe(true);
expect(store.getDirectoryState('C:\\repo')?.tabs).toHaveLength(1);
});