From 560e14d5ad8881ea05772ef29573b893ecb9e242 Mon Sep 17 00:00:00 2001 From: 777genius Date: Thu, 23 Apr 2026 04:20:01 +0300 Subject: [PATCH] fix(team): include richer launch members in runtime snapshot --- .../services/team/TeamProvisioningService.ts | 4 +- .../team/TeamProvisioningService.test.ts | 50 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 59e3ae85..cb5f8494 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -6273,7 +6273,9 @@ export class TeamProvisioningService { if (!memberName || member.removedAt || candidateMembers.has(memberName)) continue; candidateMembers.set(memberName, member); } - for (const memberName of launchSnapshot?.expectedMembers ?? []) { + for (const memberName of launchSnapshot + ? this.getPersistedLaunchMemberNames(launchSnapshot) + : []) { if (candidateMembers.has(memberName) || this.isMemberRemovedInMeta(metaMembers, memberName)) { continue; } diff --git a/test/main/services/team/TeamProvisioningService.test.ts b/test/main/services/team/TeamProvisioningService.test.ts index bf81dac6..f8fc404d 100644 --- a/test/main/services/team/TeamProvisioningService.test.ts +++ b/test/main/services/team/TeamProvisioningService.test.ts @@ -943,6 +943,56 @@ describe('TeamProvisioningService', () => { expect(snapshot.members.alice).toBeUndefined(); }); + it('includes persisted launch members that only exist in launchSnapshot.members when expectedMembers is stale', async () => { + const svc = new TeamProvisioningService(); + (svc as any).configReader = { + getConfig: vi.fn(async () => ({ + members: [{ name: 'team-lead', agentType: 'team-lead' }], + })), + }; + (svc as any).membersMetaStore = { + getMembers: vi.fn(async () => []), + }; + (svc as any).teamMetaStore = { + getMeta: vi.fn(async () => null), + }; + (svc as any).launchStateStore = { + read: vi.fn(async () => + createPersistedLaunchSnapshot({ + teamName: 'runtime-team', + leadSessionId: 'lead-session', + launchPhase: 'active', + expectedMembers: ['alice'], + members: { + bob: { + name: 'bob', + providerId: 'codex', + providerBackendId: 'codex-native', + model: 'gpt-5.4-mini', + effort: 'high', + launchState: 'runtime_pending_bootstrap', + agentToolAccepted: true, + runtimeAlive: false, + bootstrapConfirmed: false, + hardFailure: false, + lastEvaluatedAt: '2026-04-23T10:00:00.000Z', + }, + }, + updatedAt: '2026-04-23T10:00:00.000Z', + }) + ), + }; + vi.mocked(pidusage).mockResolvedValueOnce({} as any); + + const snapshot = await svc.getTeamAgentRuntimeSnapshot('runtime-team'); + + expect(snapshot.members.bob).toMatchObject({ + memberName: 'bob', + runtimeModel: 'gpt-5.4-mini', + providerBackendId: 'codex-native', + }); + }); + it('shows RSS for OpenCode secondary lanes through the shared runtime host without exposing a member pid', async () => { const svc = new TeamProvisioningService(); (svc as any).configReader = {