Skip to content

fix: worktree sessions showing Ungrouped toast when parent is grouped#740

Merged
pedramamini merged 2 commits intoRunMaestro:rcfrom
scriptease:worktree-toast
Apr 7, 2026
Merged

fix: worktree sessions showing Ungrouped toast when parent is grouped#740
pedramamini merged 2 commits intoRunMaestro:rcfrom
scriptease:worktree-toast

Conversation

@scriptease
Copy link
Copy Markdown

@scriptease scriptease commented Apr 6, 2026

When moving a session with children (or git work trees) to a group after the child is already created, it doesn't get a groupId, so it would show toasts with "Ungrouped > " even though they are technically grouped by the parent session.

Bildschirmfoto 2026-04-06 um 13 56 05

Summary by CodeRabbit

  • Bug Fixes
    • Child (worktree) sessions now inherit and stay synchronized with parent session group assignments when sessions are moved or when a new group is created.
    • Notifications (task completion, batch results, history entries) now display the effective group for child sessions by falling back to the parent when needed.
    • Drag-and-drop and modal group changes consistently apply group updates to related child sessions.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 862354fd-6d36-478a-9346-428d07a9829b

📥 Commits

Reviewing files that changed from the base of the PR and between e1cacdd and 6218490.

📒 Files selected for processing (7)
  • src/renderer/components/QuickActionsModal.tsx
  • src/renderer/components/SessionList/SessionList.tsx
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/batch/useBatchHandlers.ts
  • src/renderer/hooks/session/useGroupManagement.ts
  • src/renderer/hooks/session/useSessionCrud.ts
  • src/renderer/hooks/wizard/useWizardHandlers.ts
✅ Files skipped from review due to trivial changes (2)
  • src/renderer/hooks/wizard/useWizardHandlers.ts
  • src/renderer/components/QuickActionsModal.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/renderer/hooks/session/useSessionCrud.ts
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/batch/useBatchHandlers.ts
  • src/renderer/hooks/session/useGroupManagement.ts

📝 Walkthrough

Walkthrough

Normalize falsy groupId values to undefined, propagate groupId updates from a parent session to its worktree children, and resolve a session's effective groupId by inheriting from its parent when the session lacks one; applied across UI components, hooks, and notification flows.

Changes

Cohort / File(s) Summary
Modal & List group moves
src/renderer/components/QuickActionsModal.tsx, src/renderer/components/SessionList/SessionList.tsx
Normalize falsy groupIdundefined and apply that value to the moved session and any sessions with parentSessionId equal to the moved session (sync worktree children).
Drag/drop & session CRUD
src/renderer/hooks/session/useGroupManagement.ts, src/renderer/hooks/session/useSessionCrud.ts
When dropping onto a group or applying a pending group move, set/clear groupId for both the target/dragged session and its worktree children (parentSessionId matches).
Effective group resolution for notifications/history
src/renderer/hooks/agent/useAgentListeners.ts, src/renderer/hooks/batch/useBatchHandlers.ts, src/renderer/hooks/wizard/useWizardHandlers.ts
Introduce/use an effectiveGroupId (session's groupId or fallback to parent session's groupId) and resolve group names via that value; added a resolveGroupName(...) helper in batch handlers and replaced inline lookups in multiple callbacks.

Sequence Diagram(s)

sequenceDiagram
    participant User as "User / UI"
    participant Component as "QuickActionsModal / SessionList"
    participant Store as "Session Store"
    participant Groups as "Groups Store"
    participant Notifier as "Toast / History"

    User->>Component: initiate move (groupId may be falsy)
    Component->>Store: request sessions & normalize groupId (undefined if falsy)
    Component->>Store: setSessions(updatedSessions with normalized groupId)
    Store-->>Store: update target session and sessions where parentSessionId == target.id
    Store->>Groups: request group by effectiveGroupId (session.groupId or parent's groupId)
    Groups-->>Notifier: provide group name (or 'Ungrouped')
    Component->>Notifier: emit completion/toast with resolved group name
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I nudged a parent, whispered to its brood,
Falsy IDs cleared, we found the right mood,
Children followed the leader's new tune,
Toasts chimed their names beneath the moon,
Hops and groups aligned — a tidy little rune.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 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 describes the main fix: worktree sessions incorrectly showing 'Ungrouped' in toasts when their parent session is grouped.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

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

@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)
src/renderer/hooks/session/useGroupManagement.ts (1)

129-143: ⚠️ Potential issue | 🔴 Critical

Two handlers lack worktree child sync in move-to-group paths — inconsistent group assignment possible.

Lines 133-138 correctly sync children for drag/drop operations. However, src/renderer/hooks/session/useSessionCrud.ts:468 and src/renderer/components/SessionList/SessionList.tsx:334 both update only the parent session without syncing direct worktree children. This creates inconsistent behavior: dragging a parent to a group syncs children, but moving via the context menu or group creation flows does not.

Required fixes for worktree child parity

In src/renderer/hooks/session/useSessionCrud.ts:468:

  setSessions((prev) =>
-   prev.map((s) => (s.id === pendingMoveToGroupSessionId ? { ...s, groupId } : s))
+   prev.map((s) => {
+     if (s.id === pendingMoveToGroupSessionId) return { ...s, groupId };
+     if (s.parentSessionId === pendingMoveToGroupSessionId) return { ...s, groupId };
+     return s;
+   })
  );

In src/renderer/components/SessionList/SessionList.tsx:334:

  setSessions((prev) =>
-   prev.map((s) => (s.id === sessionId ? { ...s, groupId: groupId || undefined } : s))
+   prev.map((s) => {
+     if (s.id === sessionId) return { ...s, groupId: groupId || undefined };
+     if (s.parentSessionId === sessionId) return { ...s, groupId: groupId || undefined };
+     return s;
+   })
  );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/hooks/session/useGroupManagement.ts` around lines 129 - 143, The
drag/drop handler handleDropOnGroup updates both the moved session and its
direct worktree children; replicate that parity in the other move-to-group code
paths: in the session update routine inside useSessionCrud (the function that
assigns a new groupId to a session) and in the context-menu/group-move handler
in SessionList.tsx, when setting a session's groupId also iterate the sessions
state and update any session whose parentSessionId === movedSessionId to the
same groupId (use the same setSessions(prev => prev.map(...)) pattern used in
handleDropOnGroup and clear any dragging state as appropriate).
🧹 Nitpick comments (2)
src/renderer/hooks/batch/useBatchHandlers.ts (1)

216-225: Extract effective-group resolution into a local helper to prevent drift.

The fallback logic is duplicated in two callbacks; centralizing it will keep toast attribution consistent.

Refactor sketch
+function resolveEffectiveGroupName(
+	sessionId: string,
+	sessions: { id: string; groupId?: string; parentSessionId?: string }[],
+	groups: { id: string; name: string }[]
+): string {
+	const session = sessions.find((s) => s.id === sessionId);
+	const effectiveGroupId =
+		session?.groupId ||
+		(session?.parentSessionId
+			? sessions.find((s) => s.id === session.parentSessionId)?.groupId
+			: undefined);
+	return groups.find((g) => g.id === effectiveGroupId)?.name || 'Ungrouped';
+}

Then use resolveEffectiveGroupName(info.sessionId, currentSessions, currentGroups) in both onComplete and onPRResult.

Also applies to: 517-524

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

In `@src/renderer/hooks/batch/useBatchHandlers.ts` around lines 216 - 225, Extract
the duplicated fallback logic that computes effectiveGroupId/group name into a
local helper function named e.g. resolveEffectiveGroupName(sessionId,
currentSessions, currentGroups) that returns the resolved group (or null); move
the block that looks up session via currentSessions, checks session.groupId or
session.parentSessionId, and finds the group in currentGroups into that helper,
then replace the inline logic in both onComplete and onPRResult callbacks to
call resolveEffectiveGroupName(info.sessionId, currentSessions, currentGroups)
so toast attribution is determined in one place and stays consistent.
src/renderer/components/QuickActionsModal.tsx (1)

317-322: Normalize “no group” to undefined before writing session state.

This keeps grouping state canonical and avoids mixing '' and undefined as ungrouped sentinels.

Proposed cleanup
 const handleMoveToGroup = (groupId: string) => {
+	const normalizedGroupId = groupId || undefined;
 	const updatedSessions = sessions.map((s) => {
-		if (s.id === activeSessionId) return { ...s, groupId };
+		if (s.id === activeSessionId) return { ...s, groupId: normalizedGroupId };
 		// Also update worktree children to keep groupId in sync
-		if (s.parentSessionId === activeSessionId) return { ...s, groupId };
+		if (s.parentSessionId === activeSessionId) return { ...s, groupId: normalizedGroupId };
 		return s;
 	});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/components/QuickActionsModal.tsx` around lines 317 - 322,
Normalize the "no group" sentinel by converting '' to undefined before writing
session state: compute a normalizedGroupId (groupId === '' ? undefined :
groupId) and use that in the sessions.map update (the block that returns { ...s,
groupId }) so both the active session and any worktree children (checked via
parentSessionId and activeSessionId) get undefined for ungrouped instead of ''.
Update any other writes that set groupId in this component to use the normalized
value.
🤖 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 `@src/renderer/hooks/session/useGroupManagement.ts`:
- Around line 129-143: The drag/drop handler handleDropOnGroup updates both the
moved session and its direct worktree children; replicate that parity in the
other move-to-group code paths: in the session update routine inside
useSessionCrud (the function that assigns a new groupId to a session) and in the
context-menu/group-move handler in SessionList.tsx, when setting a session's
groupId also iterate the sessions state and update any session whose
parentSessionId === movedSessionId to the same groupId (use the same
setSessions(prev => prev.map(...)) pattern used in handleDropOnGroup and clear
any dragging state as appropriate).

---

Nitpick comments:
In `@src/renderer/components/QuickActionsModal.tsx`:
- Around line 317-322: Normalize the "no group" sentinel by converting '' to
undefined before writing session state: compute a normalizedGroupId (groupId ===
'' ? undefined : groupId) and use that in the sessions.map update (the block
that returns { ...s, groupId }) so both the active session and any worktree
children (checked via parentSessionId and activeSessionId) get undefined for
ungrouped instead of ''. Update any other writes that set groupId in this
component to use the normalized value.

In `@src/renderer/hooks/batch/useBatchHandlers.ts`:
- Around line 216-225: Extract the duplicated fallback logic that computes
effectiveGroupId/group name into a local helper function named e.g.
resolveEffectiveGroupName(sessionId, currentSessions, currentGroups) that
returns the resolved group (or null); move the block that looks up session via
currentSessions, checks session.groupId or session.parentSessionId, and finds
the group in currentGroups into that helper, then replace the inline logic in
both onComplete and onPRResult callbacks to call
resolveEffectiveGroupName(info.sessionId, currentSessions, currentGroups) so
toast attribution is determined in one place and stays consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6da63be3-a8b3-49de-930b-7b0f15ca5581

📥 Commits

Reviewing files that changed from the base of the PR and between 2a4f1cb and 3866b77.

📒 Files selected for processing (5)
  • src/renderer/components/QuickActionsModal.tsx
  • src/renderer/hooks/agent/useAgentListeners.ts
  • src/renderer/hooks/batch/useBatchHandlers.ts
  • src/renderer/hooks/session/useGroupManagement.ts
  • src/renderer/hooks/wizard/useWizardHandlers.ts

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 6, 2026

Greptile Summary

Fixes worktree child sessions incorrectly showing "Ungrouped >" in toast notifications when their parent was moved to a group after the child was already created. The fix takes a two-pronged approach: proactively sync all children's groupId whenever a parent is moved via drag-and-drop (handleDropOnGroup/handleDropOnUngrouped) or Quick Actions (handleMoveToGroup), and add a reactive effectiveGroupId fallback in every toast notification handler that walks up to the parent session's groupId when the child's own groupId is unset.

Confidence Score: 5/5

Safe to merge — fix is correct, two-pronged, and covers all toast notification call sites

No P0 or P1 issues found. The proactive groupId sync on parent moves handles future reparenting correctly, and the reactive effectiveGroupId fallback in all five notification handlers covers sessions created before the parent was grouped. Verified that all notifyToast call sites with a group: property use the new pattern. The one minor inconsistency (Quick Actions 'No Group' sets groupId to '' while drag-and-drop sets it to undefined) is a pre-existing pattern that both resolve to falsy and behave identically.

No files require special attention

Important Files Changed

Filename Overview
src/renderer/hooks/session/useGroupManagement.ts Proactively syncs worktree children's groupId when parent is drag-dropped to or from a group
src/renderer/components/QuickActionsModal.tsx Proactively syncs worktree children's groupId when parent is moved via Quick Actions
src/renderer/hooks/batch/useBatchHandlers.ts Adds effectiveGroupId fallback in onComplete and onPRResult so worktree children show parent's group name in auto-run and PR toasts
src/renderer/hooks/agent/useAgentListeners.ts Adds effectiveGroupId fallback in task-complete notification so worktree children resolve to the parent's group name
src/renderer/hooks/wizard/useWizardHandlers.ts Adds effectiveGroupId fallback in synopsis notification so worktree children resolve to the parent's group name

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[User moves parent session to a group] --> B{Action type}
    B -- Drag-and-drop --> C[handleDropOnGroup / handleDropOnUngrouped]
    B -- Quick Actions --> D[handleMoveToGroup]
    C --> E[Update parent groupId]
    D --> E
    E --> F[Also update all sessions where parentSessionId === movedSessionId]
    F --> G[Children groupId now in sync]

    H[Toast notification fires for a session] --> I{session.groupId set?}
    I -- Yes --> J[Use session.groupId directly]
    I -- No --> K{session.parentSessionId set?}
    K -- Yes --> L[Look up parent session's groupId]
    K -- No --> M[Show 'Ungrouped']
    L --> N{Parent groupId found?}
    N -- Yes --> O[Show parent's group name]
    N -- No --> M
Loading

Reviews (1): Last reviewed commit: "fix: worktree sessions showing Ungrouped..." | Re-trigger Greptile

Copy link
Copy Markdown

@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)
src/renderer/hooks/batch/useBatchHandlers.ts (1)

38-55: Consider extracting resolveGroupName to a shared utility.

This same logic exists inline in useAgentListeners.ts (lines 419-427). Extracting to a shared utility (e.g., src/renderer/utils/sessionUtils.ts) would eliminate duplication and ensure consistency if the fallback logic ever needs to change.

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

In `@src/renderer/hooks/batch/useBatchHandlers.ts` around lines 38 - 55, Extract
the duplicate resolveGroupName logic into a shared utility function (e.g.,
sessionUtils) and replace the inline implementations in both useBatchHandlers
(function resolveGroupName) and useAgentListeners (the identical fallback block)
with an import of that utility; ensure the utility accepts (sessionId, sessions,
groups) and returns the same string fallback ('Ungrouped') so callers continue
to work without other changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/renderer/hooks/batch/useBatchHandlers.ts`:
- Around line 38-55: Extract the duplicate resolveGroupName logic into a shared
utility function (e.g., sessionUtils) and replace the inline implementations in
both useBatchHandlers (function resolveGroupName) and useAgentListeners (the
identical fallback block) with an import of that utility; ensure the utility
accepts (sessionId, sessions, groups) and returns the same string fallback
('Ungrouped') so callers continue to work without other changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f0617a3d-3f0e-42b6-a343-74eab1e02e3d

📥 Commits

Reviewing files that changed from the base of the PR and between 3866b77 and e1cacdd.

📒 Files selected for processing (4)
  • src/renderer/components/QuickActionsModal.tsx
  • src/renderer/components/SessionList/SessionList.tsx
  • src/renderer/hooks/batch/useBatchHandlers.ts
  • src/renderer/hooks/session/useSessionCrud.ts

@pedramamini
Copy link
Copy Markdown
Collaborator

Thank you for this contribution, @scriptease! Great catch on the worktree child sessions not inheriting their parent's group.

The two-pronged approach (proactive sync on group moves + reactive fallback in toast/notification handlers) is solid and covers all the code paths comprehensively. The resolveGroupName helper in useBatchHandlers.ts is a nice DRY improvement too.

CI failures (lint-and-format, test) are pre-existing on the rc base branch and not introduced by this PR.

LGTM — approving!

Sync worktree children groupId when parent is moved to a group, and
fall back to parent group in notification group name resolution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…lize sentinel, extract helper

- useSessionCrud handleGroupCreated: propagate groupId to worktree children
- SessionList handleMoveToGroup: propagate groupId to worktree children
- QuickActionsModal: normalize empty string groupId to undefined
- useBatchHandlers: extract resolveGroupName helper for toast attribution

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pedramamini pedramamini merged commit 684b231 into RunMaestro:rc Apr 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants