Skip to content

Refine Work session lifecycle and sidebar - #973

Merged
arul28 merged 2 commits into
mainfrom
t3code/refine-ade-chat-sidebar
Jul 31, 2026
Merged

Refine Work session lifecycle and sidebar#973
arul28 merged 2 commits into
mainfrom
t3code/refine-ade-chat-sidebar

Conversation

@arul28

@arul28 arul28 commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Summary

  • modernize the Work sidebar selection, lane headers, full-bleed session rows, grouped menus, and delayed hover details
  • align settle/snooze/status behavior across desktop, Attention, CLI/TUI, push Live Activities, and iOS
  • add cross-machine routing safeguards, native parity, internal docs, and focused regression coverage

Validation

  • /quality dual-review: clean after fixes
  • desktop affected tests: 761 passed
  • ADE CLI/TUI affected tests: 696 passed
  • desktop shard 1/8: 1,334 passed
  • desktop + ADE CLI typechecks passed
  • iOS changed Swift files parse cleanly
  • internal docs validation passed

Summary by CodeRabbit

  • New Features
    • Search recent threads directly from the command palette, including remote sessions and project-aware navigation.
    • Added session lifecycle banners with wake and unsettle actions.
    • Added dynamic snooze choices, including “next week,” with clear wake-time details.
    • Redesigned session rows with hover details, status actions, lane context menus, and pull request badges.
    • Added reusable lane actions, improved lane coloring, and quiet session shelves.
  • Behavior Updates
    • Agents can no longer settle or unsettle sessions; completion is reported with notes.
    • User-stopped CLI runs no longer appear as failures.
    • Status language now consistently uses “Working,” “Done,” and “Stale.”

@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jul 31, 2026 12:16am

@arul28 arul28 changed the title Primary -> main Refine Work session lifecycle and sidebar Jul 30, 2026
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@arul28, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 34bf1e38-a172-49f8-a25a-082e5d3f4769

📥 Commits

Reviewing files that changed from the base of the PR and between 1e57088 and fd32664.

📒 Files selected for processing (21)
  • apps/ade-cli/src/adeRpcServer.test.ts
  • apps/ade-cli/src/cli.test.ts
  • apps/ade-cli/src/cli.ts
  • apps/desktop/resources/ade-cli-help.txt
  • apps/desktop/src/main/services/lanes/laneService.test.ts
  • apps/desktop/src/main/services/lanes/laneService.ts
  • apps/desktop/src/renderer/components/app/CommandPalette.test.tsx
  • apps/desktop/src/renderer/components/app/commandPaletteThreads.tsx
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/chat/ChatSurfaceShell.tsx
  • apps/desktop/src/renderer/components/settings/ChatAppearancePreview.tsx
  • apps/desktop/src/renderer/components/terminals/LaneActionsSubmenu.tsx
  • apps/desktop/src/renderer/components/terminals/SessionCard.test.tsx
  • apps/desktop/src/renderer/components/terminals/SessionCard.tsx
  • apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx
  • apps/desktop/src/renderer/components/terminals/useWorkLaneContextMenu.tsx
  • apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx
  • apps/desktop/src/shared/laneColorPalette.ts
  • apps/ios/ADE/Views/AttentionDrawer/AttentionDrawerModel.swift
  • apps/ios/ADETests/AttentionDrawerModelTests.swift
  • apps/ios/ADEWidgets/ADEAgentActivityWidget.swift
📝 Walkthrough

Walkthrough

Changes

Session lifecycle and authorization

Layer / File(s) Summary
Settlement authorization and CLI removal
apps/ade-cli/..., apps/desktop/src/main/services/adeActions/..., apps/desktop/src/shared/...
Agent self-settlement commands and actions were removed; user or CTO-gated settlement remains supported.
Dynamic snoozing and stopped-run handling
apps/ade-cli/src/tuiClient/..., apps/ade-cli/src/services/push/..., apps/desktop/src/renderer/lib/sessionSnooze.ts
Snooze choices now resolve by time, and user-stopped CLI exits are excluded from completion and failure notifications.

Command palette threads

Layer / File(s) Summary
Thread indexing and palette integration
apps/desktop/src/renderer/components/app/...
Recent local and remote threads are indexed, ranked, rendered before other results, deduplicated, and routed through project bindings.

Desktop work surface

Layer / File(s) Summary
Canonical attention and lifecycle presentation
apps/desktop/src/renderer/components/attention/..., apps/desktop/src/renderer/components/chat/..., apps/desktop/src/renderer/lib/...
Desktop status presentation distinguishes done, blocked, stale, snoozed, settled, and needs-you states, with lifecycle banners in chat.
Shared lane menus and colors
apps/desktop/src/renderer/components/lanes/..., apps/desktop/src/renderer/components/terminals/LaneActionsSubmenu.tsx
Lane actions, submenus, color allocation, Primary-lane accents, and copy/navigation actions are centralized.
Session rows, menus, and shelves
apps/desktop/src/renderer/components/terminals/...
Session cards, hover cards, status slots, context menus, singleton lanes, quiet shelves, PR metadata, and cross-machine routing were expanded or redesigned.

iOS presentation

Layer / File(s) Summary
Unified status and snooze semantics
apps/ios/ADE/..., apps/ios/ADEWidgets/..., apps/ios/ADETests/...
iOS adopts Working, Done, Stale, and Blocked terminology, revised prominence and tint rules, and shared dynamic snooze options.

Estimated code review effort: 5 (Critical) | ~90+ minutes

Possibly related PRs

  • arul28/ADE#886: Introduced the agent self-settlement actions removed by this change.
  • arul28/ADE#909: Overlaps the session settlement authorization and settleSession/unsettleSession surfaces.
  • arul28/ADE#923: Overlaps session lifecycle UI, multi-machine routing, and terminal components.

Suggested labels: desktop, ios

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 39.74% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the pull request’s primary focus on refining Work session lifecycle behavior and the sidebar UI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/refine-ade-chat-sidebar

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 13

Caution

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

⚠️ Outside diff range comments (2)
apps/desktop/src/main/services/lanes/laneService.ts (1)

2258-2291: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Enforce the reserved primary color in updateAppearance.

This backfill/insert makes Primary purple, but updateAppearance can later set its color to any value. Reject or normalize primary-lane color updates so the stated cross-surface invariant persists.

Proposed fix
 const normalizedColor = color === undefined ? lane.color : color;
+if (
+  lane.lane_type === "primary"
+  && normalizedColor !== PRIMARY_LANE_COLOR
+) {
+  throw new Error("Primary lane color is fixed.");
+}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/main/services/lanes/laneService.ts` around lines 2258 -
2291, Update updateAppearance to enforce PRIMARY_LANE_COLOR whenever the target
lane is a primary lane: reject requested color changes or normalize them to the
reserved color before persisting. Preserve the existing appearance-update
behavior for non-primary lanes and ensure any primary update cannot store
another color.

Source: Coding guidelines

apps/ade-cli/src/cli.ts (1)

6959-7014: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

chat settle/chat unsettle fall through to a generic, unhelpful error instead of the documented guidance.

Unlike buildSessionPlan, which explicitly rejects removed subcommands with a clear CliUsageError (Line 6931: `Unknown session subcommand '${sub}'. Try: show, snooze, wake, clear-woke.`), buildChatPlan no longer has any case for "settle"/"unsettle". They fall through to the generic catch-all at Lines 7847-7851 and get dispatched as domain "chat", action "settle"/"unsettle" — actions that don't exist (settlement now lives only under the "session" domain). Users get an opaque "unknown action" failure instead of the help text you just wrote at Lines 1715-1717 ("'chat settle' / 'chat unsettle' were removed: ... report your outcome with 'chat note'").

🐛 Proposed fix: explicit rejection mirroring buildSessionPlan
+  if (sub === "settle" || sub === "unsettle") {
+    throw new CliUsageError(
+      "'chat settle' / 'chat unsettle' were removed: only the user (or a merged PR) settles a session — report your outcome with 'chat note'.",
+    );
+  }
   if (sub === "list" || sub === "ls") {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/cli.ts` around lines 6959 - 7014, Update buildChatPlan to
explicitly reject the removed "settle" and "unsettle" subcommands with a
CliUsageError containing the documented guidance to use "chat note". Place this
handling before the generic chat action fallback, while preserving existing
behavior for all supported subcommands.
🧹 Nitpick comments (10)
apps/desktop/src/shared/laneColorPalette.ts (1)

54-55: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Normalize both sides of the reserved-colour comparison.

The filter only excludes purple because PRIMARY_LANE_COLOR happens to be written lowercase; changing the constant's casing would silently return purple to the allocation pool and break the "purple always means Primary" invariant this module documents.

🛡️ Proposed hardening
-export const ALLOCATABLE_LANE_COLORS: readonly LaneColor[] = LANE_COLOR_PALETTE
-  .filter((entry) => entry.hex.toLowerCase() !== PRIMARY_LANE_COLOR);
+const PRIMARY_LANE_COLOR_KEY = PRIMARY_LANE_COLOR.toLowerCase();
+export const ALLOCATABLE_LANE_COLORS: readonly LaneColor[] = LANE_COLOR_PALETTE
+  .filter((entry) => entry.hex.toLowerCase() !== PRIMARY_LANE_COLOR_KEY);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/shared/laneColorPalette.ts` around lines 54 - 55, Update the
filter in ALLOCATABLE_LANE_COLORS to normalize PRIMARY_LANE_COLOR as well as
entry.hex before comparing them, preserving the exclusion of the reserved
primary color regardless of the constant’s casing.
apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx (1)

215-215: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Also release the module-level handoff entry on unmount.

Rows in this list unmount constantly (re-sort, filter, collapse). If a row unmounts while it owns activeHoverCard, the module keeps a closure over the dead hook plus a detached trigger node until the next hover.

♻️ Proposed cleanup
-  React.useEffect(() => clearTimers, [clearTimers]);
+  React.useEffect(() => () => {
+    clearTimers();
+    if (activeHoverCard?.rowId === rowId) activeHoverCard = null;
+  }, [clearTimers, rowId]);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx` at line
215, Update the cleanup effect in the hover-card hook to release the
module-level activeHoverCard handoff when its owning row unmounts, but only if
that entry belongs to the current hook/trigger. Preserve the existing
clearTimers cleanup and avoid clearing a newer row’s active handoff.
apps/desktop/src/renderer/components/terminals/SessionListPane.test.tsx (1)

25-47: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Recorder accumulates across tests and cardPropsFor returns the first, not the latest, props.

sessionCardPropsForTest is only truncated inside two describes, and .find contradicts the doc comment ("most recent render pass") — a re-render in the same test makes the assertion read the stale prop set. Clearing it in the shared afterEach and using findLast removes the trap without touching any current expectation.

♻️ Proposed tightening
 function cardPropsFor(sessionId: string): Record<string, unknown> | undefined {
-  return sessionCardPropsForTest.find(
+  return sessionCardPropsForTest.findLast(
     (props) => (props.session as TerminalSessionSummary | undefined)?.id === sessionId,
   );
 }

Plus sessionCardPropsForTest.length = 0; in each afterEach.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/terminals/SessionListPane.test.tsx`
around lines 25 - 47, Update the shared test cleanup for sessionCardPropsForTest
so it is cleared in the common afterEach rather than only within individual
describe blocks. Change cardPropsFor to return the last matching session props
from the most recent render, using findLast or equivalent, while preserving its
existing session-id filtering behavior.
apps/desktop/src/renderer/components/terminals/SessionListPane.tsx (2)

961-980: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Re-playing a synthetic keydown to open the palette is a renderer-only workaround.

This depends on AppShell's listener being on window, in the bubble phase, un-swallowed by anything upstream, and on its matcher accepting a synthesized event — none of which this file can guarantee. Exposing an openCommandPalette action (store or context) alongside AppShell's key handler removes the coupling and keeps the shortcut chip logic here purely cosmetic.

As per coding guidelines, "prefer fixing the underlying service or shared type rather than adding renderer-only workarounds".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/terminals/SessionListPane.tsx` around
lines 961 - 980, Replace the synthetic keydown workaround in openCommandPalette
with the shared command-palette open action exposed by AppShell’s existing
state, store, or context alongside its keyboard handler. Update the search
button to invoke that action directly, and keep commandPaletteBinding only for
displaying the shortcut chip rather than parsing or dispatching keyboard events.

Source: Coding guidelines


152-196: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse the keybinding combo parser for shortcut chips.

parsePrimaryCombo in SessionListPane.tsx re-implements the same Mod/platform resolution already in lib/keybindings, and it even still uses deprecated navigator.platform. Export a small combo resolver from lib/keybindings and use it here so chips and matching always come from one source of truth.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/terminals/SessionListPane.tsx` around
lines 152 - 196, Replace the local parsePrimaryCombo implementation in
SessionListPane with a small exported combo resolver from lib/keybindings that
performs the existing Mod/platform resolution without deprecated
navigator.platform usage. Import and reuse that resolver in shortcutChipLabel,
preserving the current chip formatting while ensuring display and matching share
one source of truth.
apps/desktop/src/renderer/components/lanes/laneContextMenuItems.tsx (1)

493-500: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Swatch buttons are non-menuitem children of a role="menu" container.

LaneMenuGroups renders this custom node directly inside the menu (and inside the MenuSubmenu panel), so AT sees plain buttons as invalid menu children. Consider role="menuitemradio" with aria-checked for the swatches and role="menuitem" for the clear button.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/lanes/laneContextMenuItems.tsx` around
lines 493 - 500, Update the swatch buttons rendered by LaneMenuGroups to use
role="menuitemradio" with aria-checked reflecting isSelected, and update the
clear button to use role="menuitem", ensuring all direct children of the
role="menu" and MenuSubmenu panel have valid menu-item semantics.
apps/desktop/src/renderer/components/lanes/LaneContextMenu.tsx (1)

89-120: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Extract the duplicated entry renderer.

The submenu and inline branches map entries with byte-identical logic; one helper keeps them from drifting.

♻️ Proposed refactor
+function renderEntry(entry: LaneMenuGroup["entries"][number]) {
+  if (entry.kind === "custom") {
+    return <React.Fragment key={entry.key}>{entry.node}</React.Fragment>;
+  }
+  return (
+    <HoverButton
+      key={entry.key}
+      style={menuItemStyle}
+      dataTour={entry.dataTour}
+      onClick={entry.onSelect}
+    >
+      {entry.label}
+    </HoverButton>
+  );
+}

Then use {group.entries.map(renderEntry)} in both branches.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/lanes/LaneContextMenu.tsx` around lines
89 - 120, Extract the duplicated entry-mapping JSX into a shared renderEntry
helper near the LaneContextMenu component, preserving the existing custom
Fragment and HoverButton behavior, keys, props, and handlers. Replace both
group.entries.map callbacks in the submenu and inline branches with
group.entries.map(renderEntry).
apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx (1)

233-237: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Panel declares role="menu" but its children are plain <button>s.

ARIA requires a menu to contain menuitem/menuitemcheckbox/menuitemradio children; the session menu passes bare buttons (only LaneActionsSubmenu sets role="menuitem"). Screen readers then report a menu with zero items, and the arrow-key model implemented in moveFocus has no ARIA counterpart. Either apply the role in the panel (wrap children or document the requirement) or drop role="menu" and expose the panel as a plain group.

Also, focusableItems only matches button:not([disabled]), so any anchor or input a consumer places in a panel is skipped by arrow navigation.

Also applies to: 271-274

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx` around lines 233 -
237, Update MenuSubmenu’s panel semantics and focus management: either ensure
every supported child receives an appropriate menuitem role while preserving the
existing menu keyboard model, or remove role="menu" and expose the panel as a
plain group. Expand focusableItems beyond enabled buttons so anchors and other
supported interactive descendants are included in moveFocus, while still
excluding disabled elements.
apps/desktop/src/renderer/components/terminals/TerminalsPage.test.tsx (1)

665-702: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Store vs. hook lane/focus mocks are the same function, so these two assertions can't tell the paths apart.

baseWork spreads ...fns, so workMocks.currentWork.selectLane === workMocks.fns.selectLane (same for focusSession). Lines 699-700 therefore pass whether the handler used selectLaneInStore/focusSessionInStore or work.selectLane/work.focusSession — which is exactly the distinction this test exists to pin down. Give the store selectors their own vi.fn()s.

♻️ Sketch
   const fns = {
-    selectLane: vi.fn(),
-    focusSession: vi.fn(),
+    selectLane: vi.fn(),        // hook (work.*)
+    focusSession: vi.fn(),
+    storeSelectLane: vi.fn(),   // app store
+    storeFocusSession: vi.fn(),

…and wire selectLane: workMocks.fns.storeSelectLane / focusSession: workMocks.fns.storeFocusSession into the useAppStore selector object, asserting on those in this test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/renderer/components/terminals/TerminalsPage.test.tsx` around
lines 665 - 702, Update the TerminalsPage test mocks so store selectors use
distinct vi.fn() instances from the hook functions: add dedicated
storeSelectLane and storeFocusSession mocks, wire them into the useAppStore
selector object, and assert the foreign-session handler calls those store mocks
while preserving the existing hook-call assertions.
apps/ade-cli/src/tuiClient/sessionLifecycle.ts (1)

2-2: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Remove the direct desktop renderer import for snooze presets.

resolveSnoozePresets is imported from ../../desktop/src/renderer/lib/sessionSnooze, and this already mixes renderer-only code into a CLI target. If the CLI needs these utils, move/reexport them from a shared package or keep an own copy instead of importing through apps/desktop/src/renderer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/ade-cli/src/tuiClient/sessionLifecycle.ts` at line 2, Remove the direct
renderer import of resolveSnoozePresets from the session lifecycle module.
Provide the CLI with this utility through a shared package or a local CLI-safe
implementation, ensuring no dependency on apps/desktop/src/renderer remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/ade-cli/src/adeRpcServer.test.ts`:
- Around line 1584-1591: Extend the denial matrix loop containing settleAttempt
cases to include the CTO-only bulk writer action unsettleSessions, using the
appropriate sessionIds argument for chat-1. Preserve the existing assertions and
coverage for the other settlement actions.

In `@apps/desktop/resources/ade-cli-help.txt`:
- Around line 51-53: Replace “File a session's lifecycle” with “Manage a
session's lifecycle” in all five generated command index entries:
apps/desktop/resources/ade-cli-help.txt lines 51-53, 188-190, 747-749, 947-949,
and 1362-1364.

In `@apps/desktop/src/renderer/components/app/commandPaletteThreads.tsx`:
- Around line 444-460: Remove the aria-hidden attribute from the
ThreadOverflowNote list item so assistive technologies can announce the “Showing
shown of total threads” status. Keep the existing non-focusable li structure,
styling, and conditional rendering unchanged.
- Around line 342-349: Update the contextParts construction near the
secondary-line logic to use the entry’s routing-bound project displayName for
foreign rows instead of the current tab’s projectName. Preserve the existing
project/branch/lane ordering and fallback behavior, while ensuring cross-machine
threads are labeled with their own project identity.

In `@apps/desktop/src/renderer/components/chat/AgentChatPane.tsx`:
- Around line 11786-11791: Update the lifecycleBanner conditional and
ChatLifecycleBanner sessionId prop to use the resolved composerSessionId instead
of selectedSessionId, matching the existing composer control targeting behavior
during chat switches.

In `@apps/desktop/src/renderer/components/chat/ChatSurfaceShell.tsx`:
- Around line 10-11: Move the h-8 height utility out of CHAT_SHELL_HEADER_CLASS
so the shell wrapper retains only horizontal padding and the existing spacing
behavior. Apply h-8 directly to the WorkSurfaceHeader element, while preserving
the wrapper’s space-y-1 (or equivalent) gap when the session tabs row is
rendered.

In `@apps/desktop/src/renderer/components/terminals/LaneActionsSubmenu.tsx`:
- Around line 69-77: Add role="menuitem" to the LaneActionsSubmenu MenuSubmenu
trigger, matching the role passed by LaneContextMenu and preserving the existing
fallback child behavior.
- Around line 53-66: Update useLaneMenuActions and the LaneMenuActions type to
expose an onAppearanceChanged refresh callback, include it in the hook’s
memoization dependencies, and pass it through LaneActionsSubmenu into
buildLaneMenuGroups so the color swatch receives the callback and refreshes
after selection.

In `@apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx`:
- Around line 204-213: Track the delayed-open state with a pending-open state
value: set it when the open timer is scheduled, and clear it in clearTimers and
open. Update the scroll/resize effect guard to depend on this state so listeners
are armed during the delay, while preserving cancellation for already-open
cards.
- Around line 318-344: Make SessionHoverCard actions keyboard reachable by
adding an assistive-technology-discoverable keyboard path from the session row,
rather than relying only on the hover-triggered tooltip. Update the relevant
session-row keyboard handler to invoke the same action used by row.onActivate,
and ensure the activated control is discoverable without relying on the inner
tabIndex={-1} button or pointer hover.

In `@apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx`:
- Around line 195-221: Update closeNow to restore focus to the submenu trigger
whenever the closing panel contains document.activeElement, including
pointer-timeout closures after keyboard opening. Preserve existing close
behavior and avoid moving focus when the panel does not currently own focus; use
the trigger reference already associated with the submenu.

In `@apps/ios/ADE/Views/AttentionDrawer/AttentionDrawerModel.swift`:
- Around line 636-644: Update the WorkspaceSnapshot fallback classification near
the local snapshot handling to map phase == "blocked" to .blocked instead of
.running, while preserving .stale for disconnected hosts and existing
classifications for other phases. Add a regression test covering a local
WorkspaceSnapshot with a blocked phase and verify it produces the neutral
blocked presentation.

In `@apps/ios/ADEWidgets/ADEAgentActivityWidget.swift`:
- Around line 288-304: Update the headline logic near activeCount and the
primary-agent selection so completed runs are not counted as active work. Derive
the count from genuinely in-flight phases such as starting or running, or
preserve the host-reported active count separately, then ensure the zero-active
path at the headline generation logic produces the completed/result wording
instead of “1 agent working.”

---

Outside diff comments:
In `@apps/ade-cli/src/cli.ts`:
- Around line 6959-7014: Update buildChatPlan to explicitly reject the removed
"settle" and "unsettle" subcommands with a CliUsageError containing the
documented guidance to use "chat note". Place this handling before the generic
chat action fallback, while preserving existing behavior for all supported
subcommands.

In `@apps/desktop/src/main/services/lanes/laneService.ts`:
- Around line 2258-2291: Update updateAppearance to enforce PRIMARY_LANE_COLOR
whenever the target lane is a primary lane: reject requested color changes or
normalize them to the reserved color before persisting. Preserve the existing
appearance-update behavior for non-primary lanes and ensure any primary update
cannot store another color.

---

Nitpick comments:
In `@apps/ade-cli/src/tuiClient/sessionLifecycle.ts`:
- Line 2: Remove the direct renderer import of resolveSnoozePresets from the
session lifecycle module. Provide the CLI with this utility through a shared
package or a local CLI-safe implementation, ensuring no dependency on
apps/desktop/src/renderer remains.

In `@apps/desktop/src/renderer/components/lanes/LaneContextMenu.tsx`:
- Around line 89-120: Extract the duplicated entry-mapping JSX into a shared
renderEntry helper near the LaneContextMenu component, preserving the existing
custom Fragment and HoverButton behavior, keys, props, and handlers. Replace
both group.entries.map callbacks in the submenu and inline branches with
group.entries.map(renderEntry).

In `@apps/desktop/src/renderer/components/lanes/laneContextMenuItems.tsx`:
- Around line 493-500: Update the swatch buttons rendered by LaneMenuGroups to
use role="menuitemradio" with aria-checked reflecting isSelected, and update the
clear button to use role="menuitem", ensuring all direct children of the
role="menu" and MenuSubmenu panel have valid menu-item semantics.

In `@apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx`:
- Line 215: Update the cleanup effect in the hover-card hook to release the
module-level activeHoverCard handoff when its owning row unmounts, but only if
that entry belongs to the current hook/trigger. Preserve the existing
clearTimers cleanup and avoid clearing a newer row’s active handoff.

In `@apps/desktop/src/renderer/components/terminals/SessionListPane.test.tsx`:
- Around line 25-47: Update the shared test cleanup for sessionCardPropsForTest
so it is cleared in the common afterEach rather than only within individual
describe blocks. Change cardPropsFor to return the last matching session props
from the most recent render, using findLast or equivalent, while preserving its
existing session-id filtering behavior.

In `@apps/desktop/src/renderer/components/terminals/SessionListPane.tsx`:
- Around line 961-980: Replace the synthetic keydown workaround in
openCommandPalette with the shared command-palette open action exposed by
AppShell’s existing state, store, or context alongside its keyboard handler.
Update the search button to invoke that action directly, and keep
commandPaletteBinding only for displaying the shortcut chip rather than parsing
or dispatching keyboard events.
- Around line 152-196: Replace the local parsePrimaryCombo implementation in
SessionListPane with a small exported combo resolver from lib/keybindings that
performs the existing Mod/platform resolution without deprecated
navigator.platform usage. Import and reuse that resolver in shortcutChipLabel,
preserving the current chip formatting while ensuring display and matching share
one source of truth.

In `@apps/desktop/src/renderer/components/terminals/TerminalsPage.test.tsx`:
- Around line 665-702: Update the TerminalsPage test mocks so store selectors
use distinct vi.fn() instances from the hook functions: add dedicated
storeSelectLane and storeFocusSession mocks, wire them into the useAppStore
selector object, and assert the foreign-session handler calls those store mocks
while preserving the existing hook-call assertions.

In `@apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx`:
- Around line 233-237: Update MenuSubmenu’s panel semantics and focus
management: either ensure every supported child receives an appropriate menuitem
role while preserving the existing menu keyboard model, or remove role="menu"
and expose the panel as a plain group. Expand focusableItems beyond enabled
buttons so anchors and other supported interactive descendants are included in
moveFocus, while still excluding disabled elements.

In `@apps/desktop/src/shared/laneColorPalette.ts`:
- Around line 54-55: Update the filter in ALLOCATABLE_LANE_COLORS to normalize
PRIMARY_LANE_COLOR as well as entry.hex before comparing them, preserving the
exclusion of the reserved primary color regardless of the constant’s casing.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e10003a4-06d0-4b2b-927c-ea9eca0c64e7

📥 Commits

Reviewing files that changed from the base of the PR and between 1b087ef and 1e57088.

⛔ Files ignored due to path filters (9)
  • docs/ARCHITECTURE.md is excluded by !docs/**
  • docs/features/ade-code/README.md is excluded by !docs/**
  • docs/features/agents/README.md is excluded by !docs/**
  • docs/features/cto/README.md is excluded by !docs/**
  • docs/features/lanes/README.md is excluded by !docs/**
  • docs/features/sync-and-multi-device/ios-companion.md is excluded by !docs/**
  • docs/features/terminals-and-sessions/README.md is excluded by !docs/**
  • docs/features/terminals-and-sessions/ui-surfaces.md is excluded by !docs/**
  • docs/features/web-client/README.md is excluded by !docs/**
📒 Files selected for processing (91)
  • apps/ade-cli/README.md
  • apps/ade-cli/src/adeRpcServer.test.ts
  • apps/ade-cli/src/adeRpcServer.ts
  • apps/ade-cli/src/cli.test.ts
  • apps/ade-cli/src/cli.ts
  • apps/ade-cli/src/services/push/pushPublisherService.test.ts
  • apps/ade-cli/src/services/push/pushPublisherService.ts
  • apps/ade-cli/src/tuiClient/__tests__/adeApi.test.ts
  • apps/ade-cli/src/tuiClient/__tests__/sessionLifecycle.test.tsx
  • apps/ade-cli/src/tuiClient/adeApi.ts
  • apps/ade-cli/src/tuiClient/app.tsx
  • apps/ade-cli/src/tuiClient/commands.ts
  • apps/ade-cli/src/tuiClient/sessionLifecycle.ts
  • apps/desktop/resources/ade-cli-help.txt
  • apps/desktop/resources/agent-skills/ade-cli-control-plane/SKILL.md
  • apps/desktop/src/main/services/adeActions/registry.test.ts
  • apps/desktop/src/main/services/adeActions/registry.ts
  • apps/desktop/src/main/services/ai/tools/ctoOperatorTools.ts
  • apps/desktop/src/main/services/ai/tools/systemPrompt.test.ts
  • apps/desktop/src/main/services/chat/cursorSdkSystemPrompt.test.ts
  • apps/desktop/src/main/services/lanes/laneService.ts
  • apps/desktop/src/main/services/sessions/sessionService.ts
  • apps/desktop/src/main/services/usage/usageStatsStore.ts
  • apps/desktop/src/main/services/usage/usageTrackingService.test.ts
  • apps/desktop/src/preload/preload.test.ts
  • apps/desktop/src/preload/preload.ts
  • apps/desktop/src/renderer/components/app/CommandPalette.test.tsx
  • apps/desktop/src/renderer/components/app/CommandPalette.tsx
  • apps/desktop/src/renderer/components/app/commandPaletteSearch.tsx
  • apps/desktop/src/renderer/components/app/commandPaletteThreads.tsx
  • apps/desktop/src/renderer/components/attention/AttentionCenter.css
  • apps/desktop/src/renderer/components/attention/AttentionCenter.tsx
  • apps/desktop/src/renderer/components/attention/HeaderAttentionControl.css
  • apps/desktop/src/renderer/components/attention/HeaderAttentionControl.test.tsx
  • apps/desktop/src/renderer/components/attention/attentionHeaderSummary.ts
  • apps/desktop/src/renderer/components/attention/attentionPresentation.test.ts
  • apps/desktop/src/renderer/components/attention/attentionPresentation.ts
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/chat/ChatLifecycleBanner.test.tsx
  • apps/desktop/src/renderer/components/chat/ChatLifecycleBanner.tsx
  • apps/desktop/src/renderer/components/chat/ChatSurfaceShell.tsx
  • apps/desktop/src/renderer/components/lanes/LaneContextMenu.test.tsx
  • apps/desktop/src/renderer/components/lanes/LaneContextMenu.tsx
  • apps/desktop/src/renderer/components/lanes/laneColorPalette.ts
  • apps/desktop/src/renderer/components/lanes/laneContextMenuItems.tsx
  • apps/desktop/src/renderer/components/lanes/laneDesignTokens.ts
  • apps/desktop/src/renderer/components/lanes/laneUtils.test.ts
  • apps/desktop/src/renderer/components/terminals/LaneActionsSubmenu.tsx
  • apps/desktop/src/renderer/components/terminals/LanePrBadge.tsx
  • apps/desktop/src/renderer/components/terminals/SessionCard.test.tsx
  • apps/desktop/src/renderer/components/terminals/SessionCard.tsx
  • apps/desktop/src/renderer/components/terminals/SessionContextMenu.test.tsx
  • apps/desktop/src/renderer/components/terminals/SessionContextMenu.tsx
  • apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx
  • apps/desktop/src/renderer/components/terminals/SessionInfoPopover.tsx
  • apps/desktop/src/renderer/components/terminals/SessionListPane.test.tsx
  • apps/desktop/src/renderer/components/terminals/SessionListPane.tsx
  • apps/desktop/src/renderer/components/terminals/SessionSnoozeControl.tsx
  • apps/desktop/src/renderer/components/terminals/SessionStatusSlot.tsx
  • apps/desktop/src/renderer/components/terminals/TerminalsPage.test.tsx
  • apps/desktop/src/renderer/components/terminals/TerminalsPage.tsx
  • apps/desktop/src/renderer/components/terminals/sessionLifecycleActions.ts
  • apps/desktop/src/renderer/components/terminals/useWorkLaneContextMenu.tsx
  • apps/desktop/src/renderer/components/terminals/useWorkSessions.ts
  • apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx
  • apps/desktop/src/renderer/components/work/WorkSurfaceHeader.test.tsx
  • apps/desktop/src/renderer/components/work/WorkSurfaceHeader.tsx
  • apps/desktop/src/renderer/index.css
  • apps/desktop/src/renderer/lib/sessionSnooze.test.ts
  • apps/desktop/src/renderer/lib/sessionSnooze.ts
  • apps/desktop/src/renderer/lib/terminalAttention.test.ts
  • apps/desktop/src/renderer/lib/terminalAttention.ts
  • apps/desktop/src/renderer/webclient/shell/sessionLifecycleChrome.ts
  • apps/desktop/src/shared/adeCliGuidance.test.ts
  • apps/desktop/src/shared/adeCliGuidance.ts
  • apps/desktop/src/shared/laneColorPalette.ts
  • apps/desktop/src/shared/sessionCanonicalState.ts
  • apps/desktop/src/shared/sessionStatusPresentation.ts
  • apps/ios/ADE/Shared/ADEAgentActivityAttributes.swift
  • apps/ios/ADE/Shared/ADESharedModels.swift
  • apps/ios/ADE/Shared/ADESharedTheme.swift
  • apps/ios/ADE/Views/AttentionDrawer/AttentionDrawerModel.swift
  • apps/ios/ADE/Views/AttentionDrawer/AttentionDrawerSheet.swift
  • apps/ios/ADE/Views/Work/WorkRootComponents.swift
  • apps/ios/ADE/Views/Work/WorkSessionCanonicalState.swift
  • apps/ios/ADE/Views/Work/WorkSessionGrouping.swift
  • apps/ios/ADETests/ADETests.swift
  • apps/ios/ADETests/AttentionDrawerModelTests.swift
  • apps/ios/ADETests/WorkSessionCanonicalStateTests.swift
  • apps/ios/ADEWidgets/ADEAgentActivityWidget.swift
  • apps/ios/ADEWidgets/ADELockScreenWidget.swift
💤 Files with no reviewable changes (1)
  • apps/ade-cli/README.md

Comment thread apps/ade-cli/src/adeRpcServer.test.ts
Comment thread apps/desktop/resources/ade-cli-help.txt Outdated
Comment thread apps/desktop/src/renderer/components/app/commandPaletteThreads.tsx Outdated
Comment thread apps/desktop/src/renderer/components/app/commandPaletteThreads.tsx
Comment thread apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
Comment thread apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx Outdated
Comment thread apps/desktop/src/renderer/components/terminals/SessionHoverCard.tsx
Comment thread apps/desktop/src/renderer/components/ui/MenuSubmenu.tsx
Comment thread apps/ios/ADE/Views/AttentionDrawer/AttentionDrawerModel.swift
Comment thread apps/ios/ADEWidgets/ADEAgentActivityWidget.swift
@arul28

arul28 commented Jul 31, 2026

Copy link
Copy Markdown
Owner Author

@codex review

@arul28
arul28 merged commit d96563c into main Jul 31, 2026
33 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd3266484e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +808 to +811
// The inline input is gone (search now opens the command palette), but the
// query itself still drives every filter in this file and the setter stays in
// the contract so the parent can keep restoring/clearing it.
setQ: _setQ,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Clear the retired sidebar query before hiding its setter

When an upgrading user has a nonempty persisted WorkProjectViewState.search, useWorkSessions still applies that value to local sessions and this component also applies q to foreign rows, but the removed input was the only UI that called setQ. Opening the command palette does not change this separate persisted query, so matching sessions remain silently hidden—potentially behind a misleading “No sessions” state—with no way to clear the filter in Work. Clear/migrate the old value or retain an active-filter indicator and reset action.

Useful? React with 👍 / 👎.

Comment on lines +181 to +182
let hiddenActiveCount = max(0, safeState.activeCount - safeState.runs.count)
let activeCount = hiddenActiveCount + visibleInFlightCount

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve omitted working runs in the widget count

When the publisher has more than three runs and a recent completed/failed/waiting row occupies one of the capped runs slots, subtracting the entire visible roster from activeCount loses omitted working runs. For example, four working runs plus one newly completed run produce activeCount == 4 and a three-row roster containing the completion and two working runs; this computes only three working runs. The payload needs a working-count field or the hidden remainder must be derived from visible entries that actually contribute to the producer's count, rather than from runs.count.

Useful? React with 👍 / 👎.

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