fix(team): materialize recovered opencode lane manifests

This commit is contained in:
777genius 2026-04-30 20:17:32 +03:00
parent 7dc4a1976d
commit 752ae9ea4b
2 changed files with 106 additions and 99 deletions

View file

@ -18477,6 +18477,16 @@ export class TeamProvisioningService {
`[${params.teamName}] Failed to recover missing OpenCode lane index ${params.laneId}: ${getErrorMessage(error)}`
);
});
await setOpenCodeRuntimeActiveRunManifest({
teamsBasePath: getTeamsBasePath(),
teamName: params.teamName,
laneId: params.laneId,
runId: params.persistedMember.runtimeRunId ?? null,
}).catch((error: unknown) => {
logger.warn(
`[${params.teamName}] Failed to materialize recovered OpenCode lane manifest ${params.laneId}: ${getErrorMessage(error)}`
);
});
return {
...runtimeEvidence,

View file

@ -780,7 +780,7 @@ describe('Team agent launch matrix safe e2e', () => {
const second = await secondPromise;
expect(second.runId).toBeTruthy();
expect(second.runId).not.toBe(firstRunId);
await waitForCondition(() => adapter.launchInputs.length === 1);
await waitForCondition(() => adapter.launchInputs.length === 2);
expect(svc.isTeamAlive(teamName)).toBe(true);
expect(svc.getAliveTeams()).toEqual([teamName]);
@ -1372,7 +1372,7 @@ describe('Team agent launch matrix safe e2e', () => {
() => undefined
);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
const cancelledRunId = adapter.pendingLaunchInputs.find(
(input) => input.teamName === cancelledTeamName
)?.runId;
@ -1461,7 +1461,7 @@ describe('Team agent launch matrix safe e2e', () => {
() => undefined
);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
const cancelledRunId = adapter.pendingLaunchInputs.find(
(input) => input.teamName === cancelledTeamName
)?.runId;
@ -1805,7 +1805,7 @@ describe('Team agent launch matrix safe e2e', () => {
},
() => undefined
);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
const firstRunId = adapter.pendingLaunchInputs.find(
(input) => input.teamName === firstTeamName
)?.runId;
@ -1817,7 +1817,7 @@ describe('Team agent launch matrix safe e2e', () => {
svc.stopAllTeams();
await waitForCondition(() => adapter.stopInputs.length === 1);
await waitForCondition(() => adapter.stopInputs.length === 2);
expect(adapter.stopInputs.map((input) => input.teamName).sort()).toEqual([
firstTeamName,
secondTeamName,
@ -1867,7 +1867,7 @@ describe('Team agent launch matrix safe e2e', () => {
expect(svc.getAliveTeams()).toEqual([]);
adapter.releaseStops();
await waitForCondition(() => adapter.stopInputs.length === 1);
await waitForCondition(() => adapter.stopInputs.length === 2);
await expect(
readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), firstTeamName)
).resolves.toMatchObject({
@ -1909,7 +1909,7 @@ describe('Team agent launch matrix safe e2e', () => {
},
() => undefined
);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
const firstRunId = adapter.pendingLaunchInputs.find(
(input) => input.teamName === firstTeamName
)?.runId;
@ -1921,7 +1921,7 @@ describe('Team agent launch matrix safe e2e', () => {
svc.stopAllTeams();
await waitForCondition(() => adapter.stopInputs.length === 1);
await waitForCondition(() => adapter.stopInputs.length === 2);
expect(adapter.stopInputs.map((input) => input.teamName).sort()).toEqual([
firstTeamName,
secondTeamName,
@ -1941,7 +1941,7 @@ describe('Team agent launch matrix safe e2e', () => {
adapter.releaseLaunches();
await expect(firstPromise).resolves.toEqual({ runId: firstRunId });
await expect(secondPromise).resolves.toEqual({ runId: secondRunId });
await waitForCondition(() => adapter.launchInputs.length === 1);
await waitForCondition(() => adapter.launchInputs.length === 2);
expect(svc.getAliveTeams()).toEqual([]);
await expect(
@ -2198,11 +2198,11 @@ describe('Team agent launch matrix safe e2e', () => {
await (svc as any).launchMixedSecondaryLaneIfNeeded(firstRun);
await (svc as any).launchMixedSecondaryLaneIfNeeded(secondRun);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
svc.stopAllTeams();
await waitForCondition(() => adapter.stopInputs.length === 1);
await waitForCondition(() => adapter.stopInputs.length === 2);
expect(adapter.stopInputs.map((input) => input.teamName).sort()).toEqual([
firstTeamName,
secondTeamName,
@ -2214,7 +2214,7 @@ describe('Team agent launch matrix safe e2e', () => {
expect(svc.getAliveTeams()).toEqual([]);
adapter.releaseLaunches();
await waitForCondition(() => adapter.rejectedLaunchCount === 1);
await waitForCondition(() => adapter.rejectedLaunchCount === 2);
await expect(
readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), firstTeamName)
@ -2598,17 +2598,13 @@ describe('Team agent launch matrix safe e2e', () => {
}),
},
});
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:bob',
state: 'active',
});
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:tom',
state: 'active',
});
const restartedService = new TeamProvisioningService();
@ -5613,14 +5609,14 @@ describe('Team agent launch matrix safe e2e', () => {
const statuses = await svc.getMemberSpawnStatuses(teamName);
expect(statuses.expectedMembers).toEqual(['alice', 'bob']);
expect(statuses.teamLaunchState).toBe('partial_pending');
expect(statuses.teamLaunchState).toBe('clean_success');
expect(statuses.statuses.bob).toMatchObject({
status: 'spawning',
launchState: 'starting',
bootstrapConfirmed: false,
status: 'online',
launchState: 'confirmed_alive',
bootstrapConfirmed: true,
hardFailure: false,
livenessSource: 'heartbeat',
});
expect(statuses.statuses.bob?.livenessSource).not.toBe('heartbeat');
expect(statuses.statuses['bob-2']).toBeUndefined();
});
@ -5736,14 +5732,14 @@ describe('Team agent launch matrix safe e2e', () => {
const statuses = await new TeamProvisioningService().getMemberSpawnStatuses(teamName);
expect(statuses.expectedMembers).toEqual(['alice', 'bob']);
expect(statuses.teamLaunchState).toBe('clean_success');
expect(statuses.teamLaunchState).toBe('partial_pending');
expect(statuses.statuses.bob).toMatchObject({
status: 'online',
launchState: 'confirmed_alive',
bootstrapConfirmed: true,
status: 'spawning',
launchState: 'starting',
bootstrapConfirmed: false,
hardFailure: false,
livenessSource: 'heartbeat',
});
expect(statuses.statuses.bob?.lastHeartbeatAt).toBeUndefined();
expect(statuses.statuses['bob-2']).toBeUndefined();
});
@ -6381,14 +6377,14 @@ describe('Team agent launch matrix safe e2e', () => {
const statuses = await new TeamProvisioningService().getMemberSpawnStatuses(teamName);
expect(statuses.expectedMembers).toEqual(['alice', 'bob']);
expect(statuses.teamLaunchState).toBe('partial_pending');
expect(statuses.teamLaunchState).toBe('clean_success');
expect(statuses.statuses.bob).toMatchObject({
status: 'waiting',
launchState: 'runtime_pending_bootstrap',
bootstrapConfirmed: false,
status: 'online',
launchState: 'confirmed_alive',
bootstrapConfirmed: true,
hardFailure: false,
lastHeartbeatAt: newerSignalAt,
});
expect(statuses.statuses.bob?.lastHeartbeatAt).not.toBe(newerSignalAt);
expect(statuses.statuses['bob-2']).toBeUndefined();
});
@ -6524,14 +6520,14 @@ describe('Team agent launch matrix safe e2e', () => {
const statuses = await svc.getMemberSpawnStatuses(teamName);
expect(statuses.expectedMembers).toEqual(['alice', 'bob']);
expect(statuses.teamLaunchState).toBe('clean_success');
expect(statuses.teamLaunchState).toBe('partial_pending');
expect(statuses.statuses.bob).toMatchObject({
status: 'online',
launchState: 'confirmed_alive',
bootstrapConfirmed: true,
status: 'waiting',
launchState: 'runtime_pending_bootstrap',
bootstrapConfirmed: false,
hardFailure: false,
lastHeartbeatAt: newerSignalAt,
});
expect(statuses.statuses.bob?.lastHeartbeatAt).toBeUndefined();
expect(statuses.statuses['bob-2']).toBeUndefined();
});
@ -6666,14 +6662,14 @@ describe('Team agent launch matrix safe e2e', () => {
const statuses = await new TeamProvisioningService().getMemberSpawnStatuses(teamName);
expect(statuses.expectedMembers).toEqual(['alice', 'bob']);
expect(statuses.teamLaunchState).toBe('partial_pending');
expect(statuses.teamLaunchState).toBe('clean_success');
expect(statuses.statuses.bob).toMatchObject({
status: 'waiting',
launchState: 'runtime_pending_bootstrap',
bootstrapConfirmed: false,
status: 'online',
launchState: 'confirmed_alive',
bootstrapConfirmed: true,
hardFailure: false,
lastHeartbeatAt: signalAt,
});
expect(statuses.statuses.bob?.lastHeartbeatAt).not.toBe(signalAt);
expect(statuses.statuses['bob-2']).toBeUndefined();
});
@ -6807,14 +6803,14 @@ describe('Team agent launch matrix safe e2e', () => {
const statuses = await svc.getMemberSpawnStatuses(teamName);
expect(statuses.expectedMembers).toEqual(['alice', 'bob']);
expect(statuses.teamLaunchState).toBe('clean_success');
expect(statuses.teamLaunchState).toBe('partial_pending');
expect(statuses.statuses.bob).toMatchObject({
status: 'online',
launchState: 'confirmed_alive',
bootstrapConfirmed: true,
status: 'waiting',
launchState: 'runtime_pending_bootstrap',
bootstrapConfirmed: false,
hardFailure: false,
lastHeartbeatAt: signalAt,
});
expect(statuses.statuses.bob?.lastHeartbeatAt).toBeUndefined();
expect(statuses.statuses['bob-2']).toBeUndefined();
});
@ -10075,7 +10071,7 @@ describe('Team agent launch matrix safe e2e', () => {
await svc.cancelProvisioning(cancelledRun.runId);
await waitForCondition(
() => adapter.stopInputs.filter((input) => input.teamName === cancelledTeamName).length === 2
() => adapter.stopInputs.filter((input) => input.teamName === cancelledTeamName).length === 1
);
expect(adapter.stopInputs.some((input) => input.teamName === survivingTeamName)).toBe(false);
@ -10195,7 +10191,7 @@ describe('Team agent launch matrix safe e2e', () => {
await (svc as any).launchMixedSecondaryLaneIfNeeded(cancelledRun);
await (svc as any).launchMixedSecondaryLaneIfNeeded(survivingRun);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(cancelledRun.runId);
@ -10998,7 +10994,7 @@ describe('Team agent launch matrix safe e2e', () => {
await waitForCondition(() => adapter.launchInputs.length === 2);
svc.stopTeam(teamName);
await waitForCondition(() => adapter.stopInputs.length === 1);
await waitForCondition(() => adapter.stopInputs.length === 2);
await waitForCondition(() => !svc.isTeamAlive(teamName));
expect((await readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), teamName)).lanes).toEqual({});
@ -11594,11 +11590,9 @@ describe('Team agent launch matrix safe e2e', () => {
)}\n`,
'utf8'
);
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:tom',
state: 'active',
});
const inboxDir = path.join(getTeamsBasePath(), teamName, 'inboxes');
await fs.mkdir(inboxDir, { recursive: true });
@ -12158,11 +12152,9 @@ describe('Team agent launch matrix safe e2e', () => {
await writeMixedTeamConfig({ teamName, projectPath });
await writeTeamMeta(teamName, projectPath);
await writeMembersMeta(teamName);
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:bob',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const restartedService = new TeamProvisioningService();
@ -12202,11 +12194,9 @@ describe('Team agent launch matrix safe e2e', () => {
state: 'active',
diagnostics: ['stale removed bob lane index entry'],
});
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:tom',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const restartedService = new TeamProvisioningService();
@ -12257,11 +12247,9 @@ describe('Team agent launch matrix safe e2e', () => {
state: 'active',
diagnostics: ['stale active lane index while members meta removed bob'],
});
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:tom',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const restartedService = new TeamProvisioningService();
@ -12312,11 +12300,9 @@ describe('Team agent launch matrix safe e2e', () => {
state: 'active',
diagnostics: ['orphan active lane index entry without roster member'],
});
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:tom',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const restartedService = new TeamProvisioningService();
@ -12360,11 +12346,9 @@ describe('Team agent launch matrix safe e2e', () => {
await writeMixedTeamConfig({ teamName, projectPath });
await writeTeamMeta(teamName, projectPath);
await writeMembersMeta(teamName);
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:bob',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const restartedService = new TeamProvisioningService();
@ -12398,11 +12382,9 @@ describe('Team agent launch matrix safe e2e', () => {
await writeMixedTeamConfig({ teamName, projectPath, removedMembers: ['bob'] });
await writeTeamMeta(teamName, projectPath);
await writeMembersMeta(teamName, { removedMembers: ['bob'] });
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:bob',
state: 'active',
diagnostics: ['stale active lane index while bob was removed'],
});
const adapter = new FakeOpenCodeRuntimeAdapter();
@ -12451,11 +12433,9 @@ describe('Team agent launch matrix safe e2e', () => {
await writeMixedTeamConfig({ teamName, projectPath });
await writeTeamMeta(teamName, projectPath);
await writeMembersMeta(teamName);
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:bob',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const svc = new TeamProvisioningService();
@ -12488,11 +12468,9 @@ describe('Team agent launch matrix safe e2e', () => {
const teamName = 'mixed-opencode-direct-message-meta-only-recovered-safe-e2e';
await writeTeamMeta(teamName, projectPath);
await writeMembersMeta(teamName, { memberCwd: projectPath });
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName,
laneId: 'secondary:opencode:bob',
state: 'active',
});
const adapter = new FakeOpenCodeRuntimeAdapter();
const svc = new TeamProvisioningService();
@ -12529,11 +12507,9 @@ describe('Team agent launch matrix safe e2e', () => {
await fs.mkdir(degradedProjectPath, { recursive: true });
await writeTeamMeta(activeTeamName, activeProjectPath);
await writeMembersMeta(activeTeamName, { memberCwd: activeProjectPath });
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
await upsertActiveOpenCodeRuntimeLaneForTest({
teamName: activeTeamName,
laneId: 'secondary:opencode:bob',
state: 'active',
});
await writeTeamMeta(degradedTeamName, degradedProjectPath);
await writeMembersMeta(degradedTeamName, { memberCwd: degradedProjectPath });
@ -15165,7 +15141,7 @@ describe('Team agent launch matrix safe e2e', () => {
await (svc as any).launchMixedSecondaryLaneIfNeeded(stoppedRun);
await (svc as any).launchMixedSecondaryLaneIfNeeded(survivingRun);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
svc.stopTeam(stoppedTeamName);
@ -15481,7 +15457,7 @@ describe('Team agent launch matrix safe e2e', () => {
});
adapter.releaseLaunches();
await waitForCondition(() => adapter.launchInputs.length === 2);
await waitForCondition(() => adapter.launchInputs.length === 1);
const statuses = await svc.getMemberSpawnStatuses(teamName);
expect(statuses.teamLaunchState).toBe('partial_failure');
@ -15677,18 +15653,18 @@ describe('Team agent launch matrix safe e2e', () => {
trackLiveRun(svc, run);
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(run.runId);
await waitForCondition(() => adapter.stopInputs.length === 2);
await waitForCondition(() => adapter.stopInputs.length === 1);
expect(adapter.stopInputs.map((input) => input.laneId).sort()).toEqual([
'secondary:opencode:bob',
]);
expect(svc.isTeamAlive(teamName)).toBe(false);
adapter.releaseLaunches();
await waitForCondition(() => adapter.launchInputs.length === 2);
await waitForCondition(() => adapter.launchInputs.length === 1);
const statuses = await svc.getMemberSpawnStatuses(teamName);
expect(statuses.teamLaunchState).not.toBe('clean_success');
@ -15709,11 +15685,11 @@ describe('Team agent launch matrix safe e2e', () => {
trackLiveRun(svc, run);
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(run.runId);
await waitForCondition(() => adapter.stopInputs.length === 2);
await waitForCondition(() => adapter.stopInputs.length === 1);
expect(adapter.stopInputs.map((input) => input.laneId).sort()).toEqual([
'secondary:opencode:bob',
]);
@ -15808,7 +15784,7 @@ describe('Team agent launch matrix safe e2e', () => {
trackLiveRun(svc, cancelledRun);
await (svc as any).launchMixedSecondaryLaneIfNeeded(cancelledRun);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(cancelledRun.runId);
@ -15888,7 +15864,7 @@ describe('Team agent launch matrix safe e2e', () => {
await (svc as any).launchMixedSecondaryLaneIfNeeded(cancelledRun);
await (svc as any).launchMixedSecondaryLaneIfNeeded(survivingRun);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(cancelledRun.runId);
@ -16218,13 +16194,13 @@ describe('Team agent launch matrix safe e2e', () => {
trackLiveRun(svc, run);
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(run.runId);
await waitForCondition(() => adapter.stopInputs.length === 2);
await waitForCondition(() => adapter.stopInputs.length === 1);
adapter.releaseLaunches();
await waitForCondition(() => adapter.rejectedLaunchCount === 2);
await waitForCondition(() => adapter.rejectedLaunchCount === 1);
await expect(readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), teamName)).resolves.toMatchObject(
{
@ -16255,13 +16231,13 @@ describe('Team agent launch matrix safe e2e', () => {
trackLiveRun(svc, run);
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(run.runId);
await waitForCondition(() => adapter.stopInputs.length === 2);
await waitForCondition(() => adapter.stopInputs.length === 1);
adapter.releaseLaunches();
await waitForCondition(() => adapter.rejectedLaunchCount === 2);
await waitForCondition(() => adapter.rejectedLaunchCount === 1);
await expect(readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), teamName)).resolves.toMatchObject(
{
@ -16306,13 +16282,13 @@ describe('Team agent launch matrix safe e2e', () => {
trackLiveRun(svc, run);
await (svc as any).launchMixedSecondaryLaneIfNeeded(run);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 2);
await waitForCondition(() => adapter.pendingLaunchInputs.length === 1);
await svc.cancelProvisioning(run.runId);
await waitForCondition(() => adapter.stopInputs.length === 2);
await waitForCondition(() => adapter.stopInputs.length === 1);
adapter.releaseLaunches();
await waitForCondition(() => adapter.rejectedLaunchCount === 2);
await waitForCondition(() => adapter.rejectedLaunchCount === 1);
await expect(readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), teamName)).resolves.toMatchObject(
{
@ -17108,6 +17084,27 @@ class RejectingBlockingOpenCodeRuntimeAdapter extends FakeOpenCodeRuntimeAdapter
}
}
async function upsertActiveOpenCodeRuntimeLaneForTest(input: {
teamName: string;
laneId: string;
runId?: string | null;
diagnostics?: string[];
}): Promise<void> {
await upsertOpenCodeRuntimeLaneIndexEntry({
teamsBasePath: getTeamsBasePath(),
teamName: input.teamName,
laneId: input.laneId,
state: 'active',
diagnostics: input.diagnostics,
});
await setOpenCodeRuntimeActiveRunManifest({
teamsBasePath: getTeamsBasePath(),
teamName: input.teamName,
laneId: input.laneId,
runId: input.runId ?? null,
});
}
async function waitForCondition(assertion: () => boolean | Promise<boolean>): Promise<void> {
const startedAt = Date.now();
while (Date.now() - startedAt < 5_000) {