fix(sidebar): move agent child disclosure to the right (#23577)

* fix(sidebar): move agent child disclosure to the timestamp slot

* fix(sidebar): align agent disclosure with summary caret
This commit is contained in:
Brennan Benson
2026-09-28 14:27:29 -07:00
committed by GitHub
parent 1a0ff42eb1
commit dbc4e21d9c
8 changed files with 284 additions and 110 deletions
+25
View File
@@ -1626,6 +1626,31 @@ html.native-shell .app-layout {
animation: compact-agent-expansion-reveal 180ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
/* Keep the disclosure in the timestamp slot without moving adjacent content. */
.agent-child-disclosure-time {
visibility: hidden;
}
@media (hover: hover) {
.agent-child-disclosure[data-expanded='false'] .agent-child-disclosure-time {
visibility: visible;
}
.agent-child-disclosure[data-expanded='false'] [data-agent-child-disclosure-button] {
opacity: 0;
}
.agent-disclosure-row:hover .agent-child-disclosure-time,
.agent-disclosure-row:focus-within .agent-child-disclosure-time {
visibility: hidden;
}
.agent-disclosure-row:hover [data-agent-child-disclosure-button],
.agent-disclosure-row:focus-within [data-agent-child-disclosure-button] {
opacity: 1;
}
}
/* Why: the collapsed summary still uses pill spacing, while expanded compact
agents read as a quiet tree inside the existing worktree card. */
.compact-agent-summary-panel {
@@ -0,0 +1,157 @@
/** @vitest-environment happy-dom */
import { fireEvent, render, screen, cleanup } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { CompactAgentRow } from '../sidebar/worktree-card-compact-agent-row'
import { TooltipProvider } from '../ui/tooltip'
import DashboardAgentRow from './DashboardAgentRow'
import type { DashboardAgentRow as AgentRow } from './useDashboardData'
import { DashboardAgentChildDisclosure } from './DashboardAgentChildDisclosure'
vi.mock('./use-agent-row-conversation-name', () => ({ useAgentRowConversationName: () => null }))
vi.mock('../sidebar/CacheTimer', () => ({
default: () => null,
usePromptCacheCountdownForPane: () => null
}))
afterEach(cleanup)
const agent: AgentRow = {
paneKey: 'tab:leaf',
agentType: 'claude',
state: 'working',
startedAt: 60000,
entry: {
paneKey: 'tab:leaf',
state: 'working',
prompt: 'Review the change',
updatedAt: 60000,
stateStartedAt: 60000,
stateHistory: []
},
tab: {
id: 'tab',
ptyId: null,
worktreeId: 'workspace',
title: 'Agent',
customTitle: null,
color: null,
sortOrder: 0,
createdAt: 1
}
}
describe('agent child disclosure', () => {
it('toggles children without activating the surrounding agent or workspace', () => {
const activate = vi.fn()
const toggle = vi.fn()
const pointerDown = vi.fn()
const keyDown = vi.fn()
render(
<div onClick={activate} onPointerDown={pointerDown} onKeyDown={keyDown}>
<DashboardAgentChildDisclosure
childAgentCount={2}
childAgentsExpanded={false}
onToggleChildAgents={toggle}
timestamp="5m"
/>
</div>
)
const button = screen.getByRole('button', { name: 'Show 2 child agents' })
fireEvent.pointerDown(button)
fireEvent.keyDown(button, { key: 'Enter' })
fireEvent.keyDown(button, { key: ' ' })
fireEvent.click(button)
expect(toggle).toHaveBeenCalledTimes(1)
expect(activate).not.toHaveBeenCalled()
expect(pointerDown).not.toHaveBeenCalled()
expect(keyDown).not.toHaveBeenCalled()
})
it('updates the accessible action and retains the timestamp when expanded', () => {
const toggle = vi.fn()
const { rerender } = render(
<DashboardAgentChildDisclosure
childAgentCount={1}
childAgentsExpanded={false}
onToggleChildAgents={toggle}
timestamp="5m"
/>
)
expect(
screen.getByRole('button', { name: 'Show 1 child agent' }).getAttribute('aria-expanded')
).toBe('false')
rerender(
<DashboardAgentChildDisclosure
childAgentCount={1}
childAgentsExpanded
onToggleChildAgents={toggle}
timestamp="5m"
/>
)
expect(
screen.getByRole('button', { name: 'Hide 1 child agent' }).getAttribute('aria-expanded')
).toBe('true')
expect(screen.getByText('5m')).toBeTruthy()
})
it('does not offer a disclosure without children or a toggle action', () => {
const { rerender } = render(
<DashboardAgentChildDisclosure
childAgentCount={0}
childAgentsExpanded={false}
onToggleChildAgents={vi.fn()}
/>
)
expect(screen.queryByRole('button')).toBeNull()
rerender(<DashboardAgentChildDisclosure childAgentCount={2} childAgentsExpanded={false} />)
expect(screen.queryByRole('button')).toBeNull()
})
})
describe.each(['compact', 'full'] as const)('%s row disclosure actions', (mode) => {
it.each([undefined, 'eligible'] as const)(
'keeps child expansion separate from row actions in %s send mode',
(sendTargetStatus) => {
const onActivate = vi.fn(),
onSendTargetClick = vi.fn(),
onDismiss = vi.fn(),
onToggleChildAgents = vi.fn()
const props = {
agent,
now: 120000,
childAgentCount: 2,
childAgentsExpanded: false,
onToggleChildAgents,
onActivate,
sendTargetStatus,
onSendTargetClick
}
render(
<TooltipProvider>
{mode === 'compact' ? (
<CompactAgentRow {...props} />
) : (
<DashboardAgentRow {...props} onDismiss={onDismiss} hideExpand />
)}
</TooltipProvider>
)
fireEvent.click(screen.getByRole('button', { name: 'Show 2 child agents' }))
expect(onToggleChildAgents).toHaveBeenCalledTimes(1)
expect(onActivate).not.toHaveBeenCalled()
expect(onSendTargetClick).not.toHaveBeenCalled()
expect(onDismiss).not.toHaveBeenCalled()
fireEvent.click(screen.getByText('Review the change'))
if (sendTargetStatus) {
expect(onSendTargetClick).toHaveBeenCalledWith(agent.paneKey)
expect(onActivate).not.toHaveBeenCalled()
} else {
expect(onActivate).toHaveBeenCalledWith(agent.tab.id, agent.paneKey)
if (mode === 'full') {
fireEvent.click(screen.getByRole('button', { name: 'Dismiss agent' }))
expect(onDismiss).toHaveBeenCalledWith(agent.paneKey)
expect(onActivate).toHaveBeenCalledTimes(1)
}
}
}
)
})
@@ -1,18 +1,21 @@
import React, { useCallback } from 'react'
import { ChevronRight } from 'lucide-react'
import { ChevronDown } from 'lucide-react'
import { cn } from '@/lib/utils'
import { Button } from '@/components/ui/button'
import { translate } from '@/i18n/i18n'
type Props = {
childAgentCount?: number
childAgentsExpanded: boolean
onToggleChildAgents?: () => void
timestamp?: React.ReactNode
}
export function DashboardAgentChildDisclosure({
childAgentCount,
childAgentsExpanded,
onToggleChildAgents
onToggleChildAgents,
timestamp
}: Props) {
const hasChildDisclosure =
typeof childAgentCount === 'number' &&
@@ -40,29 +43,46 @@ export function DashboardAgentChildDisclosure({
}
return (
<button
type="button"
onClick={handleToggleChildren}
onMouseDown={stopMouseDown}
onKeyDown={stopKeyDown}
className="-ml-0.5 inline-flex size-4 shrink-0 items-center justify-center rounded-sm border border-sidebar-border/80 bg-sidebar text-foreground/80 shadow-xs hover:bg-sidebar-accent hover:text-foreground"
aria-label={translate(
'auto.components.dashboard.DashboardAgentChildDisclosure.1b57ce9fa4',
'{{value0}} {{value1}} child {{value2}}',
{
value0: childAgentsExpanded ? 'Hide' : 'Show',
value1: childAgentCount,
value2: childAgentCount === 1 ? 'agent' : 'agents'
}
)}
aria-expanded={childAgentsExpanded}
<span
className="agent-child-disclosure relative inline-grid h-5 min-w-5 shrink-0 items-center justify-items-end"
data-expanded={childAgentsExpanded}
>
<ChevronRight
className={cn(
'size-3 transition-transform duration-150',
childAgentsExpanded && 'rotate-90'
<span
className="agent-child-disclosure-time col-start-1 row-start-1 pointer-events-none"
aria-hidden
>
{timestamp}
</span>
{/* Why: align the 12px icon with adjacent row icons while keeping its 24px hit target. */}
<Button
variant="ghost"
size="icon-xs"
type="button"
onClick={handleToggleChildren}
onMouseDown={stopMouseDown}
onPointerDown={(event) => event.stopPropagation()}
onKeyDown={stopKeyDown}
data-agent-child-disclosure-button=""
className="col-start-1 row-start-1 -mr-1.5"
aria-label={translate(
'auto.components.dashboard.DashboardAgentChildDisclosure.1b57ce9fa4',
'{{value0}} {{value1}} child {{value2}}',
{
value0: childAgentsExpanded ? 'Hide' : 'Show',
value1: childAgentCount,
value2: childAgentCount === 1 ? 'agent' : 'agents'
}
)}
/>
</button>
aria-expanded={childAgentsExpanded}
>
<ChevronDown
className={cn(
'size-3 transition-transform duration-150',
childAgentsExpanded && 'rotate-180'
)}
aria-hidden
/>
</Button>
</span>
)
}
@@ -4,7 +4,6 @@ import { AgentStateDot, agentStateLabel, type AgentDotState } from '@/components
import { AgentIcon } from '@/lib/agent-catalog'
import { agentTypeToIconAgent, formatAgentTypeLabel } from '@/lib/agent-status'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { DashboardAgentChildDisclosure } from './DashboardAgentChildDisclosure'
import { DashboardAgentRowMessage } from './DashboardAgentRowMessage'
import { DashboardAgentRowTrailingControls } from './DashboardAgentRowTrailingControls'
import { DashboardAgentRowToolStep } from './DashboardAgentRowToolStep'
@@ -56,12 +55,10 @@ type Props = {
hideExpand?: boolean
/** Reuse the row's hover tint to show the focused terminal pane's agent. */
isFocusedPane?: boolean
// Why: inline-card orchestration rows fold children under a leading chevron.
// Why: inline-card orchestration rows can fold their child agents.
childAgentCount?: number
childAgentsExpanded?: boolean
onToggleChildAgents?: () => void
// Why: a top-level chevron hangs in the card gutter so the state dot keeps the column of chevron-less rows.
disclosureInGutter?: boolean
// Why: chevron indentation replaces fixed-offset lineage connector art.
hideLineageConnectors?: boolean
// Why: send-popover target mode makes row clicks send/no-op instead of navigating.
@@ -83,7 +80,6 @@ const DashboardAgentRow = React.memo(function DashboardAgentRow({
childAgentCount,
childAgentsExpanded = false,
onToggleChildAgents,
disclosureInGutter = false,
hideLineageConnectors = false,
sendTargetStatus,
sendTargetDisabledReason,
@@ -185,8 +181,7 @@ const DashboardAgentRow = React.memo(function DashboardAgentRow({
onClick={handleActivate}
className={cn(
// Why: named group scopes the X-reveal to this row, not every row in the card.
'group/agent-row relative flex flex-col py-1',
hasChildDisclosure && disclosureInGutter ? '-ml-7' : '-ml-2',
'agent-disclosure-row group/agent-row relative -ml-2 flex flex-col py-1',
isLineageChild ? 'pl-5 pr-2' : 'px-2',
// Why: hover wash stays softer than the enclosing card's highlight.
'cursor-pointer rounded-sm worktree-agent-row-hover',
@@ -229,11 +224,6 @@ const DashboardAgentRow = React.memo(function DashboardAgentRow({
</span>
) : null}
<div className="flex items-center gap-1.5">
<DashboardAgentChildDisclosure
childAgentCount={childAgentCount}
childAgentsExpanded={childAgentsExpanded}
onToggleChildAgents={onToggleChildAgents}
/>
{/* Why: state dot sits in the leading gutter so the eye can scan one column for row state. */}
<Tooltip>
<TooltipTrigger asChild>
@@ -288,6 +278,9 @@ const DashboardAgentRow = React.memo(function DashboardAgentRow({
<DashboardAgentRowTrailingControls
paneKey={agent.paneKey}
relativeTimestamp={relativeTimestamp}
childAgentCount={childAgentCount}
childAgentsExpanded={childAgentsExpanded}
onToggleChildAgents={onToggleChildAgents}
expanded={expanded}
hideExpand={hideExpand}
hideDismiss={agent.rowSource === 'subagent'}
@@ -2,8 +2,12 @@ import React, { useCallback } from 'react'
import { ChevronDown, Send, X } from 'lucide-react'
import { translate } from '@/i18n/i18n'
import { cn } from '@/lib/utils'
import { DashboardAgentChildDisclosure } from './DashboardAgentChildDisclosure'
type DashboardAgentRowTrailingControlsProps = {
childAgentCount?: number
childAgentsExpanded?: boolean
onToggleChildAgents?: () => void
paneKey: string
relativeTimestamp: string | null
expanded: boolean
@@ -18,6 +22,9 @@ type DashboardAgentRowTrailingControlsProps = {
}
export function DashboardAgentRowTrailingControls({
childAgentCount,
childAgentsExpanded = false,
onToggleChildAgents,
paneKey,
relativeTimestamp,
expanded,
@@ -64,8 +71,15 @@ export function DashboardAgentRowTrailingControls({
[onSendTargetClick, paneKey, sendTargetStatus]
)
const hasChildDisclosure = Boolean(childAgentCount && onToggleChildAgents)
return (
<span className="relative ml-auto flex h-3.5 w-12 shrink-0 items-center justify-end">
<span
className={cn(
'relative ml-auto flex shrink-0 items-center justify-end',
hasChildDisclosure ? 'h-5 gap-1' : 'h-3.5 w-12'
)}
>
{(sendTargetStatus === 'eligible' || sendTargetStatus === 'sending') && (
<button
type="button"
@@ -75,6 +89,7 @@ export function DashboardAgentRowTrailingControls({
disabled={sendTargetStatus === 'sending'}
className={cn(
'worktree-agent-send-target-button absolute right-0 top-1/2 z-10 inline-flex h-5 -translate-y-1/2 items-center gap-1 rounded-md border px-1.5 text-[10px] font-medium leading-none transition-[background-color,border-color,color,opacity]',
hasChildDisclosure && 'static translate-y-0',
sendTargetStatus === 'sending' && 'cursor-progress opacity-75'
)}
aria-label={translate(
@@ -90,7 +105,7 @@ export function DashboardAgentRowTrailingControls({
<span>{translate('auto.components.dashboard.DashboardAgentRow.912e136cd9', 'Send')}</span>
</button>
)}
{!sendTargetStatus && hideDismiss && relativeTimestamp !== null && (
{!hasChildDisclosure && !sendTargetStatus && hideDismiss && relativeTimestamp !== null && (
<span
className="pointer-events-none shrink-0 text-[10px] leading-none text-muted-foreground/60"
aria-hidden
@@ -100,7 +115,7 @@ export function DashboardAgentRowTrailingControls({
)}
{/* Why: timestamp and dismiss-X share one slot. On no-hover devices the X
is visible by default, so the timestamp must yield there too. */}
{!sendTargetStatus && !hideDismiss && relativeTimestamp !== null && (
{!hasChildDisclosure && !sendTargetStatus && !hideDismiss && relativeTimestamp !== null && (
<span className="relative grid grid-cols-1 grid-rows-1 shrink-0 items-center justify-items-end">
<span
className={cn(
@@ -132,7 +147,7 @@ export function DashboardAgentRowTrailingControls({
</button>
</span>
)}
{!sendTargetStatus && !hideDismiss && relativeTimestamp === null && (
{!sendTargetStatus && !hideDismiss && (hasChildDisclosure || relativeTimestamp === null) && (
<button
type="button"
onClick={handleDismiss}
@@ -152,6 +167,18 @@ export function DashboardAgentRowTrailingControls({
<X className="size-3.5" />
</button>
)}
{hasChildDisclosure && (
<DashboardAgentChildDisclosure
childAgentCount={childAgentCount}
childAgentsExpanded={childAgentsExpanded}
onToggleChildAgents={onToggleChildAgents}
timestamp={
<span className="text-[10px] leading-none text-muted-foreground/60">
{relativeTimestamp}
</span>
}
/>
)}
{!hideExpand && (
<button
type="button"
@@ -132,7 +132,6 @@ vi.mock('@/components/dashboard/DashboardAgentRow', () => ({
childAgentCount,
childAgentsExpanded,
onToggleChildAgents,
disclosureInGutter,
onActivate
}: {
agent: { paneKey: string }
@@ -143,7 +142,6 @@ vi.mock('@/components/dashboard/DashboardAgentRow', () => ({
childAgentCount?: number
childAgentsExpanded?: boolean
onToggleChildAgents?: () => void
disclosureInGutter?: boolean
onActivate: (tabId: string, paneKey: string) => void
}) => {
capturedRowActivations.push({ paneKey: agent.paneKey, onActivate })
@@ -155,7 +153,6 @@ vi.mock('@/components/dashboard/DashboardAgentRow', () => ({
data-disabled-reason={sendTargetDisabledReason}
data-has-send-handler={typeof onSendTargetClick === 'function' ? 'true' : 'false'}
data-pane-key={agent.paneKey}
data-disclosure-in-gutter={disclosureInGutter ? 'true' : 'false'}
>
{agent.paneKey}
{typeof childAgentCount === 'number' && childAgentCount > 0 ? (
@@ -438,8 +435,6 @@ describe('WorktreeCardAgents', () => {
expect(markup).toContain('role="tree"')
expect(markup).toContain('data-pane-key="tab-parent:1"')
expect(markup).toContain('data-pane-key="tab-child:1"')
expect(markup).toContain('data-pane-key="tab-parent:1" data-disclosure-in-gutter="true"')
expect(markup).toContain('data-pane-key="tab-child:1" data-disclosure-in-gutter="false"')
expect(markup).toContain('aria-label="Hide 1 child agent"')
expect(markup).toContain('aria-expanded="true"')
})
@@ -245,7 +245,6 @@ const WorktreeCardAgentsBody = React.memo(function WorktreeCardAgentsBody({
}
const childAgents = childrenByParentPaneKey.get(agent.paneKey) ?? []
const hasChildAgents = childAgents.length > 0
const isRootAgent = ancestorPaneKeys.size === 0
// Why: spawned child agents are actionable work, so show them as soon as the parent appears (disclosure still folds noise).
const expanded = !collapsedLineageParents.has(agent.paneKey)
const sendTarget = isAgentSendTargetModeActive
@@ -271,14 +270,12 @@ const WorktreeCardAgentsBody = React.memo(function WorktreeCardAgentsBody({
stateDotSize="sm"
// Why: clicking the row jumps straight to the agent, so the expand chevron is redundant (keep the identity glyph).
hideExpand
// Why: fold children under the parent row's leading chevron so a parent reads as a tree node (Variant B in the mockups).
// Why: child expansion belongs to the parent agent row.
childAgentCount={hasChildAgents ? childAgents.length : undefined}
childAgentsExpanded={expanded}
onToggleChildAgents={
hasChildAgents ? () => toggleLineageParent(agent.paneKey) : undefined
}
// Why: nested levels keep the chevron inline; their gutter is the parent's guide line.
disclosureInGutter={isRootAgent}
isFocusedPane={agent.paneKey === focusedAgentPaneKey}
sendTargetStatus={sendTarget?.status}
sendTargetDisabledReason={sendTarget?.disabledReason}
@@ -307,7 +304,6 @@ const WorktreeCardAgentsBody = React.memo(function WorktreeCardAgentsBody({
}
const childAgents = childrenByParentPaneKey.get(agent.paneKey) ?? []
const hasChildAgents = childAgents.length > 0
const isRootAgent = ancestorPaneKeys.size === 0
const expanded = !collapsedLineageParents.has(agent.paneKey)
const sendTarget = isAgentSendTargetModeActive
? (sendTargetsByPaneKey.get(agent.paneKey) ?? {
@@ -334,7 +330,6 @@ const WorktreeCardAgentsBody = React.memo(function WorktreeCardAgentsBody({
onToggleChildAgents={
hasChildAgents ? () => toggleLineageParent(agent.paneKey) : undefined
}
disclosureInGutter={isRootAgent}
isFocusedPane={agent.paneKey === focusedAgentPaneKey}
cacheTimerActive={cacheTimerActive}
/>
@@ -1,12 +1,11 @@
import React, { useCallback, useEffect, useRef } from 'react'
import { ChevronRight } from 'lucide-react'
import { DashboardAgentChildDisclosure } from '@/components/dashboard/DashboardAgentChildDisclosure'
import { AgentStateDot, agentStateLabel } from '@/components/AgentStateDot'
import type { DashboardAgentRow as DashboardAgentRowData } from '@/components/dashboard/useDashboardData'
import { AgentIcon } from '@/lib/agent-catalog'
import { agentTypeToIconAgent, formatAgentTypeLabel } from '@/lib/agent-status'
import { cn } from '@/lib/utils'
import { getAgentDotState } from './worktree-card-agent-summary'
import { translate } from '@/i18n/i18n'
import { getAgentRowPrimaryText } from '@/lib/agent-row-primary-text'
import { formatAgentToolPreview } from '@/lib/agent-row-tool-preview'
import { agentNoUpdateLabel } from '@/lib/agent-row-decay-state'
@@ -70,14 +69,6 @@ function getCompactAgentTime(agent: DashboardAgentRowData, now: number): string
return startedAt > 0 ? formatShortTimeAgo(startedAt, now) : null
}
function stopActivationKeyPropagation(e: React.KeyboardEvent): void {
// Why: the surrounding worktree list handles Enter/Space as row activation.
// Focused nested buttons need those keys to stay local.
if (e.key === 'Enter' || e.key === ' ') {
e.stopPropagation()
}
}
type CompactAgentRowProps = {
agent: DashboardAgentRowData
now: number
@@ -90,7 +81,6 @@ type CompactAgentRowProps = {
childAgentCount?: number
childAgentsExpanded?: boolean
onToggleChildAgents?: () => void
disclosureInGutter?: boolean
isFocusedPane?: boolean
hideIdentityIcon?: boolean
cacheTimerActive?: boolean
@@ -107,7 +97,6 @@ export const CompactAgentRow = React.memo(function CompactAgentRow({
childAgentCount,
childAgentsExpanded = false,
onToggleChildAgents,
disclosureInGutter = false,
isFocusedPane = false,
hideIdentityIcon = false,
cacheTimerActive = true,
@@ -183,43 +172,19 @@ export const CompactAgentRow = React.memo(function CompactAgentRow({
},
[agent.paneKey, onSendTargetClick, sendTargetStatus]
)
const handleToggleChildren = useCallback(
(e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
e.stopPropagation()
onToggleChildAgents?.()
},
[onToggleChildAgents]
)
const timestamp = shortTime ? (
<span
className={cn(
'shrink-0 text-[10px] tabular-nums',
isFocusedPane ? 'text-foreground/70' : 'text-muted-foreground/60'
)}
>
{shortTime}
</span>
) : null
const rowBody = (
<>
{hasChildDisclosure ? (
<button
type="button"
className="compact-agent-child-disclosure-button flex size-4 shrink-0 items-center justify-center rounded-sm text-muted-foreground hover:bg-worktree-sidebar-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-worktree-sidebar-ring"
aria-label={translate(
'auto.components.sidebar.worktree.card.compact.agents.a128d7006b',
'{{value0}} {{value1}} child {{value2}}',
{
value0: childAgentsExpanded ? 'Hide' : 'Show',
value1: childAgentCount,
value2: childAgentCount === 1 ? 'agent' : 'agents'
}
)}
aria-expanded={childAgentsExpanded}
onClick={handleToggleChildren}
onKeyDown={stopActivationKeyPropagation}
>
<ChevronRight
className={cn(
'size-3 transition-transform duration-150',
childAgentsExpanded && 'rotate-90'
)}
aria-hidden
/>
</button>
) : null}
{/* Why: the row's actionable disabled reason must win on every hit area. */}
<AgentStateDot
state={dotState}
@@ -275,16 +240,15 @@ export const CompactAgentRow = React.memo(function CompactAgentRow({
</span>
)}
{cacheTimer && <CacheTimer startedAt={cacheTimer.startedAt} ttlMs={cacheTimer.ttlMs} />}
{shortTime && (
<span
className={cn(
'shrink-0 text-[10px] tabular-nums',
// Why: the muted timestamp drops out against the selected-row fill.
isFocusedPane ? 'text-foreground/70' : 'text-muted-foreground/60'
)}
>
{shortTime}
</span>
{hasChildDisclosure ? (
<DashboardAgentChildDisclosure
childAgentCount={childAgentCount}
childAgentsExpanded={childAgentsExpanded}
onToggleChildAgents={onToggleChildAgents}
timestamp={timestamp}
/>
) : (
timestamp
)}
</>
)
@@ -293,11 +257,9 @@ export const CompactAgentRow = React.memo(function CompactAgentRow({
<div
draggable={false}
className={cn(
'compact-agent-row group/compact-agent-row min-w-0 overflow-hidden cursor-pointer rounded-sm px-1 text-[11px] leading-none',
'compact-agent-row agent-disclosure-row group/compact-agent-row min-w-0 cursor-pointer rounded-sm px-1 text-[11px] leading-none',
'text-muted-foreground worktree-agent-row-hover',
hasChildDisclosure && 'worktree-agent-lineage-parent-row',
// Why: hang the chevron in the card gutter so the state dot keeps the column of chevron-less rows.
hasChildDisclosure && disclosureInGutter && '-ml-5',
isLineageChild && 'worktree-agent-lineage-child-row',
'flex h-6 items-center gap-1',
isFocusedPane && 'bg-worktree-sidebar-accent',