From 3ce183a2290e93f21b1acf1685a2ede1cc96776d Mon Sep 17 00:00:00 2001 From: 777genius Date: Wed, 29 Apr 2026 20:55:40 +0300 Subject: [PATCH] fix(member-work-sync): pass codex turn settled env to mixed teams --- .../services/team/TeamProvisioningService.ts | 33 ++++++++++++++++++ .../TeamProvisioningServicePrepare.test.ts | 34 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 096cd4f5..1293c686 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -4447,6 +4447,25 @@ export class TeamProvisioningService { } } + private async buildRuntimeTurnSettledEnvironmentForMembers( + primaryProviderId: TeamProviderId | undefined, + memberSpecs: TeamCreateRequest['members'] + ): Promise> { + const resolvedPrimaryProviderId = resolveTeamProviderId(primaryProviderId); + const needsCodexTurnSettledEnv = memberSpecs.some((member) => { + const memberProviderId = resolveTeamProviderId( + normalizeTeamMemberProviderId(member.providerId) ?? resolvedPrimaryProviderId + ); + return memberProviderId === 'codex'; + }); + + if (!needsCodexTurnSettledEnv) { + return {}; + } + + return this.buildRuntimeTurnSettledEnvironment('codex'); + } + private async readRuntimeProviderLaunchFacts(params: { claudePath: string; cwd: string; @@ -12861,6 +12880,13 @@ export class TeamProvisioningService { leadProviderId: request.providerId, members: materializedMemberSpecs, }); + Object.assign( + shellEnv, + await this.buildRuntimeTurnSettledEnvironmentForMembers( + request.providerId, + allEffectiveMemberSpecs + ) + ); const lanePlan = this.planRuntimeLanesOrThrow(request.providerId, allEffectiveMemberSpecs); const primaryMemberNames = new Set(lanePlan.primaryMembers.map((member) => member.name)); const effectiveMemberSpecs = allEffectiveMemberSpecs.filter((member) => @@ -13916,6 +13942,13 @@ export class TeamProvisioningService { leadProviderId: request.providerId, members: materializedMemberSpecs, }); + Object.assign( + shellEnv, + await this.buildRuntimeTurnSettledEnvironmentForMembers( + request.providerId, + allEffectiveMemberSpecs + ) + ); const lanePlan = this.planRuntimeLanesOrThrow(request.providerId, allEffectiveMemberSpecs); const primaryMemberNames = new Set(lanePlan.primaryMembers.map((member) => member.name)); const effectiveMemberSpecs = allEffectiveMemberSpecs.filter((member) => diff --git a/test/main/services/team/TeamProvisioningServicePrepare.test.ts b/test/main/services/team/TeamProvisioningServicePrepare.test.ts index ec69b507..3631dfae 100644 --- a/test/main/services/team/TeamProvisioningServicePrepare.test.ts +++ b/test/main/services/team/TeamProvisioningServicePrepare.test.ts @@ -1970,6 +1970,40 @@ describe('TeamProvisioningService prepare/auth behavior', () => { expect(result.env.AGENT_TEAMS_RUNTIME_TURN_SETTLED_SPOOL_ROOT).toBe('/tmp/runtime-hooks'); }); + it('adds Codex turn-settled env when Codex is only a secondary member provider', async () => { + const svc = new TeamProvisioningService(); + svc.setRuntimeTurnSettledEnvironmentProvider(async ({ provider }) => + provider === 'codex' + ? { AGENT_TEAMS_RUNTIME_TURN_SETTLED_SPOOL_ROOT: '/tmp/runtime-hooks' } + : null + ); + + const result = await (svc as any).buildRuntimeTurnSettledEnvironmentForMembers('anthropic', [ + { name: 'alice', providerId: 'anthropic' }, + { name: 'jack', providerId: 'codex' }, + ]); + + expect(result).toEqual({ + AGENT_TEAMS_RUNTIME_TURN_SETTLED_SPOOL_ROOT: '/tmp/runtime-hooks', + }); + }); + + it('does not add Codex turn-settled env when no member uses Codex', async () => { + const svc = new TeamProvisioningService(); + const provider = vi.fn(async () => ({ + AGENT_TEAMS_RUNTIME_TURN_SETTLED_SPOOL_ROOT: '/tmp/runtime-hooks', + })); + svc.setRuntimeTurnSettledEnvironmentProvider(provider); + + const result = await (svc as any).buildRuntimeTurnSettledEnvironmentForMembers('anthropic', [ + { name: 'alice', providerId: 'anthropic' }, + { name: 'bob', providerId: 'gemini' }, + ]); + + expect(result).toEqual({}); + expect(provider).not.toHaveBeenCalled(); + }); + it('allows help-env resolution to continue even when provisioning env warns', async () => { const svc = new TeamProvisioningService(); vi.spyOn(svc as any, 'buildProvisioningEnv').mockResolvedValue({