fix(team): treat online teammates as ready state
This commit is contained in:
parent
340e4d8c8b
commit
8ebde439a8
4 changed files with 76 additions and 10 deletions
|
|
@ -8995,8 +8995,12 @@ export class TeamProvisioningService {
|
||||||
const failedSpawnMembers = this.getFailedSpawnMembers(run);
|
const failedSpawnMembers = this.getFailedSpawnMembers(run);
|
||||||
const launchSummary = this.getMemberLaunchSummary(run);
|
const launchSummary = this.getMemberLaunchSummary(run);
|
||||||
const hasSpawnFailures = failedSpawnMembers.length > 0;
|
const hasSpawnFailures = failedSpawnMembers.length > 0;
|
||||||
|
const stillStartingCount = Math.max(
|
||||||
|
0,
|
||||||
|
launchSummary.pendingCount - launchSummary.runtimeAlivePendingCount
|
||||||
|
);
|
||||||
const hasPendingBootstrap =
|
const hasPendingBootstrap =
|
||||||
!hasSpawnFailures && launchSummary.pendingCount > 0 && run.expectedMembers.length > 0;
|
!hasSpawnFailures && stillStartingCount > 0 && run.expectedMembers.length > 0;
|
||||||
const readyMessage = hasSpawnFailures
|
const readyMessage = hasSpawnFailures
|
||||||
? `Launch completed with teammate errors — ${failedSpawnMembers
|
? `Launch completed with teammate errors — ${failedSpawnMembers
|
||||||
.map((member) => member.name)
|
.map((member) => member.name)
|
||||||
|
|
@ -9155,8 +9159,12 @@ export class TeamProvisioningService {
|
||||||
const failedSpawnMembers = this.getFailedSpawnMembers(run);
|
const failedSpawnMembers = this.getFailedSpawnMembers(run);
|
||||||
const launchSummary = this.getMemberLaunchSummary(run);
|
const launchSummary = this.getMemberLaunchSummary(run);
|
||||||
const hasSpawnFailures = failedSpawnMembers.length > 0;
|
const hasSpawnFailures = failedSpawnMembers.length > 0;
|
||||||
|
const stillStartingCount = Math.max(
|
||||||
|
0,
|
||||||
|
launchSummary.pendingCount - launchSummary.runtimeAlivePendingCount
|
||||||
|
);
|
||||||
const hasPendingBootstrap =
|
const hasPendingBootstrap =
|
||||||
!hasSpawnFailures && launchSummary.pendingCount > 0 && run.expectedMembers.length > 0;
|
!hasSpawnFailures && stillStartingCount > 0 && run.expectedMembers.length > 0;
|
||||||
const progress = updateProgress(
|
const progress = updateProgress(
|
||||||
run,
|
run,
|
||||||
'ready',
|
'ready',
|
||||||
|
|
|
||||||
|
|
@ -159,9 +159,7 @@ export const TeamProvisioningBanner = ({
|
||||||
? `Team provisioned — ${heartbeatConfirmedCount}/${fallbackTeammateCount} teammates made contact${processOnlyAliveCount > 0 ? `, ${processOnlyAliveCount} teammate${processOnlyAliveCount === 1 ? '' : 's'} online` : ''}${pendingSpawnCount > 0 ? `${processOnlyAliveCount > 0 ? ', ' : ', '}${pendingSpawnCount} still starting` : ''}`
|
? `Team provisioned — ${heartbeatConfirmedCount}/${fallbackTeammateCount} teammates made contact${processOnlyAliveCount > 0 ? `, ${processOnlyAliveCount} teammate${processOnlyAliveCount === 1 ? '' : 's'} online` : ''}${pendingSpawnCount > 0 ? `${processOnlyAliveCount > 0 ? ', ' : ', '}${pendingSpawnCount} still starting` : ''}`
|
||||||
: 'Team provisioned — teammates are still starting';
|
: 'Team provisioned — teammates are still starting';
|
||||||
const readyDetailSeverity =
|
const readyDetailSeverity =
|
||||||
failedSpawnCount > 0 || processOnlyAliveCount > 0 || pendingSpawnCount > 0
|
failedSpawnCount > 0 || pendingSpawnCount > 0 ? 'warning' : undefined;
|
||||||
? 'warning'
|
|
||||||
: undefined;
|
|
||||||
const readyMessage =
|
const readyMessage =
|
||||||
failedSpawnCount > 0
|
failedSpawnCount > 0
|
||||||
? `Launch finished with errors — ${failedSpawnCount}/${Math.max(fallbackTeammateCount, failedSpawnCount)} teammates failed to start`
|
? `Launch finished with errors — ${failedSpawnCount}/${Math.max(fallbackTeammateCount, failedSpawnCount)} teammates failed to start`
|
||||||
|
|
@ -191,9 +189,7 @@ export const TeamProvisioningBanner = ({
|
||||||
onCancel={null}
|
onCancel={null}
|
||||||
successMessage={readyMessage}
|
successMessage={readyMessage}
|
||||||
successMessageSeverity={
|
successMessageSeverity={
|
||||||
failedSpawnCount > 0 || processOnlyAliveCount > 0 || pendingSpawnCount > 0
|
failedSpawnCount > 0 || pendingSpawnCount > 0 ? 'warning' : 'success'
|
||||||
? 'warning'
|
|
||||||
: 'success'
|
|
||||||
}
|
}
|
||||||
onDismiss={() => setDismissed(true)}
|
onDismiss={() => setDismissed(true)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ export const SPAWN_DOT_COLORS: Record<MemberSpawnStatus, string> = {
|
||||||
|
|
||||||
export const SPAWN_PRESENCE_LABELS: Record<MemberSpawnStatus, string> = {
|
export const SPAWN_PRESENCE_LABELS: Record<MemberSpawnStatus, string> = {
|
||||||
offline: 'offline',
|
offline: 'offline',
|
||||||
waiting: 'online',
|
waiting: 'starting',
|
||||||
spawning: 'starting',
|
spawning: 'starting',
|
||||||
online: 'ready',
|
online: 'ready',
|
||||||
error: 'spawn failed',
|
error: 'spawn failed',
|
||||||
|
|
@ -123,7 +123,7 @@ export function getSpawnAwareDotClass(
|
||||||
return SPAWN_DOT_COLORS.error;
|
return SPAWN_DOT_COLORS.error;
|
||||||
}
|
}
|
||||||
if (spawnLaunchState === 'runtime_pending_bootstrap' && spawnStatus === 'online') {
|
if (spawnLaunchState === 'runtime_pending_bootstrap' && spawnStatus === 'online') {
|
||||||
return SPAWN_DOT_COLORS.spawning;
|
return SPAWN_DOT_COLORS.online;
|
||||||
}
|
}
|
||||||
if (spawnStatus === 'waiting') {
|
if (spawnStatus === 'waiting') {
|
||||||
return SPAWN_DOT_COLORS.waiting;
|
return SPAWN_DOT_COLORS.waiting;
|
||||||
|
|
|
||||||
62
test/renderer/utils/memberHelpers.test.ts
Normal file
62
test/renderer/utils/memberHelpers.test.ts
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
import {
|
||||||
|
getSpawnAwareDotClass,
|
||||||
|
getSpawnAwarePresenceLabel,
|
||||||
|
} from '@renderer/utils/memberHelpers';
|
||||||
|
|
||||||
|
import type { ResolvedTeamMember } from '@shared/types';
|
||||||
|
|
||||||
|
const member: ResolvedTeamMember = {
|
||||||
|
name: 'alice',
|
||||||
|
status: 'unknown',
|
||||||
|
taskCount: 0,
|
||||||
|
currentTaskId: null,
|
||||||
|
lastActiveAt: null,
|
||||||
|
messageCount: 0,
|
||||||
|
color: 'blue',
|
||||||
|
agentType: 'reviewer',
|
||||||
|
role: 'Reviewer',
|
||||||
|
removedAt: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('memberHelpers spawn-aware presence', () => {
|
||||||
|
it('shows process-online teammates as online with a green dot', () => {
|
||||||
|
expect(
|
||||||
|
getSpawnAwarePresenceLabel(
|
||||||
|
member,
|
||||||
|
'online',
|
||||||
|
'runtime_pending_bootstrap',
|
||||||
|
'process',
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
).toBe('online');
|
||||||
|
|
||||||
|
expect(
|
||||||
|
getSpawnAwareDotClass(
|
||||||
|
member,
|
||||||
|
'online',
|
||||||
|
'runtime_pending_bootstrap',
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
).toContain('bg-emerald-400');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps accepted-but-not-yet-online teammates in starting state', () => {
|
||||||
|
expect(
|
||||||
|
getSpawnAwarePresenceLabel(
|
||||||
|
member,
|
||||||
|
'waiting',
|
||||||
|
'starting',
|
||||||
|
undefined,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
undefined
|
||||||
|
)
|
||||||
|
).toBe('starting');
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue