Skip to content

fix: refresh renderer stores after workspace change#491

Open
HiddenPuppy wants to merge 1 commit into
mainfrom
fix/issue-404
Open

fix: refresh renderer stores after workspace change#491
HiddenPuppy wants to merge 1 commit into
mainfrom
fix/issue-404

Conversation

@HiddenPuppy
Copy link
Copy Markdown
Collaborator

Summary

When the user changes workspace via SystemSection, the main process re-initializes the database for the new path, but the renderer's Zustand stores (task, message, dashboard, usage, approval) still hold stale data from the old workspace. The user would see a blank or incorrect task list and would need to manually refresh or relaunch.

Changes

  • Main process (workspace-handlers.ts): After reinitDatabase + updateConfig succeed, emit a workspace:changed IPC event to the renderer window with the new workspace path
  • Preload (index.ts + clawwork.d.ts): Expose onWorkspaceChanged(callback) that subscribes to the IPC event and returns an unsubscribe function
  • Renderer (SystemSection.tsx): A useEffect subscribes to onWorkspaceChanged. On receipt:
    • Clears task store + re-calls hydrate() to load from new DB
    • Clears message store (messages, active turns, processing set)
    • Clears dashboard, usage, and approval caches
    • Re-fetches settings from the backend

Testing

  • pnpm typecheck — passes
  • pnpm test — all 311 tests pass (49 test files)
  • Architecture guardrails — all 4 rules pass

Fixes #404

When the user changes workspace via SystemSection, the main process
re-initializes the database but the renderer's Zustand stores still
hold stale data from the old workspace.

This fix emits a 'workspace:changed' IPC event from the main process
after the workspace swap succeeds. The renderer subscribes to this
event and clears/re-hydrates task store, message store, dashboard
store, usage store, and approval store so the UI reflects the new
workspace contents without requiring a manual refresh or relaunch.

Fixes #404
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 9, 2026

Hi @HiddenPuppy,
Thanks for your pull request!
If the PR is ready, use the /auto-cc command to assign Reviewer to Review.
We will review it shortly.

Details

Instructions for interacting with me using comments are available here.
If you have questions or suggestions related to my behavior, please file an issue against the gh-ci-bot repository.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a state synchronization issue where the renderer's data stores retained stale information after a user switched workspaces. By introducing an IPC-based notification system, the application now correctly clears and re-initializes all relevant caches and stores, ensuring the UI reflects the data of the newly selected workspace without requiring a manual refresh.

Highlights

  • IPC Communication: Implemented a new 'workspace:changed' IPC event emitted by the main process upon successful workspace migration and configuration update.
  • Preload API Expansion: Exposed the 'onWorkspaceChanged' subscription method in the preload script to allow the renderer to listen for workspace changes.
  • Renderer State Management: Added a useEffect hook in SystemSection to clear and re-hydrate Zustand stores (tasks, messages, dashboard, usage, approval) when a workspace change is detected.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a mechanism to notify the renderer process when a workspace change occurs, ensuring that application stores are cleared and re-hydrated with the new data. However, the current implementation only targets the first available window and ties the event listener to the lifecycle of a specific settings component. Feedback suggests broadcasting the event to all windows and moving the listener to a global location to ensure state consistency across the entire application regardless of the active view.

Comment on lines +73 to +90
useEffect(() => {
return window.clawwork.onWorkspaceChanged(async () => {
// Clear task store and re-hydrate from new DB
useTaskStore.setState({ tasks: [], activeTaskId: null, hydrated: false });
useTaskStore.getState().hydrate();

// Clear message store
useMessageStore.setState({ messagesByTask: {}, activeTurnBySession: {}, processingBySession: new Set() });

// Clear dashboard, usage, and approval caches
useDashboardStore.getState().clear();
useUsageStore.getState().clear();
useApprovalStore.getState().clear();

// Refresh settings to pick up new workspace config
await refreshSettings().catch(() => {});
});
}, [refreshSettings]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The onWorkspaceChanged listener is currently tied to the lifecycle of the SystemSection component. This presents two architectural issues:

  1. Lifecycle Dependency: The stores will only refresh if the user is actively viewing the "System" settings section when the workspace change event is received. If they navigate away or close the settings before the IPC event arrives, the stores remain stale.
  2. Multi-window Consistency: In a multi-window setup, only the window that has the settings page open will refresh its stores. Other windows will remain out of sync.

Consider moving this subscription to a global location (e.g., a root layout component or a dedicated initialization hook) to ensure the application state is consistently updated across all windows and views. Once moved, the manual refreshSettings() call in handleChangeWorkspace (line 107) should be removed to avoid redundant network requests.

References
  1. Verify dependency direction and ensure architectural invariants are maintained across layers. (link)

Comment on lines +59 to +60
const win = BrowserWindow.getAllWindows()[0];
if (win) win.webContents.send('workspace:changed', newWorkspacePath);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using BrowserWindow.getAllWindows()[0] is unreliable as it only targets the first window found by the runtime. In a multi-window environment (e.g., if the user has detached chat windows or multiple instances), other windows will not receive the workspace:changed event and will continue to display stale data from the previous workspace. It is better to broadcast the event to all open windows.

Suggested change
const win = BrowserWindow.getAllWindows()[0];
if (win) win.webContents.send('workspace:changed', newWorkspacePath);
BrowserWindow.getAllWindows().forEach((win) => {
win.webContents.send('workspace:changed', newWorkspacePath);
});

Copy link
Copy Markdown
Collaborator

@mvanhorn mvanhorn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HiddenPuppy I agree with gemini's two architectural concerns and think both are worth addressing before merge:

  1. Lifecycle scope (SystemSection.tsx:90) - tying onWorkspaceChanged to a component that only mounts when the user is on the System tab means navigating away during a workspace switch will silently drop the event and leave stores stale. The listener should live at a top-level provider that's always mounted (App root, an effect inside a Zustand store init, or a dedicated useWorkspaceSync hook called from a top-level component).

  2. Multi-window broadcast (workspace-handlers.ts:60) - getAllWindows()[0] is fine for the single-window case but breaks for detached/secondary windows. BrowserWindow.getAllWindows().forEach(w => w.webContents.send(...)) covers it.

The quality CI failure looks unrelated - 6 no-explicit-any errors in packages/desktop/test/ssrf-guard.test.ts, which this PR doesn't touch. Worth checking whether main is also red on that file.

Overall direction is right - clearing the renderer caches after a workspace switch is the correct fix for #404. Just want the listener and broadcast wired more robustly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] changeWorkspace does not refresh renderer stores, leaving UI with stale data

2 participants