Skip to content

fix(desktop): fix creating workspace and worktree from existing branch#2982

Open
vivishko wants to merge 6 commits intosuperset-sh:mainfrom
vivishko:open-workspace-with-existing-branch
Open

fix(desktop): fix creating workspace and worktree from existing branch#2982
vivishko wants to merge 6 commits intosuperset-sh:mainfrom
vivishko:open-workspace-with-existing-branch

Conversation

@vivishko
Copy link
Copy Markdown
Contributor

@vivishko vivishko commented Mar 29, 2026

Description

This PR makes Create behavior in the branch dropdown strict and explicit:

  • Create on a branch row now always means: create workspace/worktree from that existing branch
    (useExistingBranch=true).
  • Create is hidden for branches that already have a worktree (tracked or external, matched by branch).
  • Open behavior for existing/openable worktrees is preserved.
  • New-branch flow via branch input remains unchanged.

Backend hardening for existing-branch create was added:

  • Returns domain-style errors for:
    • WORKTREE_ALREADY_EXISTS_FOR_BRANCH
    • BRANCH_NOT_FOUND
    • GIT_OPERATION_FAILED
  • Added analytics intent:
    • create_from_existing_branch
    • create_new_branch

Also fixed default worktree base-dir fallback:

  • If project/global worktreeBaseDir is not set, fallback now consistently uses ~/.superset/worktrees
    (not workspace-name-scoped ~/.superset-/worktrees).

Related Issues

related to #2575

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Manual verification (happy path):

  • Create from existing branch (without existing worktree) creates and opens workspace correctly.
  • Create is not shown for branches that already have worktree.
  • Open remains unchanged.

Screenshots (if applicable)

image image

Additional Notes


Summary by cubic

Fixes creating a workspace/worktree from an existing branch in the desktop app. The branch picker now has predictable actions (row click selects, Enter opens, Cmd/Ctrl+Enter creates), and backend validation returns clear domain errors.

  • Bug Fixes

    • Branch picker: row click selects the base branch; Open/Create are button-only. Enter opens an active/openable worktree. Cmd/Ctrl+Enter creates from the selected branch when allowed. Create is hidden if the branch already has a worktree.
    • Backend validates existing-branch creates by listing branches and checking worktrees; returns domain errors (WORKTREE_ALREADY_EXISTS_FOR_BRANCH, BRANCH_NOT_FOUND, GIT_OPERATION_FAILED) via tRPC. UI maps these using shared WorkspaceCreateDomainErrorCode to friendly messages.
    • Existing-branch creates apply pending setup and agent launch. Analytics intent (create_from_existing_branch | create_new_branch) is recorded and auto-set when omitted.
    • Stable default worktree base-dir fallback to ~/.superset/worktrees via a shared utility. Always revokes attachment blob URLs after existing-branch create. Tests added for domain errors, default base-dir fallback, and branch-row state.
  • Refactors

    • Unified launch file prep (attachments + GitHub issue content) into a single helper used by both new-branch and existing-branch flows.
    • Added utils for branch row state and default worktree base dir; the shared WorkspaceCreateDomainErrorCode is used end-to-end.

Written for commit 48e905d. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Create a workspace from an existing branch directly in the branch picker; creation intent is tracked.
    • Improved branch picker actions and pointer-activation behavior for more predictable selection.
  • Bug Fixes

    • More robust detection and clearer, domain-aware error messages when branches or worktrees conflict.
    • Consistent default worktree base directory resolution and reduced redundant branch lookups.
  • Tests

    • Added tests covering error handling, default worktree path, and branch-row state logic.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 29, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds intent-aware telemetry, eager branch listing and domain-specific validation/error handling for creating workspaces from existing branches; introduces default worktree base-dir utilities, updates worktree-path resolution to use that utility, and surfaces open/create actions plus domain-error parsing in the NewWorkspaceModal UI.

Changes

Cohort / File(s) Summary
Workspace Create Procedure
apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
Input accepts optional intent; eagerly fetches existingBranches (local + remote) with try/catch; wraps getBranchWorktreePath in try/catch; delegates validation to validateExistingBranchCreate; removes redundant listBranches call.
Domain Error Utilities & Tests
apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.ts, apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.test.ts
New WorkspaceCreateDomainErrorCode type and helpers: throwWorkspaceCreateDomainError (logs + throws TRPCError with domain-prefixed message) and validateExistingBranchCreate (checks branch presence and worktree occupancy). Adds tests covering error cases and TRPC mapping.
Default Worktree Base-dir Utility & Tests
apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.ts, apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.test.ts
Adds getDefaultWorktreeBaseDir(homeDirectory?) to compute fallback worktrees base dir using constants; test asserts constructed path and absence of workspace-scoped suffix.
Worktree Path Resolution
apps/desktop/src/lib/trpc/routers/workspaces/utils/resolve-worktree-path.ts
Replaces inline homedir/constants fallback with getDefaultWorktreeBaseDir() while preserving precedence of project.worktreeBaseDir and local DB setting.
Frontend Prompt Group & Intent
apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx
Adds parseWorkspaceCreateDomainError; introduces handleCreateFromExistingBranch to call create RPC with useExistingBranch and intent; pointer-down timing to distinguish select vs open; integrates resolveBranchRowState, prepareLaunchFiles, and updates Create/Open UI flows.
Branch Row State Logic & Tests
apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.ts, .../branchRowState.test.ts
Adds BranchRowStateInput/BranchRowStateOutput and resolveBranchRowState (computes showOpen = `hasActiveWorkspace

Sequence Diagram

sequenceDiagram
    actor User
    participant UI as PromptGroup UI
    participant Client as TRPC Client
    participant Server as Workspace Create Procedure
    participant Git as Git Ops
    participant DB as Local DB

    User->>UI: select branch / request create/open
    UI->>Client: createWorkspace.mutateAsync({ branchName, useExistingBranch?, intent })
    Client->>Server: RPC create workspace request
    Server->>Git: listBranches (local + remote)
    Git-->>Server: branch names
    Server->>Server: existingBranches := branch names
    alt useExistingBranch == true
        Server->>Git: getBranchWorktreePath(branch)
        Git-->>Server: existingWorktreePath (or null)
        Server->>Server: validateExistingBranchCreate(branch, existingBranches, existingWorktreePath)
    end
    Server->>DB: persist workspace (if validated)
    DB-->>Server: created
    Server-->>Client: response or domain TRPC error
    Client-->>UI: show success or parsed domain error toast
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I hopped through branches, counted each name,
Sniffed for worktrees, called errors by name.
I cached the lists, then validated with cheer,
Create or open — the path is now clear.
Carrots and commits, a rabbit's small cheer. 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: fixing workspace and worktree creation from existing branches.
Description check ✅ Passed The PR description comprehensively covers all required sections of the template with substantial detail about changes, issues, testing, and context.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

3 issues found across 9 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx">

<violation number="1" location="apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx:478">
P2: `CommandItem.onSelect` now always selects compare-base, so keyboard item activation no longer opens existing/openable worktrees/workspaces.</violation>

<violation number="2" location="apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx:1100">
P2: Existing-branch create path omits pending setup overrides, skipping agent launch/setup behavior used by normal workspace creation.</violation>
</file>

<file name="apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.test.ts">

<violation number="1" location="apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.test.ts:6">
P2: Test uses a hardcoded POSIX path string while implementation uses platform-dependent `path.join`, making the assertion brittle on Windows.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

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.

🧹 Nitpick comments (1)
apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx (1)

76-79: Consider sharing the error code type with the backend.

The WorkspaceCreateDomainErrorCode type is duplicated here and in create-domain-errors.ts. If the backend adds new error codes, this frontend type won't automatically include them. Consider exporting the type from a shared location if the module boundaries allow it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx`
around lines 76 - 79, The WorkspaceCreateDomainErrorCode type in PromptGroup.tsx
is duplicated from create-domain-errors.ts which risks drifting when backend
adds codes; remove the local declaration of WorkspaceCreateDomainErrorCode and
instead import the exported type from the shared module (or move the type into a
common/shared package and import it) so the frontend uses the single source of
truth (update the import where PromptGroup.tsx references
WorkspaceCreateDomainErrorCode and ensure create-domain-errors.ts exports the
type).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx`:
- Around line 76-79: The WorkspaceCreateDomainErrorCode type in PromptGroup.tsx
is duplicated from create-domain-errors.ts which risks drifting when backend
adds codes; remove the local declaration of WorkspaceCreateDomainErrorCode and
instead import the exported type from the shared module (or move the type into a
common/shared package and import it) so the frontend uses the single source of
truth (update the import where PromptGroup.tsx references
WorkspaceCreateDomainErrorCode and ensure create-domain-errors.ts exports the
type).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c56703e6-d413-4de7-81bb-2d9d890d69c3

📥 Commits

Reviewing files that changed from the base of the PR and between 3c46f4f and 47d00e9.

📒 Files selected for processing (9)
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.test.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.test.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/resolve-worktree-path.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.test.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.ts

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.

🧹 Nitpick comments (1)
apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx (1)

1135-1168: Add explicit closeAndReset option for consistency with handleCreate.

This function passes no third argument to runAsyncAction, relying on the default behavior to close and reset the modal. For consistency and clarity, explicitly pass { closeAndReset: false } (matching line 1076) and add a .finally() block to call clearPendingWorkspace(pendingWorkspaceId) like the other workspace creation handlers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx`
around lines 1135 - 1168, The call to runAsyncAction with
createWorkspace.mutateAsyncWithPendingSetup should explicitly pass the
third-argument options object { closeAndReset: false } (to match handleCreate
behavior) and append a .finally() that calls
clearPendingWorkspace(pendingWorkspaceId); update the invocation around
runAsyncAction/createWorkspace.mutateAsyncWithPendingSetup to include the {
closeAndReset: false } option and ensure a finally block invokes
clearPendingWorkspace(pendingWorkspaceId) so pendingWorkspace cleanup happens
consistently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In
`@apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx`:
- Around line 1135-1168: The call to runAsyncAction with
createWorkspace.mutateAsyncWithPendingSetup should explicitly pass the
third-argument options object { closeAndReset: false } (to match handleCreate
behavior) and append a .finally() that calls
clearPendingWorkspace(pendingWorkspaceId); update the invocation around
runAsyncAction/createWorkspace.mutateAsyncWithPendingSetup to include the {
closeAndReset: false } option and ensure a finally block invokes
clearPendingWorkspace(pendingWorkspaceId) so pendingWorkspace cleanup happens
consistently.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: db0e1b1b-bb99-4197-9b63-d8ac834014d5

📥 Commits

Reviewing files that changed from the base of the PR and between 29451f1 and 991161e.

📒 Files selected for processing (1)
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx

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: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx`:
- Around line 563-577: The "Create" button label currently shows an Enter hint
("↵") which is misleading because pressing Enter triggers CommandItem.onSelect()
and only updates compareBaseBranch instead of calling
onCreateFromExistingBranch(); remove the arrow hint by changing the span content
in the Button (inside the showCreate branch) to not include "↵" — e.g., render
only modKey when hasExistingWorkspace (or remove the span entirely) and keep the
existing onClick that calls onCreateFromExistingBranch(branch.name) and
setOpen(false).
- Around line 1116-1180: The handleCreateFromExistingBranch callback diverges
from handleCreate by not forwarding compareBaseBranch and by building the agent
launch request before running the same attachment/linked-issue preparation,
causing wrong base-branch and missing context; modify
handleCreateFromExistingBranch to reuse the same pre-launch preparation steps
used in handleCreate (run the attachment/linked-issue/file preparation that adds
attachments and linkedGitHubIssue and forwards compareBaseBranch) before calling
buildLaunchRequest(selectedPrompt), then pass the resulting launchRequest into
createWorkspace.mutateAsyncWithPendingSetup just like handleCreate does (keep
the same resolveInitialCommands behavior), ensuring compareBaseBranch and
attachment/linked-issue context are included.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aa76ed9a-5919-47b2-af76-4d257d46dff3

📥 Commits

Reviewing files that changed from the base of the PR and between 991161e and 5eddb26.

📒 Files selected for processing (9)
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.test.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.test.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/resolve-worktree-path.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.test.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.ts
✅ Files skipped from review due to trivial changes (3)
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/utils/create-domain-errors.test.ts
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/utils/branchRowState/branchRowState.test.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/resolve-worktree-path.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/utils/default-worktree-base-dir.test.ts

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 1 file (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx">

<violation number="1" location="apps/desktop/src/renderer/components/NewWorkspaceModal/components/PromptGroup/PromptGroup.tsx:413">
P2: Early returns after preparing attachments skip the blob URL cleanup, so attachment URLs leak when prepareLaunchFiles or buildLaunchRequest fails in the existing-branch flow.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

@vivishko vivishko force-pushed the open-workspace-with-existing-branch branch from 851dd84 to bb69d15 Compare April 2, 2026 21:40
@vivishko vivishko force-pushed the open-workspace-with-existing-branch branch from bb69d15 to 48e905d Compare April 9, 2026 20:45
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