From 776957b6076f250d371277aabbee7a1f1a097d50 Mon Sep 17 00:00:00 2001 From: 777genius Date: Sun, 24 May 2026 20:43:11 +0300 Subject: [PATCH] fix(team): keep runtime adapter lead activity idle --- .../services/team/TeamProvisioningService.ts | 13 +++- .../team/TeamProvisioningService.test.ts | 59 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/main/services/team/TeamProvisioningService.ts b/src/main/services/team/TeamProvisioningService.ts index 76dc33f9..e3838b26 100644 --- a/src/main/services/team/TeamProvisioningService.ts +++ b/src/main/services/team/TeamProvisioningService.ts @@ -12168,7 +12168,18 @@ export class TeamProvisioningService { const runId = this.getTrackedRunId(teamName); if (!runId) return { state: 'offline', runId: null }; const run = this.runs.get(runId); - if (!run || run.processKilled || run.cancelRequested) return { state: 'offline', runId: null }; + if (!run) { + const runtimeAdapterRun = this.runtimeAdapterRunByTeam.get(teamName); + const runtimeProgress = this.runtimeAdapterProgressByRunId.get(runId); + if ( + runtimeAdapterRun?.runId === runId && + !['cancelled', 'disconnected', 'failed'].includes(runtimeProgress?.state ?? '') + ) { + return { state: 'idle', runId }; + } + return { state: 'offline', runId: null }; + } + if (run.processKilled || run.cancelRequested) return { state: 'offline', runId: null }; // Read-repair active lead task intervals for runs that were already active // before interval tracking was introduced or before the renderer polled state. this.syncLeadTaskActivityForState(run, run.leadActivityState, run.leadActivityState); diff --git a/test/main/services/team/TeamProvisioningService.test.ts b/test/main/services/team/TeamProvisioningService.test.ts index 91dfd4dd..17180495 100644 --- a/test/main/services/team/TeamProvisioningService.test.ts +++ b/test/main/services/team/TeamProvisioningService.test.ts @@ -679,6 +679,8 @@ interface LeadActivityTestRun { interface LeadActivityServiceInternals { runs: Map; aliveRunByTeam: Map; + runtimeAdapterProgressByRunId: Map; + runtimeAdapterRunByTeam: Map; setLeadActivity(run: LeadActivityTestRun, state: LeadActivityTestState): void; } @@ -2511,6 +2513,63 @@ describe('TeamProvisioningService', () => { }); describe('lead activity task intervals', () => { + it('reports runtime adapter teams as idle instead of offline when no legacy run exists', () => { + const svc = new TeamProvisioningService(); + const internals = svc as unknown as LeadActivityServiceInternals; + const teamName = 'opencode-runtime-adapter-lead-activity-team'; + const runId = 'opencode-runtime-adapter-run'; + + internals.aliveRunByTeam.set(teamName, runId); + internals.runtimeAdapterRunByTeam.set(teamName, { + runId, + providerId: 'opencode', + cwd: '/tmp/opencode-runtime-adapter-lead-activity-team', + members: {}, + }); + internals.runtimeAdapterProgressByRunId.set(runId, { + runId, + teamName, + state: 'ready', + message: 'OpenCode team launch is waiting for runtime evidence or permissions', + startedAt: '2026-05-02T10:00:00.000Z', + updatedAt: '2026-05-02T10:00:05.000Z', + }); + + expect(svc.isTeamAlive(teamName)).toBe(true); + expect(svc.getLeadActivityState(teamName)).toEqual({ + state: 'idle', + runId, + }); + }); + + it('keeps terminal runtime adapter progress offline without a legacy run', () => { + const svc = new TeamProvisioningService(); + const internals = svc as unknown as LeadActivityServiceInternals; + const teamName = 'opencode-runtime-adapter-terminal-lead-activity-team'; + const runId = 'opencode-runtime-adapter-terminal-run'; + + internals.aliveRunByTeam.set(teamName, runId); + internals.runtimeAdapterRunByTeam.set(teamName, { + runId, + providerId: 'opencode', + cwd: '/tmp/opencode-runtime-adapter-terminal-lead-activity-team', + members: {}, + }); + internals.runtimeAdapterProgressByRunId.set(runId, { + runId, + teamName, + state: 'failed', + message: 'OpenCode team launch failed readiness gate', + startedAt: '2026-05-02T10:00:00.000Z', + updatedAt: '2026-05-02T10:00:05.000Z', + }); + + expect(svc.getLeadActivityState(teamName)).toEqual({ + state: 'offline', + runId: null, + }); + }); + it('read-repairs active lead task intervals once when lead activity is polled', () => { vi.useFakeTimers(); vi.setSystemTime(new Date('2026-05-02T10:00:00.000Z'));