-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Description
Bug Description
When connecting OpenCode Desktop to multiple servers (local sidecar + remote opencode serve), switching between them leaves stale state from the previous server in persisted layout storage. This causes a "Session not found" polling loop when the Desktop tries to restore sessions that only exist on the other server.
Reproduction Steps
- Run
opencode serveon a remote machine (e.g.http://remote:8472) - In OpenCode Desktop, add the remote server via the server picker
- Switch to the remote server — open some projects, navigate to sessions
- Switch back to local sidecar
- Observe:
ERROR service=server error=Session not found failedrepeats every ~4 seconds in the sidecar log - Error notifications accumulate with red badges on projects
Root Cause
Three pieces of persisted state in global.dat are keyed by directory path only, not by server origin + directory path:
1. lastProjectSession (packages/app/src/pages/layout.tsx:96-108)
// layout.page.v1 — global, not per-server
lastProjectSession: {} as { [directory: string]: { directory: string; id: string; at: number } }rememberSessionRoute() (line 1189) stores session IDs keyed by directory. When switching servers, the previous server's session IDs remain. On return to local, navigateToProject() (line 1215) tries to restore these sessions via openSession() (line 1236) — fails because the session ID belongs to the remote server's database.
2. sidebar.workspaces (packages/app/src/pages/layout.tsx:227-261)
// layout.v6 — global, not per-server
sidebar: {
workspaces: {} as Record<string, boolean>, // keyed by directory path
}Remote server workspace paths (e.g. /Users/remote-user/repos/project) persist in the sidebar layout after switching back to local. The Desktop then tries to bootstrap child stores for these non-existent local paths.
3. notifications (packages/app/src/context/notification.tsx:126-131)
// notification.v1 — global, single flat list
list: [] as Notification[]Error notifications from the session restoration failures accumulate in a single list capped at 500, pushing out legitimate turn-complete notifications.
What IS correctly isolated
The project list itself is correctly namespaced — server.tsx:24-29 uses projectsKey(origin) to key store.projects[origin]. This is why the sidebar shows different projects per server. The runtime state is also isolated via <ServerKey keyed> which remounts the entire component tree on switch.
Proposed Fix
Namespace the three affected storage keys by server origin, matching the pattern already used in server.tsx:
Option A (minimal): Clear lastProjectSession entries and sidebar.workspaces entries for the previous server's paths when switching servers.
Option B (proper): Key these stores by origin() the same way store.projects already is:
// Instead of:
lastProjectSession: {} as { [directory: string]: SessionRoute }
// Use:
lastProjectSession: {} as { [origin: string]: { [directory: string]: SessionRoute } }Environment
- Version: 1.2.27
- Two servers: local sidecar + remote
opencode serveon a separate machine - The session loop fires ~every 4 seconds and generates error notifications with audible chimes