fix(team): clear stale permission launch state

This commit is contained in:
777genius 2026-04-23 01:44:55 +03:00
parent 76fca31fb1
commit 80beb3c877
2 changed files with 32 additions and 3 deletions

View file

@ -375,8 +375,8 @@ export class RuntimePermissionRequestStore {
teamName: string;
visibleProviderRequestIds: Set<string>;
now: string;
}): Promise<string[]> {
const expired: string[] = [];
}): Promise<Array<Pick<RuntimePermissionRequestRecord, 'appRequestId' | 'memberName'>>> {
const expired: Array<Pick<RuntimePermissionRequestRecord, 'appRequestId' | 'memberName'>> = [];
await this.store.updateLocked((records) =>
records.map((record) => {
if (
@ -387,7 +387,7 @@ export class RuntimePermissionRequestStore {
) {
return record;
}
expired.push(record.appRequestId);
expired.push({ appRequestId: record.appRequestId, memberName: record.memberName });
return {
...record,
state: 'provider_missing' as const,
@ -648,6 +648,26 @@ export class RuntimePermissionReconciler {
});
}
const clearedMembers = new Set(
expired
.map((record) => record.memberName)
.filter((memberName) => memberName.trim().length > 0)
.filter((memberName) => !pendingByMember.has(memberName))
);
for (const memberName of clearedMembers) {
await this.launchStateStore.updateMember(input.teamName, memberName, (member) => ({
...member,
launchState:
member.launchState === 'confirmed_alive'
? member.launchState
: member.bootstrapConfirmed
? 'confirmed_alive'
: 'runtime_pending_bootstrap',
pendingPermissionRequestIds: [],
lastRuntimeEventAt: now,
}));
}
for (const [memberName, requestIds] of pendingByMember) {
await this.launchStateStore.updateMember(input.teamName, memberName, (member) => ({
...member,

View file

@ -349,6 +349,11 @@ describe('RuntimePermissionRequestStore and services', () => {
it('expires local pending requests that disappeared from provider', async () => {
await store.upsertPending(permissionRecord());
await launchState.updateMember('team-a', 'alice', (member) => ({
...member,
launchState: 'runtime_pending_permission',
pendingPermissionRequestIds: ['opencode:run-1:perm_1'],
}));
client.pending = [];
const reconciler = new RuntimePermissionReconciler(
client,
@ -368,6 +373,10 @@ describe('RuntimePermissionRequestStore and services', () => {
state: 'provider_missing',
lastError: 'Provider no longer lists this permission request',
});
expect(launchState.members.get('alice')).toMatchObject({
launchState: 'runtime_pending_bootstrap',
pendingPermissionRequestIds: [],
});
expect(diagnostics.append).toHaveBeenCalledWith(
expect.objectContaining({
type: 'opencode_permission_requests_expired',