Skip to content

fix(desktop): prevent ghost workspace re-appearance on close#1345

Open
Kitenite wants to merge 4 commits intomainfrom
kitenite/wildebeest
Open

fix(desktop): prevent ghost workspace re-appearance on close#1345
Kitenite wants to merge 4 commits intomainfrom
kitenite/wildebeest

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Feb 9, 2026

Summary

  • Closing a workspace awaited terminal kills before marking it as deleting, leaving a window where getAllGrouped refetches could resurrect the workspace in the sidebar
  • If a new workspace was created during that window, the closed workspace's git metadata (diff stats) would ghost-appear at its old sidebar position
  • Aligns workspace close and project close with the existing delete procedure pattern

Changes

  • workspaces/procedures/delete.ts: Move markWorkspaceAsDeleting and updateActiveWorkspaceIfRemoved before the async terminal kill in the close procedure; keep hideProjectIfNoWorkspaces after deleteWorkspace (it counts all rows including deletingAt for concurrent deletion safety)
  • projects/projects.ts: Batch-set deletingAt on all project workspaces and hide the project before the async terminal kill loop; update active workspace via selectNextActiveWorkspace() before terminal kills (previously used an unfiltered query after deletion); parallelize terminal kills with Promise.all

Test Plan

  • Close a workspace and immediately create a new one — verify the closed workspace doesn't briefly reappear in the sidebar
  • Close a project — verify all workspaces disappear immediately, not after terminal shutdown
  • Close a project with multiple workspaces — verify active workspace switches immediately to a workspace outside the project
  • Verify closing still works end-to-end (terminals killed, workspace removed, navigation to next workspace)

Summary by CodeRabbit

  • Refactor
    • Improved workspace closure with parallel terminal shutdown for faster performance.
    • Reorganized cleanup to mark workspaces as deleting and update active workspace before terminal termination for more consistent state.
    • Consolidated post-shutdown cleanup and failure accounting to provide clearer outcomes and preserve workspace visibility/order.

When closing a workspace, the `close` procedure awaited terminal kills
before marking the workspace as deleting. If another workspace was
created during that window, the `getAllGrouped` refetch found the
closing workspace still visible in the DB, overwriting the optimistic
removal and causing stale git metadata to appear on the sidebar.

Move `markWorkspaceAsDeleting` and dependent state updates before the
async terminal kill in both the workspace `close` and project `close`
procedures, matching the existing `delete` procedure pattern.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 9, 2026

📝 Walkthrough

Walkthrough

Reorders close/delete flows: closed workspace IDs are determined early, workspaces are marked deletingAt and project tabOrder cleared before concurrently killing terminals via Promise.all; terminal results determine totalFailed, then workspaces are deleted and last-active workspace is set using selectNextActiveWorkspace/setLastActiveWorkspace.

Changes

Cohort / File(s) Summary
Project close logic
apps/desktop/src/lib/trpc/routers/projects/projects.ts
Adds selectNextActiveWorkspace import; computes closed workspace IDs early, marks workspaces deletingAt, clears project tabOrder, kills terminals in parallel (Promise.all) and derives totalFailed from results, then deletes workspaces and updates last-active workspace via selectNextActiveWorkspace/setLastActiveWorkspace.
Workspace delete procedure
apps/desktop/src/lib/trpc/routers/workspaces/procedures/delete.ts
Moves markWorkspaceAsDeleting(input.id) and updateActiveWorkspaceIfRemoved(input.id) to execute before terminal termination; removes the post-delete active-workspace update so terminals are killed while the workspace is already marked deleting.
Manifest
package.json
Minor manifest changes (lines added/removed reported).

Sequence Diagram(s)

sequenceDiagram
  participant API as Projects API
  participant DB as Database
  participant Term as TerminalService
  participant WS as WorkspaceService

  API->>DB: compute closedWorkspaceIds(projectId)
  API->>DB: mark workspaces deletingAt(closedWorkspaceIds)
  API->>DB: set project.tabOrder = null
  API->>Term: kill terminals for closedWorkspaceIds (parallel)
  Term-->>API: terminal kill results (success/failure)
  API->>DB: selectNextActiveWorkspace(projectId)
  API->>DB: setLastActiveWorkspace(nextActiveWorkspace)
  API->>WS: delete workspaces(closedWorkspaceIds)
  WS-->>DB: remove workspace rows
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐇 I boxed the tabs and set them to sleep,
Marked the burrows as leaving, tidy and neat.
Terminals hush in parallel hum,
Delete, select next — the hops are done. 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main fix: preventing ghost workspace re-appearance on close, which is the core objective of the changeset.
Description check ✅ Passed The description provides a comprehensive summary, explains the problem, lists specific file changes, and includes a detailed test plan, covering all required template sections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kitenite/wildebeest

No actionable comments were generated in the recent review. 🎉


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@apps/desktop/src/lib/trpc/routers/workspaces/procedures/delete.ts`:
- Around line 302-312: hideProjectIfNoWorkspaces is called before
deleteWorkspace so the helper still sees the workspace (only marked deletingAt)
and never hides the project; either move the
hideProjectIfNoWorkspaces(input.projectId) call to after
deleteWorkspace(input.id) in the delete procedure (so it runs once the row is
removed) or update the helper in db-helpers.ts to exclude rows with deletingAt
set; update the code paths around markWorkspaceAsDeleting,
getWorkspaceRuntimeRegistry().terminal.killByWorkspaceId, and deleteWorkspace to
ensure hideProjectIfNoWorkspaces runs after the workspace is actually deleted.

Comment thread apps/desktop/src/lib/trpc/routers/workspaces/procedures/delete.ts
hideProjectIfNoWorkspaces counts all rows including deletingAt ones
(intentional for concurrent deletion safety), so the row must be fully
deleted before the check runs.
@Kitenite Kitenite force-pushed the kitenite/wildebeest branch from 2e55baa to b7584e1 Compare February 11, 2026 00:59
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.

1 participant