diff --git a/desktop/src/components/layout/Sidebar.test.tsx b/desktop/src/components/layout/Sidebar.test.tsx
index 64e3f548..bb4cb2f0 100644
--- a/desktop/src/components/layout/Sidebar.test.tsx
+++ b/desktop/src/components/layout/Sidebar.test.tsx
@@ -293,6 +293,35 @@ describe('Sidebar', () => {
expect(screen.getByRole('button', { name: 'Collapse display' })).toBeInTheDocument()
})
+ it('lets a manual session refresh supersede a stuck automatic refresh', async () => {
+ fetchSessions.mockReturnValue(new Promise(() => {}))
+
+ render()
+
+ await waitFor(() => expect(fetchSessions).toHaveBeenCalledTimes(1))
+ fireEvent.click(screen.getByRole('button', { name: 'Refresh sessions' }))
+
+ await waitFor(() => expect(fetchSessions).toHaveBeenCalledTimes(2))
+ })
+
+ it('keeps the session refresh control usable when a background refresh is still loading existing sessions', async () => {
+ useSessionStore.setState({
+ sessions: [
+ makeSession('session-loaded', 'Loaded session', '/workspace/alpha', '2026-05-15T10:00:00.000Z'),
+ ],
+ isLoading: true,
+ })
+
+ render()
+
+ const refreshButton = screen.getByRole('button', { name: 'Refresh sessions' })
+ expect(refreshButton).not.toBeDisabled()
+ expect(refreshButton.querySelector('svg')).not.toHaveClass('animate-spin')
+
+ fireEvent.click(refreshButton)
+ await waitFor(() => expect(fetchSessions).toHaveBeenCalled())
+ })
+
it('reorders project groups by dragging project headers while preserving expanded state', async () => {
const base = new Date('2026-05-15T10:00:00.000Z').getTime()
useSessionStore.setState({
diff --git a/desktop/src/components/layout/Sidebar.tsx b/desktop/src/components/layout/Sidebar.tsx
index 3dc7ca0a..31e0f92d 100644
--- a/desktop/src/components/layout/Sidebar.tsx
+++ b/desktop/src/components/layout/Sidebar.tsx
@@ -127,6 +127,7 @@ export function Sidebar({ isMobile = false, onRequestClose }: SidebarProps) {
))
}, [hiddenProjectKeys, orderedProjectGroups])
const showInitialLoading = isLoading && sessions.length === 0
+ const showRefreshLoading = showInitialLoading
const filteredSessionIds = useMemo(() => filteredSessions.map((session) => session.id), [filteredSessions])
const selectedCount = selectedSessionIds.size
const sessionsById = useMemo(
@@ -709,12 +710,11 @@ export function Sidebar({ isMobile = false, onRequestClose }: SidebarProps) {