Repository navigation
Graduate Agents activity view with filtering, persistence, and performance improvements - #18222
Conversation
- Emphasize task title and last activity in row layout over metadata - Add child agent toggle; hide orchestration workers by default - Support collapsible groups and ungrouped view mode - Improve orchestration worker message handling to surface replies - Add sidebar search and filter controls for agent activity
- Add "Clear completed" action for activity threads with undo window; clears completed and interrupted rows from view, persists across restart - Virtualize activity thread list to render only viewport-bounded rows - Cache activity thread search text to prevent recomputation on every keystroke - Cache dashboard bucket counts per-worktree for selective invalidation on unrelated changes - Use useDeferredValue for activity search filtering to keep input responsive - Make compact mode the default display for activity threads - Add activity-cleared-at persisted state tracking (per-pane cutoff timestamps)
Agents scope filters are deliberately separate from workspace-nav filters so a monitoring surface never inherits workspace context silently. Filters survive restarts and always display an active-filter chips row with hidden count, making filtering visible and reversible.
- Agents Dashboard moves from experimental to standard feature with showAgentsSidebar setting controlling visibility - Add identity-checked cache eviction (dropPersisted IPC) to prevent newer runs from being evicted when UI clears older status, fixing clear-completed safety - Extract ActivityThreadHoverCardSummary and ActivityThreadListToolbar components for better organization and reusability - Implement mark-thread-read as separate action from select with clickable bell icon - Add hasActivityThreadWorkspace helper for checking workspace availability across hosts (SSH/runtime targets) - Preserve scope filter array identity during hydration for memo optimization - Track manually-unread turns in auto-ack to prevent re-acknowledgement - Clean up activity cleared-at cutoffs on pane retirement - Remove activity-thread-hover-card max-lines lint override (code refactored below threshold)
- Simplify AgentStatusCacheIdentity: keep only paneKey, receivedAt, stateStartedAt - This fixes silent no-ops where renderer-enriched fields diverged from main's cache - Add worktree-jump-navigation for navigating activity to workspaces - Add manual mark-unread protection separate from auto-ack - Optimize activity owner resolution with per-build memoization - Optimize detected worktree lookup with indexed search
Replace the floating sticky header overlay with scroll position memory via a ref. This preserves the user's scroll location when switching between threads or remounting the agents list, improving UX without requiring React state.
Keep group headers visible at the top while scrolling when threads are grouped. Headers stick to the viewport while their section is in view, then unstick as the next header approaches.
…ed UI slice. - Removed dead sidebar search/menu props and the unused search ref. - Removed the unnecessary sidebar visibility bitmask. - Replaced hardcoded sidebar toggle colors with design-system tokens. - Removed duplicate “mark all read / clear completed” controls in the sidebar. - Preserved manual-unread state correctly across pane retire, transfer, and drop. - Made clear-completed cutoffs monotonic so clock skew cannot resurrect old activity. - Fixed blank workspace names in hover cards with the existing fallback helper. - Added missing localization entries and stabilized hydrated filter array identity. - Updated misleading Agents setting copy to describe both sidebar surfaces.
Agent view filters and presentation settings now sync across paired clients. Preserves per-pane activity clearance cutoffs in persistent state. Improves activity thread row accessibility with proper ARIA roles, and preserves terminal host ownership after pane teardown via retained terminal handle.
- Migrate `showAgentsSidebar` setting from legacy experimental flags; default new profiles to the agents sidebar - Replace scoped-thread filtering with visible-thread filtering so bulk actions (mark all read, clear completed) only affect rendered rows - Rewrite child agent classification as a set of visible pane keys to fix orphan promotion and parent-cycle handling - Improve activity cleared-at cutoff lifecycle: preserve on row dismissal (pane may still be live) but clear on pane removal - Add pagehide flush for pending clear-completed evictions so quit/reload cannot replay cleared activity - Polish agents sidebar: unread count badge, expand button, onboarding intro for migrated/new users - Extract shared time-ago formatting to a library module - Fix scroll restoration to defer until content can contain the saved offset - Improve stable message hold for compact agent rows using state instead of refs - Add worktree filter-visibility check to distinguish collapsed-but-unfiltered from filtered-hidden
- Remove the deprecated full-page Agents view; fix settings navigation fallback - Refactor bulk action bindings and separate mark-all-read from visible threads - Preserve sidebar collapse state across remounts; fix child-agent badge filtering - Add safety window for scroll-restore and improve worktree host-qualified filtering
- Move Agents sidebar from experimental settings to standard feature with intro flow - Add persistent manual unread turn tracking for activity feed - Consolidate workspace activation through activateAndRevealWorkspace dispatcher - Improve sidebar view toggle with radio semantics and arrow-key navigation
The Agents tab now has its own `showAgentsSidebar` setting (defaults on) independent from the dashboard popout experiment. Activity unread counting is simplified to count all events uniformly without mode-specific filtering. Dashboard visibility is now controlled solely by `experimentalAgentDashboardPopout`, with its own UI in the Experimental settings pane. Migration path updated: only `experimentalActivity=true` graduates to the sidebar; the dashboard experiment remains separate.
Build activity event contexts from structured agent-session tabs and worktree-attributed status entries. When activating a thread, try agent-session tab activation before falling back to terminal pane.
label—no grouping-based “Projects” label or hidden width-reservation span.
Activity group order now surfaces threads needing attention (blocked,
waiting, interrupted) before working/done so they're never buried. The
Agents tab shows an unread count badge while viewing Spaces, since the
open Agents list already highlights unread rows.
Also improves UX text ("Hide Agents" vs "Maybe later"), accessibility
with proper ARIA labels, and handles edge cases: preserves read state
for retained panes on SSH reconnect and handles deleted worktrees
gracefully in navigation.
- Add dropPersistedStatusEntries batch API; consolidate evictions into one persist - Implement fallback timeout in clear-completed for unseen toast callbacks - Project only activity-relevant tabs; memoize terminal tab derivations - Stabilize activity virtualizer key to prevent unnecessary item measurements
Simplify useActivityUnreadCount by removing the enabled parameter and conditional logic, as the badge is no longer displayed in the UI.
Live pane status is the primary source; retained and migration entries serve as fallback caches that may briefly overlap it during lifecycle transitions. Count each pane only once by tracking seen keys, prioritizing the live status as the canonical source. Also fix monitoring state display: it's a distinct agent state, not a tool-running row state, so exclude it from tool preview checks.
|
Too many files changed for review (184 files, 100 file limit). Bypass the limit by tagging |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
Reviewed the full base→head diff (183 files, 28 commits) for the Agents graduation and the reworked activity surface.
- Agents view graduated to a default-on sidebar tab —
experimentalActivityreplaced byshowAgentsSidebar(shared/agents-sidebar-visibility.ts), with a migration + first-run intro popover inSidebarHeader.tsx. - "Clear completed" with undo — persisted per-pane
activityClearedAtByPaneKeycutoffs plus a deferred, identity-checked main-process eviction (dropPersistedStatusEntriesinmain/agent-hooks/server/server-cleanup.ts). - Manual mark-unread — persisted
manuallyUnreadTurnsByPaneKeywith protection that lapses on pane switch or a new turn. - Unread-count rework —
countActivityUnreadcollapsed to a single mode with source-overlap dedup and cutoff awareness. - Agents scope filters — persisted
agentsVisibleHostIds/agentsFilterRepoIds, deliberately separate from workspace-nav filters. - Child-agent filtering via the shared lineage model.
- Performance work — identity-reuse caches for the activity/thread pipeline, a per-worktree dashboard row cache, and a tab projection that survives focus rewrites.
- Remapping/teardown coverage — the two new pane-keyed records are swept consistently across restore, drop, purge, and mirrored-tab retraction paths.
ℹ️ PR template left empty
The body is just the LoC table: ELI5, What Changed, Why, Testing, and Linked Issue are all blank, and the Visual Proof section (marked REQUIRED for UI changes) is empty. For a 12k-line change that graduates the Agents experience to on-by-default for every user, a filled-in description and before/after visuals would make this materially easier to review and land. Nothing blocking — the code itself reads clean.
DeepSeek Pro (free via Pullfrog for OSS) | 𝕏
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (20)
📝 WalkthroughWalkthroughThe change adds an Agents sidebar with Spaces and Agents views, onboarding, filters, grouping, virtualization, hover cards, and activity actions. Activity state now persists across sessions and remaps across restored pane keys. Completed activity supports deferred status-cache eviction with undo. Activity and dashboard pipelines add identity-aware caching, host ownership resolution, bounded history, child-agent classification, unread handling, and workspace navigation. IPC contracts, localization, web bridges, and tests are updated. Merge Risk: 🟡 Moderate · up to The dashboard introduces new activity clearing, navigation, localization, and settings persistence behavior. Current code can erase cleared or unread state during same-pane heartbeats, break keyboard navigation, and allow an unscoped renderer request to remove matching persisted status rows; failed cleanup can also leave local and persisted state out of sync. These are concrete current-head correctness, security, and reliability issues, so merge should wait for fixes or explicit acceptance. 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
Full details: Description checkExplanation The description includes the required headings but leaves the ELI5, What Changed, Why, Linked Issue, Visual Proof, Testing, AI Disclosure, Review, Agent skill upstream boundary, Notes, and Checklist sections incomplete. The linked issue is also only an empty Resolution Complete the required sections with a high-level explanation, scope, rationale, linked issue, UI screenshots or Full details: Docstring CoverageExplanation Docstring coverage is 17.71% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 96 functions across 50 files. (132 skipped: 6 unsupported, 126 over the file limit.)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (2)
src/renderer/src/components/activity/activity-clear-completed.ts (1)
150-150: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse a semantic interpolation placeholder.
Replace
{{value0}}with{{count}}. Pass{ count: plan.clearedThreadCount }. Update the matching locale entries.Proposed change
- 'Cleared {{value0}} completed agents', - { value0: plan.clearedThreadCount } + 'Cleared {{count}} completed agents', + { count: plan.clearedThreadCount }Based on learnings: newly added user-facing strings must use intent-named localization IDs with named interpolation placeholders.
Source: Learnings
src/renderer/src/components/settings/ExperimentalPane.tsx (1)
70-70: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse one localized description for the setting.
SearchableSetting.descriptionuses the catalog description, but the visible paragraph uses different text. Settings search can therefore show text that differs from the setting page. Reuse the same localized value for both locations.Based on learnings: pass the same localized explanatory text through
descriptionand the visible child.Also applies to: 79-82
Source: Learnings
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Team
Run ID: 7646a91d-681c-4bd2-a37c-cc9b6e643dbe
📒 Files selected for processing (183)
docs/reference/wsl-probe-failure-semantics.mdsrc/main/agent-hooks/server-status-listener-fanout.test.tssrc/main/agent-hooks/server/server-cleanup.tssrc/main/ipc/agent-hooks.test.tssrc/main/ipc/agent-status-row-teardown-ipc.tssrc/main/persistence/applying-settings/ui-state-read.tssrc/main/persistence/applying-settings/ui-state-update.tssrc/main/persistence/loading-store/normalize-loaded-global-settings.test.tssrc/main/persistence/loading-store/normalize-loaded-global-settings.tssrc/main/persistence/loading-store/workspace-session-snapshot-publication.tssrc/main/persistence/restoring-sessions/pane-key-remapping.test.tssrc/main/persistence/restoring-sessions/pane-key-remapping.tssrc/main/persistence/restoring-sessions/workspace-pane-normalization.tssrc/main/runtime/rpc/methods/client-ui-pairing-local-fields.test.tssrc/main/runtime/rpc/methods/client-ui-schemas.tssrc/preload/api/agent-status-api.tssrc/preload/api/agent-status-bridge.tssrc/renderer/src/app-shell/use-app-startup-hydration.tssrc/renderer/src/app-shell/use-persisted-ui-writer.tssrc/renderer/src/components/activity/ActivityPrototypePage.test.tssrc/renderer/src/components/activity/ActivityPrototypePage.thread-grouping.test.tssrc/renderer/src/components/activity/ActivityPrototypePage.tsxsrc/renderer/src/components/activity/ActivityThreadOptionsMenu.test.tsxsrc/renderer/src/components/activity/ActivityTitlebarControls.tsxsrc/renderer/src/components/activity/activity-auto-mark-read-loop.react185.test.tsxsrc/renderer/src/components/activity/activity-clear-completed.test.tssrc/renderer/src/components/activity/activity-clear-completed.tssrc/renderer/src/components/activity/activity-event-build-cache.tssrc/renderer/src/components/activity/activity-event-builder-agent-context.test.tssrc/renderer/src/components/activity/activity-event-builder-context.tssrc/renderer/src/components/activity/activity-event-builder-sources.tssrc/renderer/src/components/activity/activity-event-builder.bounded-history.test.tssrc/renderer/src/components/activity/activity-event-builder.host-ownership.test.tssrc/renderer/src/components/activity/activity-event-builder.identity-reuse.test.tssrc/renderer/src/components/activity/activity-event-builder.tssrc/renderer/src/components/activity/activity-event-cap.tssrc/renderer/src/components/activity/activity-pane-events.tssrc/renderer/src/components/activity/activity-scope-filter-controls.tsxsrc/renderer/src/components/activity/activity-scope-filter.test.tssrc/renderer/src/components/activity/activity-scope-filter.tssrc/renderer/src/components/activity/activity-standalone-worktree.tssrc/renderer/src/components/activity/activity-tab-projection.tssrc/renderer/src/components/activity/activity-thread-actions.test.tssrc/renderer/src/components/activity/activity-thread-actions.tssrc/renderer/src/components/activity/activity-thread-builder.tssrc/renderer/src/components/activity/activity-thread-child-agent.test.tssrc/renderer/src/components/activity/activity-thread-child-agent.tssrc/renderer/src/components/activity/activity-thread-collapse-context.tssrc/renderer/src/components/activity/activity-thread-controls.tsxsrc/renderer/src/components/activity/activity-thread-grouping.search-cache.test.tssrc/renderer/src/components/activity/activity-thread-grouping.tssrc/renderer/src/components/activity/activity-thread-hover-card-summary.tsxsrc/renderer/src/components/activity/activity-thread-hover-card.test.tsxsrc/renderer/src/components/activity/activity-thread-hover-card.tsxsrc/renderer/src/components/activity/activity-thread-list-pane-collapsible.test.tsxsrc/renderer/src/components/activity/activity-thread-list-pane.tsxsrc/renderer/src/components/activity/activity-thread-list-pane.virtualization.test.tsxsrc/renderer/src/components/activity/activity-thread-list-resize-handle.tsxsrc/renderer/src/components/activity/activity-thread-list-toolbar.tsxsrc/renderer/src/components/activity/activity-thread-options-menu.tsxsrc/renderer/src/components/activity/activity-thread-presentation.test.tssrc/renderer/src/components/activity/activity-thread-presentation.tssrc/renderer/src/components/activity/activity-thread-row.tsxsrc/renderer/src/components/activity/activity-thread-types.tssrc/renderer/src/components/activity/activity-thread-virtual-items.test.tssrc/renderer/src/components/activity/activity-thread-virtual-items.tssrc/renderer/src/components/activity/activity-thread-virtual-row.tsxsrc/renderer/src/components/activity/dev-activity-fixture.test.tssrc/renderer/src/components/activity/dev-activity-fixture.tssrc/renderer/src/components/activity/event-time-clock-refresh.test.tsxsrc/renderer/src/components/activity/use-activity-thread-action-bindings.test.tsxsrc/renderer/src/components/activity/use-activity-thread-action-bindings.tssrc/renderer/src/components/activity/use-agent-pane-threads.tssrc/renderer/src/components/activity/useActivityUnreadCount.test.tssrc/renderer/src/components/activity/useActivityUnreadCount.tssrc/renderer/src/components/dashboard/agent-row-lineage-model.tssrc/renderer/src/components/dashboard/build-dashboard-bucket-counts.cache.test.tssrc/renderer/src/components/dashboard/build-dashboard-bucket-counts.tssrc/renderer/src/components/dashboard/build-dashboard-snapshot.rows-cache.test.tssrc/renderer/src/components/dashboard/build-dashboard-snapshot.tssrc/renderer/src/components/dashboard/useAgentBucketCounts.test.tsxsrc/renderer/src/components/dashboard/useAgentBucketCounts.tssrc/renderer/src/components/dashboard/useDashboardPopoutBridge.tssrc/renderer/src/components/dashboard/useLiveDashboardSnapshot.tssrc/renderer/src/components/dashboard/worktree-agent-rows-cache.tssrc/renderer/src/components/settings/AppearanceWindowSidebarSection.tsxsrc/renderer/src/components/settings/ExperimentalPane.test.tsxsrc/renderer/src/components/settings/ExperimentalPane.tsxsrc/renderer/src/components/settings/appearance-sidebar-search.tssrc/renderer/src/components/settings/experimental-search.tssrc/renderer/src/components/sidebar/AgentDashboardSidebarEntry.tsxsrc/renderer/src/components/sidebar/Sidebar.test.tsxsrc/renderer/src/components/sidebar/SidebarAgentsList.tsxsrc/renderer/src/components/sidebar/SidebarHeader.test.tsxsrc/renderer/src/components/sidebar/SidebarHeader.tsxsrc/renderer/src/components/sidebar/SidebarNav.test.tsxsrc/renderer/src/components/sidebar/SidebarNav.tsxsrc/renderer/src/components/sidebar/SidebarRepositoryFilterSection.tsxsrc/renderer/src/components/sidebar/SidebarWorkspaceOptionsMenu.tsxsrc/renderer/src/components/sidebar/agents-sidebar-visibility.test.tssrc/renderer/src/components/sidebar/agents-sidebar-visibility.tssrc/renderer/src/components/sidebar/index.tsxsrc/renderer/src/components/sidebar/sidebar-count-badge.tsxsrc/renderer/src/components/sidebar/sidebar-header-actions.tsxsrc/renderer/src/components/sidebar/sidebar-view-toggle.test.tsxsrc/renderer/src/components/sidebar/sidebar-view-toggle.tsxsrc/renderer/src/components/sidebar/use-workspace-reveal-body-redirect.test.tsxsrc/renderer/src/components/sidebar/use-workspace-reveal-body-redirect.tssrc/renderer/src/components/sidebar/visible-worktrees.tssrc/renderer/src/components/sidebar/workspace-options-menu-items.tsxsrc/renderer/src/components/sidebar/worktree-agent-row-selectors.tssrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.stable-message.test.tsxsrc/renderer/src/components/sidebar/worktree-card-compact-agent-row.tsxsrc/renderer/src/components/sidebar/worktree-filter-visibility.test.tssrc/renderer/src/components/sidebar/worktree-filter-visibility.tssrc/renderer/src/components/terminal-pane/stale-agent-row.tssrc/renderer/src/components/terminal-pane/use-terminal-pane-close-actions.tssrc/renderer/src/components/ui/dropdown-menu.tsxsrc/renderer/src/components/ui/popover.tsxsrc/renderer/src/hooks/useAutoAckViewedAgent.clock-skew.test.tssrc/renderer/src/hooks/useAutoAckViewedAgent.test.tssrc/renderer/src/hooks/useAutoAckViewedAgent.tssrc/renderer/src/i18n/locales/en.jsonsrc/renderer/src/i18n/locales/es.jsonsrc/renderer/src/i18n/locales/ja.jsonsrc/renderer/src/i18n/locales/ko.jsonsrc/renderer/src/i18n/locales/zh.jsonsrc/renderer/src/lib/activity-thread-display.test.tssrc/renderer/src/lib/activity-thread-display.tssrc/renderer/src/lib/short-time-ago.tssrc/renderer/src/lib/worktree-activation.tssrc/renderer/src/lib/worktree-jump-navigation.test.tssrc/renderer/src/lib/worktree-jump-navigation.tssrc/renderer/src/lib/worktree-runtime-owner-index.tssrc/renderer/src/runtime/web-session-tabs-sync/agent-status-primitives.tssrc/renderer/src/runtime/web-session-tabs-sync/state.tssrc/renderer/src/store/slices/activity-cleared-at.test.tssrc/renderer/src/store/slices/agent-pane-authority.test.tssrc/renderer/src/store/slices/agent-status-ack-cleanup.test.tssrc/renderer/src/store/slices/agent-status-authority-actions.tssrc/renderer/src/store/slices/agent-status-cleanup-actions.tssrc/renderer/src/store/slices/agent-status-contract.tssrc/renderer/src/store/slices/agent-status-drop-actions.tssrc/renderer/src/store/slices/agent-status-drop-reducer.tssrc/renderer/src/store/slices/agent-status-pane-keyed-records.tssrc/renderer/src/store/slices/agent-status-provider-session-actions.tssrc/renderer/src/store/slices/agent-status-retention-actions.tssrc/renderer/src/store/slices/agent-status-slice-contract.tssrc/renderer/src/store/slices/agent-status-worktree-drop-actions.tssrc/renderer/src/store/slices/persisted-ui-write-baseline.test.tssrc/renderer/src/store/slices/persisted-ui-write-baseline.tssrc/renderer/src/store/slices/retired-terminal-tab-state-sweep.tssrc/renderer/src/store/slices/runtime-status-recheck.tssrc/renderer/src/store/slices/ui-hydration-view-layout.test.tssrc/renderer/src/store/slices/ui-hydration-workspace-preferences.test.tssrc/renderer/src/store/slices/ui-page-navigation.test.tssrc/renderer/src/store/slices/ui/ui-slice-activity-actions.tssrc/renderer/src/store/slices/ui/ui-slice-agent-actions.tssrc/renderer/src/store/slices/ui/ui-slice-contract-core.tssrc/renderer/src/store/slices/ui/ui-slice-contract-preferences.tssrc/renderer/src/store/slices/ui/ui-slice-hydration-actions.tssrc/renderer/src/store/slices/ui/ui-slice-hydration-sanitizers.tssrc/renderer/src/store/slices/ui/ui-slice-hydration-values.tssrc/renderer/src/store/slices/ui/ui-slice-preference-actions.tssrc/renderer/src/store/slices/ui/ui-slice-settings-actions.tssrc/renderer/src/store/slices/ui/ui-slice-surface-actions.tssrc/renderer/src/store/slices/ui/ui-slice-view-actions.tssrc/renderer/src/store/slices/worktrees/listing/detected-worktree-meta.tssrc/renderer/src/store/slices/worktrees/teardown/worktree-purge-state.tssrc/renderer/src/web/preload-api/web-agent-status-api.tssrc/renderer/src/web/preload-api/web-preference-normalization.tssrc/renderer/src/web/web-preload-api-ui.test.tssrc/shared/agent-status-ipc-payload.tssrc/shared/agent-status-types.tssrc/shared/agents-sidebar-visibility.tssrc/shared/constants.tssrc/shared/default-global-settings.tssrc/shared/global-settings-types.tssrc/shared/pairing-local-ui-fields.test.tssrc/shared/pairing-local-ui-fields.tssrc/shared/persisted-ui-state-types.tssrc/shared/telemetry-property-schemas.tstests/e2e/activity-agent-pane-isolation.spec.ts
💤 Files with no reviewable changes (1)
- src/renderer/src/components/settings/AppearanceWindowSidebarSection.tsx
Included review availability: Your plan provides up to 10 included reviews per hour; 7 remain after this review.
|
@coderabbitai Fixing. Will be in the next commit |
|
Tip For best results, initiate chat on the files or code changes.
You are interacting with an AI system. |
- Remove ActivityPaneVisibility type and readActivityPaneVisibility() helper - Update agentsSidebarButton selector to match badge-less state - Simplify assertions to check pane focus instead of visibility isolation - Remove test for unread badge acknowledgement flow
- Thread defaultHostId through activity operations for correct host resolution - Add language-aware caching for standalone terminal names with cache invalidation - Fix scroll restoration bounds calculation for tall viewports - Add focus management to sidebar radio group keyboard navigation - Refresh localized sidebar content on language changes - Preserve activity state across heartbeats to prevent history loss - Improve host-id strictness in worktree jump navigation
A failed window.api.settings.get() leaves settings null, which was incorrectly treated as opt-out. Add the missing null check so the activity-view gate only applies when settings are available. Includes tests for this scenario and related edge cases in keyboard navigation, worktree jumping, and session state handling.
|
@coderabbitai Fixing. Will be in the next commit |
|
Tip For best results, initiate chat on the files or code changes.
You are interacting with an AI system. |
…ucket projections per recompute (#18241) Layers three identity memos onto the row cache #18222 landed, without changing what the four sidebar numbers say in any state. - The active-workspace descriptor list is memoized on the four slices `collectActiveDashboardWorkspaces(state, false)` actually reads. - Each worktree's bucket tally is memoized on its rows plus the acknowledgement map, so a ping that rebuilds one worktree no longer re-projects the board. - The `useShallow` selector becomes a module-level 14-identity gate, which allocates nothing on the unchanged path. - The counts object is reused by identity when all four totals hold.
…and its own model setting (#56) * feat(session-summary): show the session summary in a right-sidebar tab The brief merged in #51 could never appear. It mounted only inside ActivityThreadDetailPane, which only ActivityPrototypePage renders, and nothing has called openActivityPage since the agent list became a sidebar tab (upstream stablyai#18222). The panel was dead UI in every build. Give it a live surface: a static right-sidebar `summary` tab, following the agent session focused in the active workspace and nothing else. - Strictly focus-driven (`getFocusedAgentPaneKeyForWorktree`). Another agent in the same workspace is not this pane's subject: showing the most recently active one reads as though it were the session the user is looking at. With nothing focused the pane asks the user to focus an agent session. - Finished sessions already qualify, now pinned by a test: the fold resolves its transcript from a provider session, and main retains a `providerSessionOnly` remnant row for a dropped status row (`server-cleanup.ts`), so a hibernated pane the user focuses summarizes like a live one. - The ledger view and header state are extracted from the activity strip (session-summary-ledger-view.tsx, session-summary-presentation.ts) so both hosts render one component instead of two copies. - The tab is declared in the three allowlists a static tab needs: the shared union, the client-ui schema, and the main-process persistence normalizer. Dropping any one makes the tab vanish or reset to Explorer on restart, so the regression test moves onto the new value. Wire-safe in both directions: an older host drops a value it cannot express (tolerateUnknownValues) instead of failing the whole ui.set batch, and an older client normalizes an unknown tab to Explorer. Also adds docs/reference/session-summary.md, which two source files already referenced but which did not exist. * feat(session-summary): give the fold its own agent and model setting A summary borrowed the commit-message Source Control AI recipe, so its cost could not be changed without changing commit messages — and editing the commit prompt looked like it should affect summaries when it never could. Give the fold its own setting, same shape, separate storage: - `sessionSummaryAi` (Settings → Agents → Session summaries): agent, model, per-model thinking effort, and the custom command for a custom agent. Resolved by `shared/session-summary-ai.ts`; the fold now reads it instead of operation 'commitMessage'. Unset means the default agent and that agent's default model and effort, so nothing has to be configured for summaries to work. - The selection rules (capability lookup, model/effort seeding on switch, patch building) move to `lib/ai-generation-settings.ts`, and the picker fields to `settings/ai-generation-fields.tsx`, so the AI-author card and this block share one implementation instead of two. The block is also registered in settings search, which is how the Agents pane is reached. - Primitive typography is left to the primitives: the moved fields no longer pass `text-xs` to <Label>/<SelectTrigger> or `font-mono text-xs` to <Input> (the design-system gate forbids restyling them), and the labels sit above their controls instead of in a 92px column that only fitted the smaller type. Tests: resolver units including "ignores the source-control AI choice entirely", the fold-params contract, and the settings block's own behaviour. Verified in the running app: the block shows Codex / GPT-5.4 / High from `sessionSummaryAi` while `commitMessageAi` stays null, and the value persists in profile state. * fix(agent-spec): declare effort levels for Copilot's Claude models Copilot's hosted Claude entries listed no thinking levels, so the model/effort pickers hid the effort control for exactly the models users pick when they want reasoning — while the CLI accepts `--effort` (an alias of `--reasoning-effort`) for any of its models and validates the value list globally, not per model. Declare the same low/medium/high/xhigh levels the GPT entries already use, with the same 'low' default, so those entries expose effort in Settings and in the per-action recipes. * feat(session-summary): list a dynamic agent's models from its own CLI The picker could not offer a model for a dynamic agent: Pi advertises a single `Config default` stub, and its real list only exists in its CLI output. Selecting Pi therefore gave no model choice and no effort control at all, even though the fold passes `--model` and `--thinking` and `parsePiModels` reports 60+ models with effort levels. Probe once per agent and cache the answer: - Resolve the selected agent through the spec, then replace its model list with whatever a probe reported for that agent (`discoveredModelsByAgent`, keyed by agent so another agent's probe can never be applied to this one). The existing panel only ever read discovered models in the resolver, never in the picker. - Probe through `git:discoverCommitMessageModels` with no worktree or connection: host-native, which is where the fold spawns the CLI. Cache only a real probe — a `spec`-origin result is the built-in list and caching it would retire the probe for that agent permanently. - Storage stays host-keyed (`discoveredModelsByAgentByHost.local`) while the pane resolves the local slot, because the fold reads the transcript locally too; a host-aware fold can then land without a migration. - The pane says `Discovering models…` while the probe runs and falls back to the built-in list with an explanation when it fails, instead of silently showing a one-entry list. Verified in the running app: selecting Pi exposes 63 probed models with effort levels (Model: Deepseek Deepseek Flash, Thinking effort: Low) and caches them in both slots. * feat(ai-settings): keep the effort control visible for every model The effort dropdown rendered only when the selected model declared thinking levels, so it silently vanished for models that take none — Pi's four `thinking: no` rows, Copilot's `auto` and `gpt-4.1` — which reads as a missing feature rather than as a property of the model. Render the row whenever a model is selected: enabled with that model's levels, or disabled showing `—` with a one-line explanation. Levels stay model-scoped, which is how `selectedThinkingByModel` is modelled. Verified in the running app with Pi: `deepseek/deepseek-flash` shows an enabled Low/…/Xhigh control, `omlx/Laguna-S-2.1-oQ4e` shows the disabled control and the explanation, and the Agent and Model dropdowns stay independent of it. * fix(session-summary): create the fold's scratch dir, and refuse an unusable agent Two ways a fold could not do what the user asked: - The scratch cwd (`<tmpdir>/orca-session-summary`) was never created, and the launcher passes it straight to spawn, so every fold failed with ENOENT on a machine that had never had that directory. The brain now creates it, because it is the component that requires it. - A resolver that reported "nothing usable is configured" (Custom with an empty command, or every candidate agent disabled) was turned into the default agent. That runs a provider the user did not choose — possibly one they disabled — with their transcript. It now fails the fold with a message naming the setting. * fix(session-summary): run the model and effort the pane displays The pane could show one model while the fold ran another, and an effort the user picked could be dropped: - Effort was resolved through the spec/synthesis helper, which guesses thinking support from the model id (`withOpenAiThinking` matches gpt-5/codex). A probed Pi model therefore produced no thinking level, so picking High changed nothing. Resolution now prefers the probed model's own levels. - A model a probe no longer lists was displayed as replaced while execution still passed the stale id; conversely, an unset choice displayed the probe's first model while execution passed `default`. The spec default now stays in the list, and a stored id is validated against the probe (or, for a static agent, the spec). Both sides now read one rule, so what the dropdown says is what the CLI is given. * fix(session-summary): follow the session, and stay honest about what it can do - The pane keyed only on the pane key, so a new session started in the pane the user was already focused on kept the previous session's brief. The key now includes the provider session id, which makes the service reset the ledger. - The tab was offered in every window, but a paired web client composes no `sessionSummary` bridge, so the pane would sit on its loading state forever. The activity bar now omits the tab when the bridge is missing, and the pane says so if it is somehow opened. - A successful probe was cached for the life of the install with no way to list again, so models the CLI began reporting were unreachable. The pane offers Refresh models for a dynamic agent. * fix(ci): prepare shared FPM tools before parallel Linux packaging
* more obvious toggle
* more obvious toggle
* feat(activity): redesign thread rows and add child agent filtering
- Emphasize task title and last activity in row layout over metadata
- Add child agent toggle; hide orchestration workers by default
- Support collapsible groups and ungrouped view mode
- Improve orchestration worker message handling to surface replies
- Add sidebar search and filter controls for agent activity
* periodic checkin
* feat(activity): add "Clear completed" action and performance improvement
- Add "Clear completed" action for activity threads with undo window; clears completed and interrupted rows from view, persists across restart
- Virtualize activity thread list to render only viewport-bounded rows
- Cache activity thread search text to prevent recomputation on every keystroke
- Cache dashboard bucket counts per-worktree for selective invalidation on unrelated changes
- Use useDeferredValue for activity search filtering to keep input responsive
- Make compact mode the default display for activity threads
- Add activity-cleared-at persisted state tracking (per-pane cutoff timestamps)
* improve style
* minor change
* feat(activity): add persisted host and project filters to agents view
Agents scope filters are deliberately separate from workspace-nav filters so a monitoring surface never inherits workspace context silently. Filters survive restarts and always display an active-filter chips row with hidden count, making filtering visible and reversible.
* Graduate Agents view from experimental, refine activity handling
- Agents Dashboard moves from experimental to standard feature with showAgentsSidebar setting controlling visibility
- Add identity-checked cache eviction (dropPersisted IPC) to prevent newer runs from being evicted when UI clears older status, fixing clear-completed safety
- Extract ActivityThreadHoverCardSummary and ActivityThreadListToolbar components for better organization and reusability
- Implement mark-thread-read as separate action from select with clickable bell icon
- Add hasActivityThreadWorkspace helper for checking workspace availability across hosts (SSH/runtime targets)
- Preserve scope filter array identity during hydration for memo optimization
- Track manually-unread turns in auto-ack to prevent re-acknowledgement
- Clean up activity cleared-at cutoffs on pane retirement
- Remove activity-thread-hover-card max-lines lint override (code refactored below threshold)
* Refactor agent cache identity to use timing fields only
- Simplify AgentStatusCacheIdentity: keep only paneKey, receivedAt, stateStartedAt
- This fixes silent no-ops where renderer-enriched fields diverged from main's cache
- Add worktree-jump-navigation for navigating activity to workspaces
- Add manual mark-unread protection separate from auto-ack
- Optimize activity owner resolution with per-build memoization
- Optimize detected worktree lookup with indexed search
* Remove sticky header, add scroll position persistence
Replace the floating sticky header overlay with scroll position memory via
a ref. This preserves the user's scroll location when switching between
threads or remounting the agents list, improving UX without requiring
React state.
* Implement sticky group headers in activity thread list
Keep group headers visible at the top while scrolling when threads are grouped. Headers stick to the viewport while their section is in view, then unstick as the next header approaches.
* add blue flash
* update settings appearnce
* Extracted activity acknowledgement/clearance actions from the oversized UI slice.
- Removed dead sidebar search/menu props and the unused search ref.
- Removed the unnecessary sidebar visibility bitmask.
- Replaced hardcoded sidebar toggle colors with design-system tokens.
- Removed duplicate “mark all read / clear completed” controls in the sidebar.
- Preserved manual-unread state correctly across pane retire, transfer, and drop.
- Made clear-completed cutoffs monotonic so clock skew cannot resurrect old activity.
- Fixed blank workspace names in hover cards with the existing fallback helper.
- Added missing localization entries and stabilized hydrated filter array identity.
- Updated misleading Agents setting copy to describe both sidebar surfaces.
* add onboarding guide for the new agents panel
* Add activity clearance tracking and synced agent view settings
Agent view filters and presentation settings now sync across paired clients.
Preserves per-pane activity clearance cutoffs in persistent state. Improves
activity thread row accessibility with proper ARIA roles, and preserves
terminal host ownership after pane teardown via retained terminal handle.
* rm html
* Graduate Agents from experimental and improve activity visibility
- Migrate `showAgentsSidebar` setting from legacy experimental flags; default new profiles to the agents sidebar
- Replace scoped-thread filtering with visible-thread filtering so bulk actions (mark all read, clear completed) only affect rendered rows
- Rewrite child agent classification as a set of visible pane keys to fix orphan promotion and parent-cycle handling
- Improve activity cleared-at cutoff lifecycle: preserve on row dismissal (pane may still be live) but clear on pane removal
- Add pagehide flush for pending clear-completed evictions so quit/reload cannot replay cleared activity
- Polish agents sidebar: unread count badge, expand button, onboarding intro for migrated/new users
- Extract shared time-ago formatting to a library module
- Fix scroll restoration to defer until content can contain the saved offset
- Improve stable message hold for compact agent rows using state instead of refs
- Add worktree filter-visibility check to distinguish collapsed-but-unfiltered from filtered-hidden
* Graduate Agents from experimental and improve activity visibility
- Remove the deprecated full-page Agents view; fix settings navigation fallback
- Refactor bulk action bindings and separate mark-all-read from visible threads
- Preserve sidebar collapse state across remounts; fix child-agent badge filtering
- Add safety window for scroll-restore and improve worktree host-qualified filtering
* Graduate Agents from experimental and add manual unread tracking
- Move Agents sidebar from experimental settings to standard feature with intro flow
- Add persistent manual unread turn tracking for activity feed
- Consolidate workspace activation through activateAndRevealWorkspace dispatcher
- Improve sidebar view toggle with radio semantics and arrow-key navigation
* Graduate Agents sidebar and separate dashboard experiment
The Agents tab now has its own `showAgentsSidebar` setting (defaults on) independent from the dashboard popout experiment. Activity unread counting is simplified to count all events uniformly without mode-specific filtering. Dashboard visibility is now controlled solely by `experimentalAgentDashboardPopout`, with its own UI in the Experimental settings pane. Migration path updated: only `experimentalActivity=true` graduates to the sidebar; the dashboard experiment remains separate.
* Add agent-session tab support to activity tracking
Build activity event contexts from structured agent-session tabs and
worktree-attributed status entries. When activating a thread, try
agent-session tab activation before falling back to terminal pane.
* • The workspace sidebar tab is now a static Spaces
label—no grouping-based “Projects” label or hidden
width-reservation span.
* Show unread count badge and prioritize attention-needing agent threads
Activity group order now surfaces threads needing attention (blocked,
waiting, interrupted) before working/done so they're never buried. The
Agents tab shows an unread count badge while viewing Spaces, since the
open Agents list already highlights unread rows.
Also improves UX text ("Hide Agents" vs "Maybe later"), accessibility
with proper ARIA labels, and handles edge cases: preserves read state
for retained panes on SSH reconnect and handles deleted worktrees
gracefully in navigation.
* Batch agent-status evictions and optimize activity pane rebuilds
- Add dropPersistedStatusEntries batch API; consolidate evictions into one persist
- Implement fallback timeout in clear-completed for unseen toast callbacks
- Project only activity-relevant tabs; memoize terminal tab derivations
- Stabilize activity virtualizer key to prevent unnecessary item measurements
* Remove unread count badge from Agents sidebar tab
Simplify useActivityUnreadCount by removing the enabled parameter and
conditional logic, as the badge is no longer displayed in the UI.
* Deduplicate activity unread counts across source overlaps
Live pane status is the primary source; retained and migration entries
serve as fallback caches that may briefly overlap it during lifecycle
transitions. Count each pane only once by tracking seen keys, prioritizing
the live status as the canonical source.
Also fix monitoring state display: it's a distinct agent state, not a
tool-running row state, so exclude it from tool preview checks.
* Update activity pane tests to remove unread badge assertions
- Remove ActivityPaneVisibility type and readActivityPaneVisibility() helper
- Update agentsSidebarButton selector to match badge-less state
- Simplify assertions to check pane focus instead of visibility isolation
- Remove test for unread badge acknowledgement flow
* Fix activity pane workspace resolution and localization handling
- Thread defaultHostId through activity operations for correct host resolution
- Add language-aware caching for standalone terminal names with cache invalidation
- Fix scroll restoration bounds calculation for tall viewports
- Add focus management to sidebar radio group keyboard navigation
- Refresh localized sidebar content on language changes
- Preserve activity state across heartbeats to prevent history loss
- Improve host-id strictness in worktree jump navigation
* Preserve activity view when settings fetch fails
A failed window.api.settings.get() leaves settings null, which was
incorrectly treated as opt-out. Add the missing null check so the
activity-view gate only applies when settings are available.
Includes tests for this scenario and related edge cases in keyboard
navigation, worktree jumping, and session state handling.
…ucket projections per recompute (stablyai#18241) Layers three identity memos onto the row cache stablyai#18222 landed, without changing what the four sidebar numbers say in any state. - The active-workspace descriptor list is memoized on the four slices `collectActiveDashboardWorkspaces(state, false)` actually reads. - Each worktree's bucket tally is memoized on its rows plus the acknowledgement map, so a ping that rebuilds one worktree no longer re-projects the board. - The `useShallow` selector becomes a module-level 14-identity gate, which allocates nothing on the unchanged path. - The counts object is reused by identity when all four totals hold.

ELI5
The Agents activity view is now a first-class, easier-to-scan workspace for monitoring agent work. You can filter it to the projects and hosts you care about, focus on unread or attention-needed threads, and clear completed work without losing state across restarts.
What Changed
Why
The previous activity experience made important agent work easy to miss and became expensive to render as history grew. This update makes the view more actionable while keeping state stable across restarts and remote-host lifecycle transitions.
Linked Issue
No linked issue was included in the PR metadata.
Visual Proof
UI changes are contained in the Agents activity view and sidebar; visual attachments were not added to this retrospective description update.
Testing
Automated tests were added or updated across the activity, dashboard, sidebar, persistence, and IPC layers. The merged PR's CI status is the source of truth for the full validation matrix.
AI Disclosure
Internal contributor; not applicable.
Review
Agent skill upstream boundary
Notes
Considered cross-platform, SSH/remote, persistence, backwards-compatibility, accessibility, and rendering-performance paths in the implementation and tests.
Checklist