Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions packages/web-shell/client/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3532,6 +3532,44 @@ describe('App session callbacks', () => {
);
});

it('reports the selected workspace, not the stale connection workspace, when no session is active', async () => {
// A cleared session leaves connection.workspaceCwd pointing at the old
// workspace (here: a secondary with a running task). Starting a new chat
// in the primary must report the primary, not route the host back to the
// stale workspace.
mockConnection.sessionId = undefined;
mockConnection.workspaceCwd = '/work/secondary';
mockWorkspace.capabilities = {
workspaces: [
{ id: 'primary', cwd: '/workspace', primary: true, trusted: true },
{
id: 'secondary',
cwd: '/work/secondary',
primary: false,
trusted: true,
},
],
};
const onSessionIdChange = vi.fn();

renderApp({
onSessionIdChange,
initialSelectedWorkspaceCwd: '/workspace',
});
await flush();

expect(onSessionIdChange).toHaveBeenCalledWith(
undefined,
undefined,
'/workspace',
);
expect(onSessionIdChange).not.toHaveBeenCalledWith(
undefined,
'secondary',
'/work/secondary',
);
});

it('creates scratch once, accepts refreshed capabilities, and opens a fresh chat', async () => {
mockWorkspace.capabilities = {
features: [
Expand Down
17 changes: 13 additions & 4 deletions packages/web-shell/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4619,8 +4619,16 @@ export function App({
lastNotifiedWorkspaceCwdRef.current = undefined;
return;
}
// With no active session (deferred or just cleared) the connection's
// workspaceCwd is a leftover from the previous session — routing the host
// by it would send a "new chat in workspace A" back to the old workspace
// (e.g. one with a running task). The workspace picked for the next
// session is the source of truth in that state.
const reportedWorkspaceCwd = connection.sessionId
? connection.workspaceCwd
: (selectedWorkspaceCwd ?? connection.workspaceCwd);
Comment thread
qwen-code-dev-bot marked this conversation as resolved.
Resolved
const activeWorkspace = workspaces.find(
(entry) => entry.cwd === connection.workspaceCwd,
(entry) => entry.cwd === reportedWorkspaceCwd,
);
if (connection.sessionId && !workspace.capabilities) return;
const workspaceId =
Expand All @@ -4630,23 +4638,24 @@ export function App({
if (
lastNotifiedSessionIdRef.current === connection.sessionId &&
lastNotifiedWorkspaceIdRef.current === workspaceId &&
lastNotifiedWorkspaceCwdRef.current === connection.workspaceCwd
lastNotifiedWorkspaceCwdRef.current === reportedWorkspaceCwd
) {
return;
}
lastNotifiedSessionIdRef.current = connection.sessionId;
lastNotifiedWorkspaceIdRef.current = workspaceId;
lastNotifiedWorkspaceCwdRef.current = connection.workspaceCwd;
lastNotifiedWorkspaceCwdRef.current = reportedWorkspaceCwd;
onSessionIdChange?.(
connection.sessionId,
workspaceId,
connection.workspaceCwd,
reportedWorkspaceCwd,
);
}, [
connection.missingSession,
connection.sessionId,
connection.workspaceCwd,
onSessionIdChange,
selectedWorkspaceCwd,
workspace.capabilities,
workspaces,
]);
Expand Down
Loading