fix(team): preserve launch error and permission details
This commit is contained in:
parent
65fa117626
commit
3e53391a73
5 changed files with 75 additions and 0 deletions
|
|
@ -63,6 +63,7 @@ export interface OpenCodeLaunchTeamCommandBody {
|
|||
export interface OpenCodeTeamMemberLaunchCommandData {
|
||||
sessionId: string;
|
||||
launchState: OpenCodeTeamMemberLaunchBridgeState;
|
||||
pendingPermissionRequestIds?: string[];
|
||||
model: string;
|
||||
runtimePid?: number;
|
||||
evidence: Array<{ kind: string; observedAt: string }>;
|
||||
|
|
|
|||
|
|
@ -385,6 +385,7 @@ function mapOpenCodeLaunchDataToRuntimeResult(
|
|||
fallbackLaunchState,
|
||||
bridgeMember?.sessionId,
|
||||
bridgeMember?.runtimePid,
|
||||
bridgeMember?.pendingPermissionRequestIds,
|
||||
bridgeMember != null,
|
||||
[
|
||||
...(bridgeMember
|
||||
|
|
@ -426,6 +427,7 @@ function mapBridgeMemberToRuntimeEvidence(
|
|||
launchState: OpenCodeTeamMemberLaunchBridgeState,
|
||||
sessionId: string | undefined,
|
||||
runtimePid: number | undefined,
|
||||
pendingPermissionRequestIds: string[] | undefined,
|
||||
runtimeMaterialized: boolean,
|
||||
diagnostics: string[]
|
||||
): TeamRuntimeMemberLaunchEvidence {
|
||||
|
|
@ -448,6 +450,10 @@ function mapBridgeMemberToRuntimeEvidence(
|
|||
bootstrapConfirmed: confirmed,
|
||||
hardFailure: failed,
|
||||
hardFailureReason: failed ? 'OpenCode bridge reported member launch failure' : undefined,
|
||||
pendingPermissionRequestIds:
|
||||
pendingPermissionRequestIds && pendingPermissionRequestIds.length > 0
|
||||
? [...new Set(pendingPermissionRequestIds)]
|
||||
: undefined,
|
||||
sessionId,
|
||||
...(typeof runtimePid === 'number' && Number.isFinite(runtimePid) && runtimePid > 0
|
||||
? { runtimePid }
|
||||
|
|
|
|||
|
|
@ -733,6 +733,7 @@ function areMemberSpawnStatusEntriesEqual(
|
|||
left.status === right.status &&
|
||||
left.launchState === right.launchState &&
|
||||
left.error === right.error &&
|
||||
left.hardFailureReason === right.hardFailureReason &&
|
||||
left.livenessSource === right.livenessSource &&
|
||||
left.runtimeAlive === right.runtimeAlive &&
|
||||
left.runtimeModel === right.runtimeModel &&
|
||||
|
|
|
|||
|
|
@ -251,6 +251,7 @@ describe('OpenCodeTeamRuntimeAdapter', () => {
|
|||
alice: {
|
||||
sessionId: 'oc-session-1',
|
||||
launchState: 'permission_blocked',
|
||||
pendingPermissionRequestIds: ['perm-1', 'perm-1', 'perm-2'],
|
||||
runtimePid: 123,
|
||||
model: 'openai/gpt-5.4-mini',
|
||||
evidence: [
|
||||
|
|
@ -283,6 +284,7 @@ describe('OpenCodeTeamRuntimeAdapter', () => {
|
|||
alice: {
|
||||
providerId: 'opencode',
|
||||
launchState: 'runtime_pending_permission',
|
||||
pendingPermissionRequestIds: ['perm-1', 'perm-2'],
|
||||
runtimeAlive: true,
|
||||
agentToolAccepted: true,
|
||||
bootstrapConfirmed: false,
|
||||
|
|
|
|||
|
|
@ -3463,6 +3463,71 @@ describe('teamSlice actions', () => {
|
|||
expect(store.getState().memberSpawnSnapshotsByTeam['my-team']).toEqual(nextSnapshot);
|
||||
});
|
||||
|
||||
it('rewrites renderer state when only hard failure reason changes', async () => {
|
||||
const store = createSliceStore();
|
||||
const previousSnapshot = createMemberSpawnSnapshot({
|
||||
teamLaunchState: 'partial_failure',
|
||||
summary: {
|
||||
confirmedCount: 0,
|
||||
pendingCount: 0,
|
||||
failedCount: 1,
|
||||
runtimeAlivePendingCount: 0,
|
||||
},
|
||||
statuses: {
|
||||
alice: createMemberSpawnStatus({
|
||||
status: 'error',
|
||||
launchState: 'failed_to_start',
|
||||
runtimeAlive: false,
|
||||
livenessSource: undefined,
|
||||
bootstrapConfirmed: false,
|
||||
hardFailure: true,
|
||||
hardFailureReason: 'initial failure',
|
||||
}),
|
||||
},
|
||||
});
|
||||
const previousStatuses = previousSnapshot.statuses;
|
||||
|
||||
store.setState({
|
||||
currentRuntimeRunIdByTeam: {
|
||||
'my-team': 'runtime-run',
|
||||
},
|
||||
memberSpawnStatusesByTeam: {
|
||||
'my-team': previousStatuses,
|
||||
},
|
||||
memberSpawnSnapshotsByTeam: {
|
||||
'my-team': previousSnapshot,
|
||||
},
|
||||
});
|
||||
|
||||
const nextSnapshot = createMemberSpawnSnapshot({
|
||||
teamLaunchState: 'partial_failure',
|
||||
summary: {
|
||||
confirmedCount: 0,
|
||||
pendingCount: 0,
|
||||
failedCount: 1,
|
||||
runtimeAlivePendingCount: 0,
|
||||
},
|
||||
statuses: {
|
||||
alice: createMemberSpawnStatus({
|
||||
status: 'error',
|
||||
launchState: 'failed_to_start',
|
||||
runtimeAlive: false,
|
||||
livenessSource: undefined,
|
||||
bootstrapConfirmed: false,
|
||||
hardFailure: true,
|
||||
hardFailureReason: 'resolved runtime reported missing auth',
|
||||
}),
|
||||
},
|
||||
});
|
||||
hoisted.getMemberSpawnStatuses.mockResolvedValue(nextSnapshot);
|
||||
|
||||
await store.getState().fetchMemberSpawnStatuses('my-team');
|
||||
|
||||
expect(store.getState().memberSpawnStatusesByTeam['my-team']).not.toBe(previousStatuses);
|
||||
expect(store.getState().memberSpawnStatusesByTeam['my-team']).toEqual(nextSnapshot.statuses);
|
||||
expect(store.getState().memberSpawnSnapshotsByTeam['my-team']).toEqual(nextSnapshot);
|
||||
});
|
||||
|
||||
it('rewrites renderer state when top-level launch summary changes', async () => {
|
||||
const store = createSliceStore();
|
||||
const previousSnapshot = createMemberSpawnSnapshot({
|
||||
|
|
|
|||
Loading…
Reference in a new issue