diff --git a/src/renderer/utils/teamProvisioningPresentation.ts b/src/renderer/utils/teamProvisioningPresentation.ts index 48edf876..fd01934c 100644 --- a/src/renderer/utils/teamProvisioningPresentation.ts +++ b/src/renderer/utils/teamProvisioningPresentation.ts @@ -41,7 +41,11 @@ function countPermissionBlockedMembers(memberSpawnStatuses: MemberSpawnStatusCol ? [...memberSpawnStatuses.values()] : Object.values(memberSpawnStatuses); - return entries.filter((entry) => entry.launchState === 'runtime_pending_permission').length; + return entries.filter( + (entry) => + entry.launchState === 'runtime_pending_permission' || + (entry.pendingPermissionRequestIds?.length ?? 0) > 0 + ).length; } function buildAwaitingPermissionPhrase(count: number): string { diff --git a/test/renderer/utils/teamProvisioningPresentation.test.ts b/test/renderer/utils/teamProvisioningPresentation.test.ts index e2f1c33a..349a244c 100644 --- a/test/renderer/utils/teamProvisioningPresentation.test.ts +++ b/test/renderer/utils/teamProvisioningPresentation.test.ts @@ -397,6 +397,69 @@ describe('buildTeamProvisioningPresentation', () => { expect(presentation?.panelMessage).toBe('1 teammate awaiting permission approval'); }); + it('trusts pending permission request ids even before launchState flips to runtime_pending_permission', () => { + const presentation = buildTeamProvisioningPresentation({ + progress: { + runId: 'run-4e', + teamName: 'opencode-team', + state: 'finalizing', + startedAt: '2026-04-13T10:00:00.000Z', + updatedAt: '2026-04-13T10:00:08.000Z', + message: 'Waiting for runtime confirmation', + messageSeverity: undefined, + pid: 4321, + cliLogsTail: '', + assistantOutput: '', + }, + members: [ + { + name: 'team-lead', + agentType: 'team-lead', + status: 'active', + currentTaskId: null, + taskCount: 0, + lastActiveAt: null, + messageCount: 0, + }, + { + name: 'bob', + agentType: 'engineer', + status: 'unknown', + currentTaskId: null, + taskCount: 0, + lastActiveAt: null, + messageCount: 0, + }, + ], + memberSpawnStatuses: { + bob: { + status: 'online', + launchState: 'runtime_pending_bootstrap', + updatedAt: '2026-04-13T10:00:07.000Z', + runtimeAlive: true, + livenessSource: 'process', + bootstrapConfirmed: false, + hardFailure: false, + agentToolAccepted: true, + pendingPermissionRequestIds: ['perm_1'], + firstSpawnAcceptedAt: '2026-04-13T10:00:01.000Z', + }, + }, + memberSpawnSnapshot: { + expectedMembers: ['bob'], + summary: { + confirmedCount: 0, + pendingCount: 1, + failedCount: 0, + runtimeAlivePendingCount: 1, + }, + }, + }); + + expect(presentation?.compactDetail).toBe('1 teammate awaiting permission approval'); + expect(presentation?.panelMessage).toBe('1 teammate awaiting permission approval'); + }); + it('keeps a generic failed teammate message while launch is still active if only persisted failure counts remain', () => { const presentation = buildTeamProvisioningPresentation({ progress: {