Skip to content

feat: group linked git worktrees under their main repo in sidebar#650

Open
truongsinh wants to merge 6 commits intositeboon:mainfrom
truongsinh:feat/worktree-support
Open

feat: group linked git worktrees under their main repo in sidebar#650
truongsinh wants to merge 6 commits intositeboon:mainfrom
truongsinh:feat/worktree-support

Conversation

@truongsinh
Copy link
Copy Markdown

@truongsinh truongsinh commented Apr 13, 2026

Problem

When Claude Code (or any other agent) runs inside a git linked worktree, the session is stored under a different path in ~/.claude/projects/, so cloudcli treats it as a completely unrelated project. Users who rely on claude mcp / EnterWorktree for parallel workstreams end up with a fragmented sidebar.

Solution

Detect worktrees on the server and surface grouping metadata to the frontend, which then renders linked worktrees as indented sub-items beneath their main repo.

Backend (server/projects.js)

  • Add resolveWorktreeInfo(projectPath): runs git -C <path> worktree list --porcelain (fast, no network) and returns { isWorktree, mainRepoPath, worktreeBranch } for each project path. Falls back silently for non-git directories.
  • Call it for every discovered project (both auto-discovered and manually added), attaching the three optional fields to the project object.

Frontend

  • src/types/app.ts: add isWorktree?, mainRepoPath?, worktreeBranch? to Project.
  • SidebarProjectList: useMemo-group filteredProjects by mainRepoPath. Worktrees whose main repo is present in the list are promoted to sub-items; orphan worktrees (main repo not loaded) continue to appear as standalone entries.
  • SidebarWorktreeItem (new): renders a linked worktree as an indented sub-item with:
    • A left connector line visually attaching it to the parent
    • A GitBranch icon + branch name badge
    • Its own expand/collapse and session list (reuses SidebarProjectSessions)
    • A delete button on hover

Terminal & Git diff — no changes needed

Both features already use the actual worktree projectPath as cwd:

  • Terminal (server/index.js line ~1824): pty.spawn(shell, ..., { cwd: resolvedProjectPath }) — spawns in the worktree dir, so the shell opens on the right branch.
  • Git explorer (server/routes/git.js): calls git rev-parse --show-toplevel with the worktree path, which returns the worktree root. All diff/status/stage/commit operations run scoped to that worktree's branch.

Screenshots

Worktrees now appear indented under their main repo with a branch badge:

📁 my-repo          (main branch sessions)
  └─ 🌿 feature-x  (worktree sessions)
  └─ 🌿 hotfix-123 (worktree sessions)

Testing

  1. Create a worktree: git worktree add ../my-repo-feature feature-branch
  2. Start a Claude session in that worktree directory
  3. Open cloudcli — the worktree should appear indented under my-repo
  4. Click the worktree → sessions load correctly
  5. Open Terminal tab → shell opens in the worktree directory
  6. Open Git tab → shows diffs for feature-branch, not main

Summary by CodeRabbit

  • New Features
    • Detect and display linked Git worktrees for projects (branch + main-repo info).
    • Group linked worktrees under their main repository in the sidebar.
    • Add a "New worktree" flow: sidebar dialog, server-side creation API with validation, and UI affordance to create worktrees.
    • Compact worktree sidebar entries (desktop & mobile) show branch and session counts; newly created worktrees are auto-selected and start a new session.

When Claude Code runs in a git worktree, the session is stored under a
different project path in ~/.claude/projects/, causing cloudcli to show
it as an unrelated project.

Changes:
- server/projects.js: add resolveWorktreeInfo() which calls
  `git worktree list --porcelain` to detect linked worktrees and
  returns { isWorktree, mainRepoPath, worktreeBranch }. Applied to all
  projects (both directory-scanned and manually added).
- src/types/app.ts: extend Project interface with isWorktree,
  mainRepoPath, worktreeBranch optional fields.
- SidebarProjectList: group worktree projects under their main repo
  using a useMemo-computed map. Worktrees whose main repo is not in the
  project list continue to appear as standalone items.
- SidebarWorktreeItem: new component rendering a linked worktree as an
  indented sub-item with a branch icon, connector line, branch name, and
  its own session list. Full terminal and git-diff support is unaffected
  because both already use the actual worktree path as cwd.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 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

Detects and classifies Git worktrees on the server, adds an authenticated API to create worktrees, and updates the frontend to group and render linked worktrees under their main repositories with UI to create and manage worktrees.

Changes

Cohort / File(s) Summary
Backend Worktree Detection
server/projects.js
Added execFileAsync and resolveWorktreeInfo(projectPath) to run git -C <path> worktree list --porcelain, parse blocks, and annotate projects with isWorktree, mainRepoPath, worktreeBranch. Integrated into getProjects() for discovered and manual projects; failures are non-fatal.
Worktree Creation Endpoint
server/index.js
Added POST /api/projects/:projectName/worktrees: validates branch, computes sibling worktree path, checks existence, runs git worktree add (uses -b when creating a new branch), registers the new project, and returns { success, worktreePath, project }.
Frontend API
src/utils/api.js
Added api.createWorktree(projectName, branchName) which POSTs { branchName } to the new server endpoint.
Types
src/types/app.ts
Extended exported Project interface with optional fields: isWorktree?: boolean, mainRepoPath?: string, worktreeBranch?: string.
Sidebar List & Grouping
src/components/sidebar/view/subcomponents/SidebarProjectList.tsx
Added useMemo-based groupedProjects to nest worktrees (projects with isWorktree + mainRepoPath) under their main repo, replaced flat rendering with grouped rendering, and added optional onNewWorktree prop; consolidated shared props for item components.
Worktree Item UI
src/components/sidebar/view/subcomponents/SidebarWorktreeItem.tsx
New SidebarWorktreeItem component (desktop/mobile) rendering linked worktrees with branch label, session count, selection/expand/delete behavior, and inlined session list when expanded.
Project Item: New-worktree Action
src/components/sidebar/view/subcomponents/SidebarProjectItem.tsx
Added optional onNewWorktree prop and a “New worktree” action (icon/button) shown for main repos that invokes the callback.
New Worktree Dialog
src/components/sidebar/view/subcomponents/NewWorktreeDialog.tsx
New modal to input branch name, validate, call api.createWorktree, show errors/spinner, and call onCreated(worktreePath) on success.
Sidebar Integration
src/components/sidebar/view/Sidebar.tsx
Added newWorktreeProject state, wired onNewWorktree into project list props, renders NewWorktreeDialog, and handles post-creation flow (refresh projects, select new project, start session or fallback to reload).

Sequence Diagram

sequenceDiagram
    participant User as Browser UI
    participant Frontend as React Frontend
    participant Server as Server (index.js / projects.js)
    participant Git as Git CLI

    User->>Frontend: open NewWorktreeDialog & submit branchName
    Frontend->>Server: POST /api/projects/:projectName/worktrees { branchName }
    Server->>Git: git -C <mainRepo> rev-parse --verify <branch>
    alt branch exists
        Server->>Git: git worktree add <worktreePath> <branch>
    else branch missing
        Server->>Git: git worktree add -b <branch> <worktreePath>
    end
    Git-->>Server: success / failure
    Server->>Server: addProjectManually(worktreePath)
    Server-->>Frontend: { success, worktreePath, project }
    Frontend->>Frontend: refreshProjects() and group worktrees under main repo
    Frontend-->>User: render Sidebar with new SidebarWorktreeItem
Loading

Possibly related PRs

Suggested reviewers

  • blackmammoth
  • viper151

Poem

🐇 I hopped through branches, found a new trail,
carved a sibling path where commits set sail.
Main repo hums, its worktrees align,
nested in the sidebar—so tidy, so fine.
Carrots for commits, and a carrot for mine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding git worktree grouping functionality to the sidebar UI, matching the core objective.

✏️ 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

@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: 3

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

Inline comments:
In `@server/projects.js`:
- Around line 424-428: The returned mainRepoPath should be normalized so
frontend lookups match project.fullPath; replace the raw mainWorktree.path with
a resolved path using path.resolve(mainWorktree.path) when constructing the
object in the function that returns { isWorktree: true, mainRepoPath: ...,
worktreeBranch: ... } (use the same module's path import or require if missing),
ensuring mainRepoPath is canonical for SidebarProjectList.tsx's
byPath.get(p.mainRepoPath) lookup.

In `@src/components/sidebar/view/subcomponents/SidebarWorktreeItem.tsx`:
- Around line 154-166: The delete button's group-hover styles never trigger
because the ancestor clickable row element in SidebarWorktreeItem (the row
container element that wraps the project item and handles selection/clicks) is
missing the Tailwind "group" class; add "group" to that container's className so
the nested elements using "group-hover:flex" and "group-hover:opacity-100" (the
delete button wrapper and button) become visible on hover.
- Line 179: The mobile onClick currently calls toggle which only
expands/collapses; change the handler to use the same select-and-toggle behavior
as desktop by replacing the mobile onClick={toggle} with
onClick={selectAndToggle} (use the existing selectAndToggle function referenced
on line ~128 in SidebarWorktreeItem) so tapping a worktree on mobile both
selects the project and toggles its expansion.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0a9de1a6-7702-46f4-b8e3-6c5c67a8d011

📥 Commits

Reviewing files that changed from the base of the PR and between c7a5baf and bf4974d.

📒 Files selected for processing (4)
  • server/projects.js
  • src/components/sidebar/view/subcomponents/SidebarProjectList.tsx
  • src/components/sidebar/view/subcomponents/SidebarWorktreeItem.tsx
  • src/types/app.ts

- Normalize mainRepoPath with path.resolve() so byPath.get() lookups
  match project.fullPath which is also resolved
- Add 'group' class to desktop row container so group-hover delete
  button visibility works correctly
- Mobile onClick: use selectAndToggle instead of toggle so tapping
  a worktree both selects it and expands it, matching desktop behavior
- POST /api/projects/:projectName/worktrees endpoint: validates branch
  name, computes sibling path, runs git worktree add, registers project
- createWorktree() API helper in src/utils/api.js
- NewWorktreeDialog modal: branch name input, spinner, error display
- GitBranch button on non-worktree SidebarProjectItem (desktop + mobile)
- Dialog wired in Sidebar.tsx; on success refreshes projects and opens a
  new session in the new worktree automatically
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: 3

🧹 Nitpick comments (2)
src/utils/api.js (1)

107-111: Consider URL-encoding projectName to handle special characters.

The projectName is interpolated directly into the URL path. If the project name contains characters that need URL encoding (e.g., spaces, #, %), the request could fail or be misrouted.

♻️ Proposed fix
   createWorktree: (projectName, branchName) =>
-    authenticatedFetch(`/api/projects/${projectName}/worktrees`, {
+    authenticatedFetch(`/api/projects/${encodeURIComponent(projectName)}/worktrees`, {
       method: 'POST',
       body: JSON.stringify({ branchName }),
     }),

Note: This is a broader pattern issue - other methods like sessions(), renameProject(), and deleteSession() also don't encode projectName. Consider addressing this consistently across the API module if special characters are expected in project names.

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

In `@src/utils/api.js` around lines 107 - 111, The createWorktree call
interpolates projectName directly into the URL; update calls that build path
segments (e.g., createWorktree, sessions, renameProject, deleteSession) to
URL-encode projectName using encodeURIComponent before interpolation so special
characters (spaces, #, %, etc.) are safe, e.g., ensure the value passed into
authenticatedFetch path is encodeURIComponent(projectName) everywhere in this
API module to keep behavior consistent; locate these functions and replace
direct ${projectName} usage with an encoded variable prior to calling
authenticatedFetch.
src/components/sidebar/view/subcomponents/NewWorktreeDialog.tsx (1)

68-69: Consider using translation function for hardcoded UI strings.

The component receives t (translation function) as a prop but doesn't use it. Several strings are hardcoded in English:

  • "New worktree — ..." (line 69)
  • Description paragraph (lines 83-84)
  • "Branch name" label (line 89)
  • Placeholder "feature/my-feature" (line 98)
  • Helper text (line 104)
  • "Cancel" and "Create worktree" buttons (lines 118, 134)

If internationalization is important for this codebase, these should use t().

Also applies to: 82-85, 88-89, 103-105, 118-118, 134-134

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

In `@src/components/sidebar/view/subcomponents/NewWorktreeDialog.tsx` around lines
68 - 69, The NewWorktreeDialog component is using hardcoded English strings
despite receiving the translation function prop t; replace all literal UI text
in NewWorktreeDialog (the header "New worktree — {project.displayName}", the
description paragraph, the "Branch name" label, the placeholder
"feature/my-feature", the helper text, and the "Cancel" / "Create worktree"
button labels) with calls to t() using appropriate translation keys (e.g.
t('newWorktree.title', { name: project.displayName }) for the header) and
interpolation for project.displayName, update placeholders and helperText to use
t(...) as well, and ensure the same keys are added to the locale files or passed
through your i18n namespace so translations are available.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/index.js`:
- Around line 651-659: The Promise wrapping the spawn call that runs git with
worktreeArgs (involving spawn, worktreeArgs, mainRepoPath) lacks an 'error'
event handler so the promise can hang if spawning fails; fix it by adding a
proc.on('error', e => reject(e)) (or reject(new Error(...))) handler alongside
the existing stderr/close listeners so any spawn-level errors immediately reject
the promise and include the error details in the rejection.
- Around line 638-645: The promise that wraps the spawn call for git rev-parse
uses the local variable check but doesn't handle the spawn 'error' event, so the
promise can hang if the git process fails to start; update the Promise around
spawn('git', ['rev-parse', '--verify', branch], { cwd: mainRepoPath }) (variable
check) to attach check.on('error', err => reject(err)) in addition to the
'close' handler so OS-level spawn failures reject the Promise and propagate into
the surrounding try/catch.

In `@src/components/sidebar/view/Sidebar.tsx`:
- Around line 129-143: handleWorktreeCreated closes over a stale projects array
so the new worktree can't be found after window.refreshProjects(); fix by
ensuring you read the fresh projects inside the .then() instead of the captured
value — either update the component to maintain a mutable projectsRef (e.g.,
sync projects into projectsRef.current via useEffect and use projectsRef.current
inside handleWorktreeCreated's .then()), or change window.refreshProjects() to
return the updated projects array and use that result to find wt; keep the
existing calls to handleProjectSelect and onNewSession once you locate wt.

---

Nitpick comments:
In `@src/components/sidebar/view/subcomponents/NewWorktreeDialog.tsx`:
- Around line 68-69: The NewWorktreeDialog component is using hardcoded English
strings despite receiving the translation function prop t; replace all literal
UI text in NewWorktreeDialog (the header "New worktree — {project.displayName}",
the description paragraph, the "Branch name" label, the placeholder
"feature/my-feature", the helper text, and the "Cancel" / "Create worktree"
button labels) with calls to t() using appropriate translation keys (e.g.
t('newWorktree.title', { name: project.displayName }) for the header) and
interpolation for project.displayName, update placeholders and helperText to use
t(...) as well, and ensure the same keys are added to the locale files or passed
through your i18n namespace so translations are available.

In `@src/utils/api.js`:
- Around line 107-111: The createWorktree call interpolates projectName directly
into the URL; update calls that build path segments (e.g., createWorktree,
sessions, renameProject, deleteSession) to URL-encode projectName using
encodeURIComponent before interpolation so special characters (spaces, #, %,
etc.) are safe, e.g., ensure the value passed into authenticatedFetch path is
encodeURIComponent(projectName) everywhere in this API module to keep behavior
consistent; locate these functions and replace direct ${projectName} usage with
an encoded variable prior to calling authenticatedFetch.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 28c2a9ad-8470-4e17-8e98-3593997e009c

📥 Commits

Reviewing files that changed from the base of the PR and between 990ae14 and e3f751e.

📒 Files selected for processing (6)
  • server/index.js
  • src/components/sidebar/view/Sidebar.tsx
  • src/components/sidebar/view/subcomponents/NewWorktreeDialog.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectItem.tsx
  • src/components/sidebar/view/subcomponents/SidebarProjectList.tsx
  • src/utils/api.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/sidebar/view/subcomponents/SidebarProjectList.tsx

- Add error event handlers to both git spawn calls in create-worktree
  endpoint so hung promises are rejected if git binary is not found
- Fix stale closure in handleWorktreeCreated: use a projectsRef that
  tracks the latest projects prop so post-refresh lookup finds the new
  worktree correctly
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 (2)
server/index.js (2)

667-670: Consider sanitizing error messages in the response.

The raw error.message is returned to the client, which could potentially leak filesystem paths or system details. While this endpoint is authenticated, consider returning a generic message and logging the detailed error server-side only:

     } catch (error) {
         console.error('Error creating worktree:', error);
-        res.status(500).json({ error: error.message });
+        res.status(500).json({ error: 'Failed to create worktree' });
     }

This is a minor hardening suggestion; the current approach is consistent with other endpoints in this file.

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

In `@server/index.js` around lines 667 - 670, In the catch block that currently
logs and returns error.message (the "Error creating worktree" catch), stop
exposing error.message to the client: keep detailed logging server-side
(console.error or processLogger.error with the full error/stack) and change the
response to a generic 500 JSON like { error: 'Failed to create worktree' } (or
similar). Locate the catch handling around the worktree creation route in
server/index.js and replace res.status(500).json({ error: error.message }) with
a generic message while preserving the existing detailed server log.

621-625: Consider validating that worktreePath falls within an allowed workspace area.

The endpoint creates the worktree as a sibling to mainRepoPath, but there's no validation that this location is within an allowed workspace boundary (like WORKSPACES_ROOT). If a project was manually added from an arbitrary filesystem location, the worktree could be created in sensitive areas.

Other endpoints in this file (e.g., browse-filesystem, create-folder) use validateWorkspacePath to enforce boundaries. Consider applying similar validation here:

         const worktreePath = path.join(path.dirname(mainRepoPath), `${repoName}-${safeSuffix}`);
 
+        // Validate worktree path is within allowed workspace
+        const validation = await validateWorkspacePath(worktreePath);
+        if (!validation.valid) {
+            return res.status(403).json({ error: validation.error });
+        }
+
         // Check if the worktree path already exists
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/index.js` around lines 621 - 625, The constructed worktreePath
(derived from mainRepoPath, repoName and safeSuffix) is not validated against
the allowed workspace boundary; call the existing validateWorkspacePath function
(the same one used by browse-filesystem/create-folder) on worktreePath (or
otherwise check it is inside WORKSPACES_ROOT) before creating the worktree and
return/throw a 4xx error when validation fails so you never create a worktree
outside the allowed workspace area.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/index.js`:
- Around line 667-670: In the catch block that currently logs and returns
error.message (the "Error creating worktree" catch), stop exposing error.message
to the client: keep detailed logging server-side (console.error or
processLogger.error with the full error/stack) and change the response to a
generic 500 JSON like { error: 'Failed to create worktree' } (or similar).
Locate the catch handling around the worktree creation route in server/index.js
and replace res.status(500).json({ error: error.message }) with a generic
message while preserving the existing detailed server log.
- Around line 621-625: The constructed worktreePath (derived from mainRepoPath,
repoName and safeSuffix) is not validated against the allowed workspace
boundary; call the existing validateWorkspacePath function (the same one used by
browse-filesystem/create-folder) on worktreePath (or otherwise check it is
inside WORKSPACES_ROOT) before creating the worktree and return/throw a 4xx
error when validation fails so you never create a worktree outside the allowed
workspace area.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ac9ee1e4-526b-4c94-90b6-fc10216189bb

📥 Commits

Reviewing files that changed from the base of the PR and between e3f751e and 5a1f097.

📒 Files selected for processing (2)
  • server/index.js
  • src/components/sidebar/view/Sidebar.tsx

…rror, stale closure

- Validate worktreePath against WORKSPACES_ROOT before creating worktree
- Return generic 500 message to client instead of raw error.message
- Fix stale-closure bug: store pendingWorktreePath in state and navigate
  via useEffect once projects list updates with the new worktree
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

♻️ Duplicate comments (1)
server/index.js (1)

644-647: ⚠️ Potential issue | 🟠 Major

Attach error handlers to both Git child processes.

If git cannot be spawned or cwd is invalid, these promises never settle because they only listen for close. That leaves the HTTP request hanging instead of failing fast.

🛠️ Suggested patch
         try {
             await new Promise((resolve, reject) => {
                 const check = spawn('git', ['rev-parse', '--verify', branch], { cwd: mainRepoPath });
+                check.on('error', reject);
                 check.on('close', code => code === 0 ? resolve() : reject());
             });
             branchExists = true;
         } catch {
             branchExists = false;
@@
         await new Promise((resolve, reject) => {
             const proc = spawn('git', worktreeArgs, { cwd: mainRepoPath });
             let stderr = '';
             proc.stderr.on('data', d => { stderr += d.toString(); });
+            proc.on('error', reject);
             proc.on('close', code => {
                 if (code === 0) resolve();
                 else reject(new Error(stderr.trim() || `git worktree add exited with code ${code}`));
             });
         });
#!/bin/bash
rg -n -C2 "spawn\\('git'|\\.on\\('error'" server/index.js

Expected result: both spawn('git', ...) blocks appear without a nearby .on('error', ...), confirming the request can hang on spawn-level failures.

Also applies to: 657-665

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

In `@server/index.js` around lines 644 - 647, The Promise wrapping the Git child
process only listens for 'close', so if spawn fails the Promise never settles;
update the promise that creates the child assigned to check (spawn('git',
['rev-parse', '--verify', branch], ...)) to also attach an .on('error', err =>
reject(err)) handler, and do the same for the other git spawn block later (the
second spawn('git', ...) around the 657-665 area) so both child processes reject
their promises on spawn errors and cannot leave the HTTP request hanging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/index.js`:
- Around line 628-631: The handler incorrectly checks
workspaceValidation.isValid (which is undefined) after calling
validateWorkspacePath(); change the condition to use the correct property
workspaceValidation.valid (i.e., if (!workspaceValidation.valid) return
res.status(400).json(...)) so the endpoint only rejects when the helper
indicates the path is invalid; update any related variable uses of isValid to
valid in this function (e.g., the worktree creation branch) to ensure the
endpoint can proceed when validation passes.

---

Duplicate comments:
In `@server/index.js`:
- Around line 644-647: The Promise wrapping the Git child process only listens
for 'close', so if spawn fails the Promise never settles; update the promise
that creates the child assigned to check (spawn('git', ['rev-parse', '--verify',
branch], ...)) to also attach an .on('error', err => reject(err)) handler, and
do the same for the other git spawn block later (the second spawn('git', ...)
around the 657-665 area) so both child processes reject their promises on spawn
errors and cannot leave the HTTP request hanging.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5b750c22-01f3-404d-b6ae-58d09aab15ea

📥 Commits

Reviewing files that changed from the base of the PR and between 5a1f097 and 7df54ca.

📒 Files selected for processing (2)
  • server/index.js
  • src/components/sidebar/view/Sidebar.tsx

Comment on lines +628 to +631
const workspaceValidation = await validateWorkspacePath(worktreePath);
if (!workspaceValidation.isValid) {
return res.status(400).json({ error: 'Worktree path is outside the allowed workspace area' });
}
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.

⚠️ Potential issue | 🔴 Critical

Use valid, not isValid, from validateWorkspacePath().

Line 629 checks a field this helper does not return. As written, workspaceValidation.isValid is undefined, so this branch always returns 400 and the endpoint never creates a worktree.

🐛 Minimal fix
-        if (!workspaceValidation.isValid) {
+        if (!workspaceValidation.valid) {
             return res.status(400).json({ error: 'Worktree path is outside the allowed workspace area' });
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const workspaceValidation = await validateWorkspacePath(worktreePath);
if (!workspaceValidation.isValid) {
return res.status(400).json({ error: 'Worktree path is outside the allowed workspace area' });
}
const workspaceValidation = await validateWorkspacePath(worktreePath);
if (!workspaceValidation.valid) {
return res.status(400).json({ error: 'Worktree path is outside the allowed workspace area' });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/index.js` around lines 628 - 631, The handler incorrectly checks
workspaceValidation.isValid (which is undefined) after calling
validateWorkspacePath(); change the condition to use the correct property
workspaceValidation.valid (i.e., if (!workspaceValidation.valid) return
res.status(400).json(...)) so the endpoint only rejects when the helper
indicates the path is invalid; update any related variable uses of isValid to
valid in this function (e.g., the worktree creation branch) to ensure the
endpoint can proceed when validation passes.

When a project has linked git worktrees, the "new session" provider
selection screen now shows a row of branch pills above the heading.
Clicking a pill switches the active project to that worktree so the
session starts in the correct directory.

Threads projects + onProjectSelect from AppContent → MainContent →
ChatInterface → ChatMessagesPane → ProviderSelectionEmptyState.
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