Skip to content

Comments

Fix: Delete Worktree Crash + PR Comments + Dev Server UX Improvements#792

Merged
gsxdsm merged 4 commits intoAutoMaker-Org:v0.15.0rcfrom
gsxdsm:fix/delete-worktree-hotifx
Feb 21, 2026
Merged

Fix: Delete Worktree Crash + PR Comments + Dev Server UX Improvements#792
gsxdsm merged 4 commits intoAutoMaker-Org:v0.15.0rcfrom
gsxdsm:fix/delete-worktree-hotifx

Conversation

@gsxdsm
Copy link
Collaborator

@gsxdsm gsxdsm commented Feb 21, 2026

Overview

This PR fixes a crash when deleting the currently-selected worktree and delivers several quality-of-life improvements across PR review comments, session scoping, and dev server UX.


Bug Fixes

Worktree Deletion Crash (Primary Fix)

  • board-view.tsx: When the active worktree is deleted, immediately reset the selected worktree to main to prevent the UI from trying to render a view for a non-existent worktree
  • board-view.tsx: Added a fallback in activeWorktree resolution — if the selected worktree path no longer exists (e.g. just deleted), fall back to the main worktree instead of returning undefined

Feature Duplication Regression

  • use-board-actions.ts: Strip initialStatus and workMode transient fields when duplicating features, preventing duplicates from incorrectly appearing as "In Progress" instead of "Backlog"
  • Also strips these fields during feature creation to avoid persisting them in feature data

PR Review Comments Improvements

Full Pagination Support (pr-review-comments.service.ts)

  • Extracted reusable executeGraphQL() helper to eliminate duplicated gh subprocess/timeout/JSON-parse logic
  • Implemented cursor-based pagination for review threads (was previously limited to 100 threads with a warning)
  • Added MAX_PAGINATION_PAGES = 20 safety limit (~2,000 threads max) to prevent infinite loops
  • Added endCursor to GraphQL response types

Bot Comment Support

  • Switched regular PR comments from gh pr view --json comments (GraphQL, drops bot authors) to gh api repos/.../issues/.../comments (REST, preserves bot/app author info)
  • Added isBot field to PRReviewComment type — propagated to electron.ts and rendered as a purple "Bot" badge in the dialog
  • Bot comments now correctly show the app slug as the author instead of unknown

Review Body Comments (New)

  • Added fetching of top-level review summary comments (the body text submitted with Approve/Request Changes/Comment reviews)
  • These were previously invisible in the PR comments dialog

UI Polish (pr-comment-resolution-dialog.tsx)

  • Moved disclosure triangle (expand/collapse) from the left side of the row to the right action area alongside the existing expand detail button
  • Row clicks no longer toggle expansion when content doesn't need it (cursor-default for short comments)
  • Removed unnecessary left padding (pl-5) from comment body and date rows
  • Added "Bot" badge to the comment detail dialog
  • Fixed dialog header overlap with the close button (pr-10)

Session Scoping per Worktree

  • libs/types/src/session.ts & electron.d.ts: Added workingDirectory field to AgentSession / SessionListItem to track which worktree a session belongs to
  • use-agent-session.ts: Session persistence key is now the worktree path (not the project path), so each worktree remembers its own last-selected session. Switching worktrees now resets the current session and restores the last session for that worktree
  • session-manager.tsx: Sessions are filtered to only show those matching the current worktree's workingDirectory; new sessions are created with the worktree path as the working directory
  • agent-view.tsx: Passes effectiveWorkingDirectory (worktree path or project path) down to session management and agent execution
  • agent-header.tsx: Displays the current worktree branch name as a pill badge next to the project name

Dev Server UX Improvements

  • worktree-panel.tsx: Starting a dev server now automatically opens the logs panel so output (including errors) is immediately visible
  • worktree-actions-dropdown.tsx: "Start/Stop Dev Server" and "View Logs" are now a split button — primary action is start/stop, with a chevron submenu revealing "View Dev Server Logs"
  • use-dev-servers.ts: Toast notifications for dev server start/failure now include descriptive subtitles pointing users to the logs panel

Summary by CodeRabbit

  • New Features

    • Bot badge indicators for automated comments
    • Sessions can be scoped to specific worktrees; session components accept an optional workingDirectory
    • Worktree branch shown in agent header
    • Session and session-list items include optional worktree association
  • Improvements

    • Better comment expansion controls and layout
    • Comment fetching/resolution improved: cursor pagination capped, more complete coverage including review-body comments, and bot detection on comments
    • Dev Server actions reorganized with split-button menus and logs auto-open; enhanced start/stop toasts
  • Bug Fixes

    • Fallback to main worktree when selected worktrees are deleted
    • Prevent transient creation fields from carrying to duplicated features

@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

Refactors PR review comment fetching with cursor-based GraphQL pagination and bot detection; scopes sessions and agent/session UI to worktrees via a new workingDirectory prop; updates PR comment resolution UI, dev-server controls (split buttons and logs), and dev-server log visibility on start.

Changes

Cohort / File(s) Summary
PR Review Comments Backend
apps/server/src/services/pr-review-comments.service.ts
Added isBot?: boolean to PRReviewComment, MAX_PAGINATION_PAGES, and executeGraphQL helper; switched to explicit cursor-based GraphQL pagination for thread resolved status (capped); replaced inline gh CLI usage with REST calls; unified mappings for regular, inline, and review-body comments; emits warning when cap reached.
PR Comment UI & Types
apps/ui/src/components/dialogs/pr-comment-resolution-dialog.tsx, apps/ui/src/lib/electron.ts, apps/ui/src/types/electron.d.ts
Added isBot to UI/electron types and render Bot badge; reorganized disclosure/expansion controls and adjusted layout/checkbox sizing in the PR comment resolution UI.
Session / Worktree Scoping
apps/ui/src/components/session-manager.tsx, apps/ui/src/types/electron.d.ts, libs/types/src/session.ts
Introduced optional workingDirectory prop and per-worktree effectiveWorkingDirectory/persistence key; scoped session lists/selectors/persistence to worktrees and added workingDirectory?: string to session types.
Agent View Integration
apps/ui/src/components/views/agent-view.tsx, apps/ui/src/components/views/agent-view/components/agent-header.tsx, apps/ui/src/components/views/agent-view/hooks/use-agent-session.ts
Compute currentWorktree/effectiveWorkingDirectory, thread workingDirectory into session hooks and Electron agent, add worktreeBranch prop to AgentHeader and render GitBranch badge, and add responsive Session Manager visibility logic.
Board View / Worktree Fallback
apps/ui/src/components/views/board-view.tsx
When a selected worktree is missing or deleted, fall back to the main worktree and reset selection to avoid rendering invalid worktree views.
Feature Creation & Duplication
apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
Strip transient creation fields (initialStatus, workMode) from duplicated/new features; use transient requestedStatus/_workMode for creation flow to avoid propagating creation-only params.
Dev Server Controls & Logs
apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx, apps/ui/src/components/views/board-view/worktree-panel/hooks/use-dev-servers.ts, apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx
Refactored Dev Server actions into split-button + submenu with "View Dev Server Logs", improved toast descriptions, and added wrapper to open logs panel automatically when starting the dev server.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(30,144,255,0.5)
    participant Caller
  end
  rect rgba(60,179,113,0.5)
    participant PRService
  end
  rect rgba(255,99,71,0.5)
    participant GitHubAPI
  end

  Caller->>PRService: fetchReviewThreadResolvedStatus(prNumber)
  PRService->>GitHubAPI: executeGraphQL(query, cursor=null)
  GitHubAPI-->>PRService: threads + pageInfo(endCursor, hasNextPage)
  alt hasNextPage and under MAX_PAGINATION_PAGES
    PRService->>GitHubAPI: executeGraphQL(query, cursor=endCursor)
  end
  alt reached MAX_PAGINATION_PAGES
    PRService-->>Caller: emit pagination cap warning
  end
  PRService-->>Caller: aggregated resolved status per comment
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

Bug, Enhancement, scope: ui

Poem

🐰 I hopped through branches, bright and sly,
Gave bots small badges when they waved hi,
Sessions now nest where worktrees reside,
Dev logs spring open when servers glide,
A rabbit cheers — merge on with a hop and a sigh!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.67% 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 summarizes the three main changes: fixing a worktree deletion crash, improving PR comments handling, and enhancing dev server UX.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @gsxdsm, 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 significantly enhances the application's stability and user experience by addressing a critical crash related to worktree deletion and introducing several quality-of-life improvements. It refines the handling of PR review comments by improving data fetching and UI presentation, introduces worktree-specific session management for the AI agent, and streamlines the developer server interaction with better feedback and log visibility.

Highlights

  • Worktree Deletion Stability: Resolved a crash when deleting the active worktree by ensuring the UI gracefully falls back to the main worktree and resets the selected worktree path.
  • Feature Duplication Fix: Prevented duplicated features from inheriting transient creation states like 'In Progress' by stripping initialStatus and workMode fields during creation and duplication.
  • Enhanced PR Review Comments: Implemented full cursor-based pagination for review threads, added support for displaying bot comments, and now fetches top-level review body comments (summary text submitted with reviews).
  • Improved PR Comment UI: Refined the display of PR comments with better layout, a 'Bot' badge, adjusted expansion behavior (row clicks only toggle expansion if content needs it), and fixed dialog header overlap.
  • Worktree-Scoped Sessions: Agent sessions are now persisted and filtered per Git worktree, allowing each worktree to maintain its own last-selected session, and the agent header displays the current worktree branch.
  • Dev Server UX Enhancements: Starting a dev server now automatically opens its logs panel, and dev server actions are presented via a split button with clearer toast notifications including descriptive subtitles.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • apps/server/src/services/pr-review-comments.service.ts
    • Added isBot field to PRReviewComment interface.
    • Introduced MAX_PAGINATION_PAGES constant for GraphQL queries.
    • Added endCursor to GraphQL page info types for pagination.
    • Extracted executeGraphQL helper for gh CLI execution.
    • Implemented cursor-based pagination for fetchReviewThreadResolvedStatus.
    • Switched regular PR comment fetching to GitHub REST API (issues/comments) to preserve bot author info.
    • Added fetching of review body comments from GitHub REST API (pulls/reviews).
  • apps/ui/src/components/dialogs/pr-comment-resolution-dialog.tsx
    • Adjusted comment row click behavior to only toggle expansion if content needs it.
    • Moved disclosure triangle to the right action area.
    • Added 'Bot' badge display for bot comments.
    • Removed unnecessary left padding from comment body and date rows.
    • Fixed dialog header overlap with close button by adding right padding.
  • apps/ui/src/components/session-manager.tsx
    • Imported pathsEqual utility.
    • Added workingDirectory prop to scope sessions.
    • Modified session creation to use effectiveWorkingDirectory.
    • Filtered displayed sessions based on the current workingDirectory.
  • apps/ui/src/components/views/agent-view.tsx
    • Integrated getCurrentWorktree to determine the effectiveWorkingDirectory.
    • Passed workingDirectory to useAgentSession and useElectronAgent hooks.
    • Passed worktreeBranch to AgentHeader for display.
  • apps/ui/src/components/views/agent-view/components/agent-header.tsx
    • Imported GitBranch icon.
    • Added worktreeBranch prop.
    • Displayed the current worktree branch name as a pill badge next to the project name.
  • apps/ui/src/components/views/agent-view/hooks/use-agent-session.ts
    • Added workingDirectory to UseAgentSessionOptions.
    • Updated session persistence key to use workingDirectory for worktree-specific sessions.
    • Modified useEffect hooks to react to persistenceKey changes, ensuring session reset and restore per worktree.
  • apps/ui/src/components/views/board-view.tsx
    • Implemented a fallback to the main worktree if the currently selected worktree is deleted.
    • Reset the selected worktree to main immediately after a deleted worktree was active.
  • apps/ui/src/components/views/board-view/hooks/use-board-actions.ts
    • Modified feature creation to strip initialStatus and workMode transient fields.
    • Modified feature duplication to strip initialStatus and workMode transient fields.
  • apps/ui/src/components/views/board-view/worktree-panel/components/worktree-actions-dropdown.tsx
    • Refactored 'Start/Stop Dev Server' and 'View Logs' into a split button with a submenu for logs.
  • apps/ui/src/components/views/board-view/worktree-panel/hooks/use-dev-servers.ts
    • Enhanced toast notifications for dev server start/failure with descriptive subtitles directing users to logs.
  • apps/ui/src/components/views/board-view/worktree-panel/worktree-panel.tsx
    • Configured dev server start action to automatically open the logs panel.
  • apps/ui/src/lib/electron.ts
    • Added isBot property to the PRReviewComment interface for bot comment identification.
  • apps/ui/src/types/electron.d.ts
    • Added an optional workingDirectory field to the SessionListItem interface.
  • libs/types/src/session.ts
    • Added an optional workingDirectory field to the AgentSession interface.
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 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 counter productive. 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.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

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
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 is a substantial pull request that delivers several valuable bug fixes and quality-of-life improvements. The fix for the worktree deletion crash is a critical stability improvement. The enhancements to PR review comments, especially pagination and bot support, are excellent additions. Scoping agent sessions per worktree and the various dev server UX improvements will significantly enhance the developer experience. The code is well-structured, and the changes are clearly explained.

I've identified one critical issue related to fetching paginated GitHub comments that could cause failures. Please see the specific comment for details.

Copy link

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
apps/server/src/services/pr-review-comments.service.ts (2)

263-299: ⚠️ Potential issue | 🟡 Minor

Mark GitHub App comments as bots for accurate badges.
When performed_via_github_app is present and user is null, isBot stays false, so app comments won’t show the Bot badge.

🐛 Suggested fix
-        isBot: c.user?.type === 'Bot',
+        isBot: c.user?.type === 'Bot' || !!c.performed_via_github_app,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/services/pr-review-comments.service.ts` around lines 263 -
299, In the regularComments mapping inside pr-review-comments.service.ts update
the isBot logic so GitHub App comments are treated as bots: replace isBot:
c.user?.type === 'Bot' with a conditional that marks the comment as a bot when
c.user is present and c.user.type === 'Bot', or when c.user is null/undefined
but c.performed_via_github_app is truthy (e.g. isBot: c.user ? c.user.type ===
'Bot' : !!c.performed_via_github_app); this ensures comments with
performed_via_github_app show the Bot badge.

250-257: ⚠️ Potential issue | 🟠 Major

Emit events for PR review comment fetching in the route handler.

The fetchPRReviewComments() service function performs remote API calls, but neither the service nor the route handler emit any events via createEventEmitter() from lib/events.ts. Per the coding guidelines, all server operations should emit events that stream to the frontend via WebSocket. Add start/success/failure event emissions in createListPRReviewCommentsHandler() to allow the frontend to observe fetch progress.

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

In `@apps/server/src/services/pr-review-comments.service.ts` around lines 250 -
257, The route handler createListPRReviewCommentsHandler currently calls
fetchPRReviewComments but does not emit progress events; update
createListPRReviewCommentsHandler to use createEventEmitter() to emit a
"pr:comments:fetch:start" event before calling
fetchPRReviewComments(projectPath, owner, repo, prNumber), emit
"pr:comments:fetch:success" with the returned PRReviewComment[] on successful
completion, and emit "pr:comments:fetch:failure" with the error details if
fetchPRReviewComments throws; ensure the emitter is created/closed per request
and include contextual identifiers (projectPath, owner, repo, prNumber) in the
event payloads so the frontend can correlate events.
apps/ui/src/components/session-manager.tsx (1)

182-227: ⚠️ Potential issue | 🟠 Major

Wrap handleQuickCreateSession in useCallback to capture current worktree directory.

onQuickCreateRef is updated only when projectPath changes, but effectiveWorkingDirectory can change independently via the optional workingDirectory prop. When switching worktrees without changing projectPath, the ref points to a stale closure with the previous worktree path, causing quick-create to use the wrong directory.

Suggested fix
-  const handleQuickCreateSession = async () => {
+  const handleQuickCreateSession = useCallback(async () => {
     const api = getElectronAPI();
     if (!api?.sessions) return;

     const sessionName = generateRandomSessionName();

     const result = await api.sessions.create(sessionName, projectPath, effectiveWorkingDirectory);

     if (result.success && result.session?.id) {
       await invalidateSessions();
       onSelectSession(result.session.id);
     }
-  };
+  }, [effectiveWorkingDirectory, projectPath, invalidateSessions, onSelectSession]);

   // Expose the quick create function via ref for keyboard shortcuts
   useEffect(() => {
     if (onQuickCreateRef) {
       onQuickCreateRef.current = handleQuickCreateSession;
     }
     return () => {
       if (onQuickCreateRef) {
         onQuickCreateRef.current = null;
       }
     };
-  }, [onQuickCreateRef, projectPath]);
+  }, [onQuickCreateRef, handleQuickCreateSession]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/session-manager.tsx` around lines 182 - 227, The
quick-create handler currently closes over effectiveWorkingDirectory and becomes
stale; wrap handleQuickCreateSession in useCallback and include
effectiveWorkingDirectory (or workingDirectory and projectPath) in its
dependency array so it always captures the current worktree, then change the
useEffect to assign onQuickCreateRef.current = handleQuickCreateSession and
depend on handleQuickCreateSession instead of projectPath; ensure cleanup sets
current = null as before.
🧹 Nitpick comments (1)
apps/ui/src/components/views/agent-view/components/agent-header.tsx (1)

37-48: Consider truncating long branch names in the badge.
Long branch names can stretch the header; a max-width + truncate keeps layout stable.

🧩 Suggested tweak
-            {worktreeBranch && (
-              <span className="inline-flex items-center gap-1 text-xs bg-muted/50 px-2 py-0.5 rounded-full border border-border">
-                <GitBranch className="w-3 h-3" />
-                {worktreeBranch}
-              </span>
-            )}
+            {worktreeBranch && (
+              <span className="inline-flex items-center gap-1 text-xs bg-muted/50 px-2 py-0.5 rounded-full border border-border">
+                <GitBranch className="w-3 h-3" />
+                <span className="max-w-[180px] truncate">{worktreeBranch}</span>
+              </span>
+            )}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/views/agent-view/components/agent-header.tsx` around
lines 37 - 48, The worktreeBranch badge can overflow; update the span that
renders worktreeBranch (the element inside the conditional that includes
GitBranch and {worktreeBranch}) to constrain long branch names by adding a
max-width and text truncation classes/styles (e.g., a utility class like
max-w-[120px] plus truncate or equivalent CSS) so the badge keeps its rounded
layout; ensure the GitBranch icon remains visible and the branch text uses
overflow-ellipsis/white-space-nowrap to show a single-line truncated name.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/server/src/services/pr-review-comments.service.ts`:
- Around line 263-299: In the regularComments mapping inside
pr-review-comments.service.ts update the isBot logic so GitHub App comments are
treated as bots: replace isBot: c.user?.type === 'Bot' with a conditional that
marks the comment as a bot when c.user is present and c.user.type === 'Bot', or
when c.user is null/undefined but c.performed_via_github_app is truthy (e.g.
isBot: c.user ? c.user.type === 'Bot' : !!c.performed_via_github_app); this
ensures comments with performed_via_github_app show the Bot badge.
- Around line 250-257: The route handler createListPRReviewCommentsHandler
currently calls fetchPRReviewComments but does not emit progress events; update
createListPRReviewCommentsHandler to use createEventEmitter() to emit a
"pr:comments:fetch:start" event before calling
fetchPRReviewComments(projectPath, owner, repo, prNumber), emit
"pr:comments:fetch:success" with the returned PRReviewComment[] on successful
completion, and emit "pr:comments:fetch:failure" with the error details if
fetchPRReviewComments throws; ensure the emitter is created/closed per request
and include contextual identifiers (projectPath, owner, repo, prNumber) in the
event payloads so the frontend can correlate events.

In `@apps/ui/src/components/session-manager.tsx`:
- Around line 182-227: The quick-create handler currently closes over
effectiveWorkingDirectory and becomes stale; wrap handleQuickCreateSession in
useCallback and include effectiveWorkingDirectory (or workingDirectory and
projectPath) in its dependency array so it always captures the current worktree,
then change the useEffect to assign onQuickCreateRef.current =
handleQuickCreateSession and depend on handleQuickCreateSession instead of
projectPath; ensure cleanup sets current = null as before.

---

Nitpick comments:
In `@apps/ui/src/components/views/agent-view/components/agent-header.tsx`:
- Around line 37-48: The worktreeBranch badge can overflow; update the span that
renders worktreeBranch (the element inside the conditional that includes
GitBranch and {worktreeBranch}) to constrain long branch names by adding a
max-width and text truncation classes/styles (e.g., a utility class like
max-w-[120px] plus truncate or equivalent CSS) so the badge keeps its rounded
layout; ensure the GitBranch icon remains visible and the branch text uses
overflow-ellipsis/white-space-nowrap to show a single-line truncated name.

- Include GitHub app-initiated comments in bot detection
- Wrap handleQuickCreateSession with useCallback to fix dependency issues
- Truncate long branch names in agent header to prevent layout overflow
Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/ui/src/components/session-manager.tsx (1)

300-310: ⚠️ Potential issue | 🟠 Major

Bug: fallback after session deletion uses unscoped sessions instead of scopedSessions.

When the currently-selected session is deleted, the fallback on Line 303 filters the global sessions list. Since the rest of the component now scopes to the current worktree via scopedSessions, this can select a session belonging to a different worktree.

🐛 Proposed fix
       if (currentSessionId === sessionId) {
         // Switch to another session or create a new one
-        const activeSessionsList = sessions.filter((s) => !s.isArchived);
+        const activeSessionsList = scopedSessions.filter((s) => !s.isArchived && s.id !== sessionId);
         if (activeSessionsList.length > 0) {
           onSelectSession(activeSessionsList[0].id);
+        } else {
+          onSelectSession(null);
         }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/session-manager.tsx` around lines 300 - 310, The
deletion fallback currently uses the global sessions list which can pick a
session from the wrong worktree; update the logic inside the delete handler (the
block that calls invalidateSessions and checks if currentSessionId ===
sessionId) to use scopedSessions instead of sessions (i.e., replace
sessions.filter(...) with scopedSessions.filter(...)) so the chosen active
session comes from the same worktree; keep the rest of the flow (onSelectSession
and setSessionToDelete(null)) unchanged.
apps/server/src/services/pr-review-comments.service.ts (1)

348-356: ⚠️ Potential issue | 🟡 Minor

Inconsistent bot detection: performed_via_github_app not checked for inline review comments or review body comments.

Section 1 (issue comments, line 298) detects bots with c.user?.type === 'Bot' || !!c.performed_via_github_app, but sections 2 and 3 only check c.user?.type === 'Bot'. The GitHub REST API also returns performed_via_github_app on pull request review comments and reviews, so app-initiated review comments won't be flagged as bot here.

♻️ Suggested fix for inline review comments (similar for review body)
-        isBot: c.user?.type === 'Bot',
+        isBot: c.user?.type === 'Bot' || !!c.performed_via_github_app,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/services/pr-review-comments.service.ts` around lines 348 -
356, The isBot check for inline review comments (the object being built with
properties isOutdated, isResolved, isBot, diffHunk, side, commitId) is missing
the performed_via_github_app check; update the isBot assignment (currently
c.user?.type === 'Bot') to match the issue-comments logic by using c.user?.type
=== 'Bot' || !!c.performed_via_github_app so app-created review comments and
review body comments are flagged as bots as well.
🧹 Nitpick comments (2)
apps/ui/src/components/views/agent-view/components/agent-header.tsx (1)

42-47: Add a title attribute so truncated branch names are visible on hover.

With max-w-[180px] truncate, long branch names get clipped. A title on the outer <span> lets users hover to see the full name.

💡 Suggested improvement
             {worktreeBranch && (
-              <span className="inline-flex items-center gap-1 text-xs bg-muted/50 px-2 py-0.5 rounded-full border border-border">
+              <span
+                className="inline-flex items-center gap-1 text-xs bg-muted/50 px-2 py-0.5 rounded-full border border-border"
+                title={worktreeBranch}
+              >
                 <GitBranch className="w-3 h-3 shrink-0" />
                 <span className="max-w-[180px] truncate">{worktreeBranch}</span>
               </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/views/agent-view/components/agent-header.tsx` around
lines 42 - 47, The branch name span in the AgentHeader component clips long
names due to max-w-[180px] truncate; update the outer conditional span (the one
wrapping GitBranch and the {worktreeBranch} text) to include a title attribute
set to worktreeBranch so the full branch name is visible on hover (refer to the
render that checks worktreeBranch in agent-header.tsx and the span containing
GitBranch and the truncated {worktreeBranch}).
apps/ui/src/components/session-manager.tsx (1)

182-192: Consider guarding effectiveWorkingDirectory against empty strings.

If both workingDirectory and projectPath are empty or undefined (e.g., during initialization), effectiveWorkingDirectory would be "" (or undefined), causing scopedSessions to behave unpredictably and the create call to receive an invalid path. A defensive check may be worthwhile.

💡 Suggested guard
  const effectiveWorkingDirectory = workingDirectory || projectPath;
+
+  // Safety: if neither path is available, bail out of session operations
+  if (!effectiveWorkingDirectory) {
+    logger.warn('No working directory or project path available');
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/session-manager.tsx` around lines 182 - 192, The
computed effectiveWorkingDirectory used in handleCreateSession can end up as an
empty string which breaks scopedSessions and api.sessions.create; update the
logic in handleCreateSession (or where effectiveWorkingDirectory is defined) to
defensively normalize/guard empty values — e.g., use trimmed checks on
workingDirectory and projectPath, and set effectiveWorkingDirectory to undefined
(or null) when both are empty so you never pass "" into api.sessions.create;
ensure references in this change include effectiveWorkingDirectory,
handleCreateSession, workingDirectory, projectPath and the call to
api.sessions.create so reviewers can locate the fix.
🤖 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/server/src/services/pr-review-comments.service.ts`:
- Around line 106-151: The executeGraphQL function can crash if gh.stdin emits
an 'error' when the child is killed; add an 'error' listener on gh.stdin (e.g.
gh.stdin.on('error', (err) => {/* noop or optionally log */})) before calling
gh.stdin.write(requestBody) so the stream error is handled; ensure the listener
is attached early (after spawn and before write) and can be left as a no-op or
used to reject the enclosing Promise if you prefer to propagate the error.

---

Outside diff comments:
In `@apps/server/src/services/pr-review-comments.service.ts`:
- Around line 348-356: The isBot check for inline review comments (the object
being built with properties isOutdated, isResolved, isBot, diffHunk, side,
commitId) is missing the performed_via_github_app check; update the isBot
assignment (currently c.user?.type === 'Bot') to match the issue-comments logic
by using c.user?.type === 'Bot' || !!c.performed_via_github_app so app-created
review comments and review body comments are flagged as bots as well.

In `@apps/ui/src/components/session-manager.tsx`:
- Around line 300-310: The deletion fallback currently uses the global sessions
list which can pick a session from the wrong worktree; update the logic inside
the delete handler (the block that calls invalidateSessions and checks if
currentSessionId === sessionId) to use scopedSessions instead of sessions (i.e.,
replace sessions.filter(...) with scopedSessions.filter(...)) so the chosen
active session comes from the same worktree; keep the rest of the flow
(onSelectSession and setSessionToDelete(null)) unchanged.

---

Nitpick comments:
In `@apps/ui/src/components/session-manager.tsx`:
- Around line 182-192: The computed effectiveWorkingDirectory used in
handleCreateSession can end up as an empty string which breaks scopedSessions
and api.sessions.create; update the logic in handleCreateSession (or where
effectiveWorkingDirectory is defined) to defensively normalize/guard empty
values — e.g., use trimmed checks on workingDirectory and projectPath, and set
effectiveWorkingDirectory to undefined (or null) when both are empty so you
never pass "" into api.sessions.create; ensure references in this change include
effectiveWorkingDirectory, handleCreateSession, workingDirectory, projectPath
and the call to api.sessions.create so reviewers can locate the fix.

In `@apps/ui/src/components/views/agent-view/components/agent-header.tsx`:
- Around line 42-47: The branch name span in the AgentHeader component clips
long names due to max-w-[180px] truncate; update the outer conditional span (the
one wrapping GitBranch and the {worktreeBranch} text) to include a title
attribute set to worktreeBranch so the full branch name is visible on hover
(refer to the render that checks worktreeBranch in agent-header.tsx and the span
containing GitBranch and the truncated {worktreeBranch}).

Copy link

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/ui/src/components/session-manager.tsx (1)

294-310: ⚠️ Potential issue | 🟠 Major

Stale closure + deleted session not excluded from next-session candidates.

confirmDeleteSession captures scopedSessions from the enclosing render. After await invalidateSessions() (which awaits a full refetch), the component schedules a re-render, but the still-executing async closure holds the old scopedSessions — one that still contains the just-deleted session. The filter at line 303 also does not exclude sessionId, so if the deleted session is at index 0 (e.g., it was the only active session), onSelectSession is called with the deleted session's ID.

🐛 Proposed fix — exclude the deleted session from the candidate list
-        const activeSessionsList = scopedSessions.filter((s) => !s.isArchived);
+        const activeSessionsList = scopedSessions.filter(
+          (s) => !s.isArchived && s.id !== sessionId
+        );

Alternatively, use the fresh data returned from invalidateSessions to avoid the stale-closure issue entirely:

  const confirmDeleteSession = async (sessionId: string) => {
    const api = getElectronAPI();
    if (!api?.sessions) return;

    const result = await api.sessions.delete(sessionId);
    if (result.success) {
-     await invalidateSessions();
+     const freshSessions = await invalidateSessions();
      if (currentSessionId === sessionId) {
-       const activeSessionsList = scopedSessions.filter((s) => !s.isArchived);
+       const freshScoped = (freshSessions ?? []).filter((s) => {
+         const dir = s.workingDirectory || s.projectPath;
+         return pathsEqual(dir, effectiveWorkingDirectory) && !s.isArchived && s.id !== sessionId;
+       });
-       if (activeSessionsList.length > 0) {
-         onSelectSession(activeSessionsList[0].id);
+       if (freshScoped.length > 0) {
+         onSelectSession(freshScoped[0].id);
        }
      }
    }
    setSessionToDelete(null);
  };

(requires invalidateSessions to return the refetched data)

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

In `@apps/ui/src/components/session-manager.tsx` around lines 294 - 310,
confirmDeleteSession currently uses the stale scopedSessions captured by the
async closure and its candidate filter doesn't exclude the deleted session;
update confirmDeleteSession to use fresh session data after invalidation (e.g.,
await the refetch result returned from invalidateSessions or read the latest
sessions state/ref after invalidateSessions completes) and when building the
activeSessionsList filter exclude the deleted sessionId (use filter(s =>
!s.isArchived && s.id !== sessionId)) before calling onSelectSession; keep
setSessionToDelete(null) at the end.
🧹 Nitpick comments (1)
apps/server/src/services/pr-review-comments.service.ts (1)

266-310: Consider extracting the repeated REST fetch-parse-map pattern into a shared helper.

All three comment-fetching blocks (regular issue comments, inline review comments, review body comments) follow an identical structure:

  1. Build gh api <endpoint> --paginate args
  2. execFileAsync with the same cwd, env, maxBuffer, timeout
  3. JSON.parse the output
  4. Guard with Array.isArray(...) ? ... : []
  5. .filter/.map to PRReviewComment
  6. push into allComments
  7. catchlogError

A small helper like fetchGitHubRestPages<T>(projectPath, endpoint): Promise<T[]> would eliminate ~30 lines of duplication and make it easier to adjust buffer sizes or timeouts uniformly in the future.

♻️ Sketch of a potential helper
async function fetchGitHubRestPages<T>(projectPath: string, endpoint: string): Promise<T[]> {
  const { stdout } = await execFileAsync(
    'gh',
    ['api', endpoint, '--paginate'],
    {
      cwd: projectPath,
      env: execEnv,
      maxBuffer: 1024 * 1024 * 10,
      timeout: GITHUB_API_TIMEOUT_MS,
    }
  );
  const data = JSON.parse(stdout);
  return Array.isArray(data) ? data : [];
}

Each call site would then just do:

const raw = await fetchGitHubRestPages<IssueComment>(projectPath, `repos/${owner}/${repo}/issues/${prNumber}/comments`);
const regularComments = raw.map(c => ({ /* mapping */ }));

Also applies to: 312-366, 368-415

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

In `@apps/server/src/services/pr-review-comments.service.ts` around lines 266 -
310, Extract the repeated REST fetch/parse logic into a helper like
fetchGitHubRestPages<T>(projectPath: string, endpoint: string): Promise<T[]>
that calls execFileAsync('gh', ['api', endpoint, '--paginate'], { cwd:
projectPath, env: execEnv, maxBuffer: 1024*1024*10, timeout:
GITHUB_API_TIMEOUT_MS }), JSON.parses stdout and returns Array.isArray(data) ?
data : []; then replace the three duplicated blocks that build endpoints and
call execFileAsync (the regular issue comments, inline review comments, and
review body comments) to instead call fetchGitHubRestPages with the same
endpoint and map the returned items to your PRReviewComment shape before pushing
into allComments; keep the existing try/catch semantics at each call site (use
logError on failure) so error handling and context remain identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@apps/ui/src/components/session-manager.tsx`:
- Around line 294-310: confirmDeleteSession currently uses the stale
scopedSessions captured by the async closure and its candidate filter doesn't
exclude the deleted session; update confirmDeleteSession to use fresh session
data after invalidation (e.g., await the refetch result returned from
invalidateSessions or read the latest sessions state/ref after
invalidateSessions completes) and when building the activeSessionsList filter
exclude the deleted sessionId (use filter(s => !s.isArchived && s.id !==
sessionId)) before calling onSelectSession; keep setSessionToDelete(null) at the
end.

---

Nitpick comments:
In `@apps/server/src/services/pr-review-comments.service.ts`:
- Around line 266-310: Extract the repeated REST fetch/parse logic into a helper
like fetchGitHubRestPages<T>(projectPath: string, endpoint: string):
Promise<T[]> that calls execFileAsync('gh', ['api', endpoint, '--paginate'], {
cwd: projectPath, env: execEnv, maxBuffer: 1024*1024*10, timeout:
GITHUB_API_TIMEOUT_MS }), JSON.parses stdout and returns Array.isArray(data) ?
data : []; then replace the three duplicated blocks that build endpoints and
call execFileAsync (the regular issue comments, inline review comments, and
review body comments) to instead call fetchGitHubRestPages with the same
endpoint and map the returned items to your PRReviewComment shape before pushing
into allComments; keep the existing try/catch semantics at each call site (use
logError on failure) so error handling and context remain identical.

Copy link

@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

🤖 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/ui/src/components/session-manager.tsx`:
- Around line 301-308: The next-session selection after deleting the current
session uses unscoped freshSessions from invalidateSessions(), which can pick
sessions from other worktrees; update the logic in the block using
currentSessionId/sessionId to first filter freshSessions by the current worktree
the same way scopedSessions does (use pathsEqual to compare session.path against
the current worktree path), then compute activeSessionsList from that scoped set
(exclude isArchived and the deleted session), and if none remain call
onSelectSession(null) so the selection is cleared instead of leaving a stale
selection; ensure you reference/integrate the existing pathsEqual helper and the
onSelectSession/invalidateSessions variables in the change.

Comment on lines +301 to 308
const refetchResult = await invalidateSessions();
if (currentSessionId === sessionId) {
// Switch to another session or create a new one
const activeSessionsList = sessions.filter((s) => !s.isArchived);
// Switch to another session using fresh data, excluding the deleted session
const freshSessions = refetchResult?.data ?? [];
const activeSessionsList = freshSessions.filter((s) => !s.isArchived && s.id !== sessionId);
if (activeSessionsList.length > 0) {
onSelectSession(activeSessionsList[0].id);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Next-session selection after delete ignores worktree scope.

After deleting the currently selected session, freshSessions is the unscoped list from the query cache, so activeSessionsList may contain sessions from other worktrees. The user could be auto-switched to a session that doesn't even appear in their current (worktree-scoped) session list.

Apply the same pathsEqual filtering used for scopedSessions:

🐛 Proposed fix — scope next-session selection to the current worktree
       const refetchResult = await invalidateSessions();
       if (currentSessionId === sessionId) {
         // Switch to another session using fresh data, excluding the deleted session
         const freshSessions = refetchResult?.data ?? [];
-        const activeSessionsList = freshSessions.filter((s) => !s.isArchived && s.id !== sessionId);
+        const activeSessionsList = freshSessions.filter((s) => {
+          if (s.isArchived || s.id === sessionId) return false;
+          const sessionDir = s.workingDirectory || s.projectPath;
+          return pathsEqual(sessionDir, effectiveWorkingDirectory);
+        });
         if (activeSessionsList.length > 0) {
           onSelectSession(activeSessionsList[0].id);
+        } else {
+          onSelectSession(null);
         }
       }

Also note that the current code silently does nothing when no active sessions remain (falls through without calling onSelectSession(null)), leaving a stale selection. The else branch above handles that.

📝 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 refetchResult = await invalidateSessions();
if (currentSessionId === sessionId) {
// Switch to another session or create a new one
const activeSessionsList = sessions.filter((s) => !s.isArchived);
// Switch to another session using fresh data, excluding the deleted session
const freshSessions = refetchResult?.data ?? [];
const activeSessionsList = freshSessions.filter((s) => !s.isArchived && s.id !== sessionId);
if (activeSessionsList.length > 0) {
onSelectSession(activeSessionsList[0].id);
}
const refetchResult = await invalidateSessions();
if (currentSessionId === sessionId) {
// Switch to another session using fresh data, excluding the deleted session
const freshSessions = refetchResult?.data ?? [];
const activeSessionsList = freshSessions.filter((s) => {
if (s.isArchived || s.id === sessionId) return false;
const sessionDir = s.workingDirectory || s.projectPath;
return pathsEqual(sessionDir, effectiveWorkingDirectory);
});
if (activeSessionsList.length > 0) {
onSelectSession(activeSessionsList[0].id);
} else {
onSelectSession(null);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/ui/src/components/session-manager.tsx` around lines 301 - 308, The
next-session selection after deleting the current session uses unscoped
freshSessions from invalidateSessions(), which can pick sessions from other
worktrees; update the logic in the block using currentSessionId/sessionId to
first filter freshSessions by the current worktree the same way scopedSessions
does (use pathsEqual to compare session.path against the current worktree path),
then compute activeSessionsList from that scoped set (exclude isArchived and the
deleted session), and if none remain call onSelectSession(null) so the selection
is cleared instead of leaving a stale selection; ensure you reference/integrate
the existing pathsEqual helper and the onSelectSession/invalidateSessions
variables in the change.

@gsxdsm gsxdsm merged commit f3edfbf into AutoMaker-Org:v0.15.0rc Feb 21, 2026
7 checks passed
gsxdsm added a commit to gsxdsm/automaker that referenced this pull request Feb 21, 2026
…AutoMaker-Org#792)

* Changes from fix/delete-worktree-hotifx

* fix: Improve bot detection and prevent UI overflow issues

- Include GitHub app-initiated comments in bot detection
- Wrap handleQuickCreateSession with useCallback to fix dependency issues
- Truncate long branch names in agent header to prevent layout overflow

* feat: Support GitHub App comments in PR review and fix session filtering

* feat: Return invalidation result from delete session handler
@gsxdsm gsxdsm deleted the fix/delete-worktree-hotifx branch February 21, 2026 19:11
gsxdsm added a commit that referenced this pull request Feb 21, 2026
* Changes from fix/docker-compose-cors-error

* Update apps/server/src/index.ts

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* Fix: Delete Worktree Crash + PR Comments + Dev Server UX Improvements (#792)

* Changes from fix/delete-worktree-hotifx

* fix: Improve bot detection and prevent UI overflow issues

- Include GitHub app-initiated comments in bot detection
- Wrap handleQuickCreateSession with useCallback to fix dependency issues
- Truncate long branch names in agent header to prevent layout overflow

* feat: Support GitHub App comments in PR review and fix session filtering

* feat: Return invalidation result from delete session handler

* fix: Improve CORS origin validation to handle wildcard correctly

* fix: Correct IPv6 localhost parsing and improve responsive UI layouts

* Changes from fix/pwa-cache-fix (#794)

* fix: Add type checking to prevent crashes from malformed cache entries

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
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