fix(status-bar): preserve workspace-space review and agent freshness

This commit is contained in:
Neil
2026-08-31 02:49:24 -07:00
parent 4d6aa240ed
commit 6f47695573
3 changed files with 48 additions and 10 deletions
@@ -1,5 +1,5 @@
import { useCallback, useMemo } from 'react'
import { useNow } from '@/hooks/use-now'
import { getAgentStatusEpochNow } from '@/lib/agent-status-epoch-clock'
import {
getWorkspaceDecisionDetails,
type WorkspaceDecisionDetails
@@ -40,7 +40,6 @@ export function useWorkspaceSpaceDecisionProjection(bindings: WorkspaceSpaceMana
} = bindings
const sourceRows = useMemo(() => analysis?.worktrees ?? [], [analysis?.worktrees])
const now = useNow(30_000)
const worktreeIdCounts = useMemo(() => {
const counts = new Map<string, number>()
for (const row of sourceRows) {
@@ -49,9 +48,9 @@ export function useWorkspaceSpaceDecisionProjection(bindings: WorkspaceSpaceMana
return counts
}, [sourceRows])
const decisionDetailsByWorktreeId = useMemo(() => {
// Why: active-agent freshness is time-based. The epoch bumps when fresh
// hook entries cross the stale boundary so delete readiness recomputes.
void agentStatusEpoch
// Why: the epoch bumps when fresh hook entries cross the stale boundary so
// delete readiness recomputes with the same wall-clock sample as the store.
const agentStatusNow = getAgentStatusEpochNow(agentStatusEpoch)
const details = new Map<string, WorkspaceDecisionDetails>()
for (const worktree of sourceRows) {
details.set(
@@ -78,7 +77,7 @@ export function useWorkspaceSpaceDecisionProjection(bindings: WorkspaceSpaceMana
settings,
activeWorktreeId,
activeWorkspaceExecutionHostId,
now
now: agentStatusNow
})
)
}
@@ -106,8 +105,7 @@ export function useWorkspaceSpaceDecisionProjection(bindings: WorkspaceSpaceMana
settings,
sourceRows,
tabsByWorktree,
worktreeMap,
now
worktreeMap
])
const getDeleteStateForWorktree = useCallback(
(worktree: WorkspaceSpaceWorktree) =>
@@ -3,9 +3,11 @@ import type {
MigrationUnsupportedPtyEntry
} from '../../../../shared/agent-status-types'
import type { ExecutionHostId } from '../../../../shared/execution-host'
import type { HostedReviewProvider } from '../../../../shared/hosted-review'
import type { Repo } from '../../../../shared/repo-types'
import type { TerminalTab } from '../../../../shared/terminal-tab-types'
import type { Worktree } from '../../../../shared/worktree/types'
import { isGitHubPRSuppressed } from '../../../../shared/worktree/github-pr-suppression'
import type { WorkspaceSpaceWorktree } from '../../../../shared/workspace-space-types'
import { branchDisplayName } from '../sidebar/WorktreeCardHelpers'
import { findRepoForHost } from '../../store/slices/repo-host-identity'
@@ -50,7 +52,15 @@ export type WorkspaceDecisionInputs = {
remoteStatusesByWorktree: Record<string, { hasUpstream: boolean; ahead: number; behind: number }>
hostedReviewCache: Record<
string,
{ data?: { number: number; state: string; status: string; title: string } | null }
{
data?: {
number: number
state: string
status: string
title: string
provider?: HostedReviewProvider
} | null
}
>
issueCache: Record<string, { data?: { number: number; title: string; state: string } | null }>
linearIssueCache: Record<
@@ -129,7 +139,13 @@ export function getWorkspaceDecisionDetails(
ownerExecutionHostId,
repo !== null && repo !== undefined
)
const hostedReview = inputs.hostedReviewCache[reviewCacheKey]?.data
const cachedHostedReview = inputs.hostedReviewCache[reviewCacheKey]?.data
const hostedReview =
cachedHostedReview?.provider === 'github' &&
workspaceRecord &&
isGitHubPRSuppressed(workspaceRecord, cachedHostedReview.number)
? null
: cachedHostedReview
const linkedPR = workspaceRecord?.linkedPR ?? null
const reviewLabel =
hostedReview !== undefined && hostedReview !== null
@@ -428,6 +428,30 @@ describe('workspace space presentation helpers', () => {
expect(details.issueLabel).toBe('#123 open: Local owner issue')
})
it('hides a GitHub review explicitly suppressed after unlinking', () => {
const details = getWorkspaceDecisionDetails(
row({ branch: 'refs/heads/feature/local' }),
decisionInputs({
hostedReviewCache: {
'local::repo::feature/local': {
data: {
number: 12,
state: 'open',
status: 'success',
title: 'Suppressed review',
provider: 'github'
}
}
},
worktreeMap: new Map([
['wt', worktreeRecord({ branch: 'refs/heads/feature/local', suppressedGitHubPR: 12 })]
])
})
)
expect(details.reviewLabel).toBeNull()
})
it('counts migration-unsupported agent entries by worktree id', () => {
const count = countWorkspaceSpaceActiveAgents({
worktreeId: 'wt',