feat(opencode): wire work sync delivery busy signals

This commit is contained in:
777genius 2026-05-06 19:20:24 +03:00
parent 2e6549620f
commit 937999c3e3
2 changed files with 144 additions and 0 deletions

View file

@ -1362,6 +1362,24 @@ async function initializeServices(): Promise<void> {
)
.map((team) => team.teamName);
},
extraBusySignals: [
{
isBusy: (input) => teamProvisioningService.getOpenCodeMemberDeliveryBusyStatus(input),
},
],
nudgeDeliveryWake: {
schedule: (input) => {
if (input.providerId !== 'opencode') {
return;
}
teamProvisioningService.scheduleOpenCodeMemberInboxDeliveryWake({
teamName: input.teamName,
memberName: input.memberName,
messageId: input.messageId,
delayMs: input.delayMs,
});
},
},
logger: createLogger('Feature:MemberWorkSync'),
});
teamProvisioningService.setRuntimeTurnSettledHookSettingsProvider((input) =>

View file

@ -10981,6 +10981,132 @@ export class TeamProvisioningService {
return null;
}
async getOpenCodeMemberDeliveryBusyStatus(input: {
teamName: string;
memberName: string;
nowIso: string;
}): Promise<{
busy: boolean;
reason?: string;
retryAfterIso?: string;
activeMessageId?: string;
activeMessageKind?: string | null;
}> {
if (!(await this.isOpenCodeRuntimeRecipient(input.teamName, input.memberName))) {
return { busy: false };
}
const nowMs = Date.parse(input.nowIso);
const retryAfterIso = new Date(
(Number.isFinite(nowMs) ? nowMs : Date.now()) + 60_000
).toISOString();
let inboxMessages: Awaited<ReturnType<TeamInboxReader['getMessagesFor']>>;
try {
inboxMessages = await this.inboxReader.getMessagesFor(input.teamName, input.memberName);
} catch {
return {
busy: true,
reason: 'opencode_inbox_read_failed',
retryAfterIso,
};
}
const foregroundMessages = inboxMessages.filter(
(message) => message.messageKind !== 'member_work_sync_nudge'
);
const unreadForeground = foregroundMessages.find(
(message) =>
!message.read &&
typeof message.text === 'string' &&
message.text.trim().length > 0 &&
this.hasStableMessageId(message)
);
if (unreadForeground?.messageId) {
return {
busy: true,
reason: 'opencode_foreground_inbox_unread',
retryAfterIso,
activeMessageId: unreadForeground.messageId,
activeMessageKind: unreadForeground.messageKind ?? null,
};
}
const recentForeground = foregroundMessages.find((message) => {
const timestampMs = Date.parse(message.timestamp);
return Number.isFinite(timestampMs) && Number.isFinite(nowMs) && nowMs - timestampMs < 60_000;
});
if (recentForeground?.messageId) {
return {
busy: true,
reason: 'opencode_foreground_inbox_recent',
retryAfterIso,
activeMessageId: recentForeground.messageId,
activeMessageKind: recentForeground.messageKind ?? null,
};
}
const identity = await this.resolveOpenCodeMemberDeliveryIdentity(
input.teamName,
input.memberName
);
if (!identity.ok) {
return { busy: true, reason: identity.reason, retryAfterIso };
}
const laneIndex = await readOpenCodeRuntimeLaneIndex(getTeamsBasePath(), input.teamName).catch(
() => null
);
if (!laneIndex) {
return { busy: true, reason: 'opencode_lane_index_unavailable', retryAfterIso };
}
if (laneIndex.lanes[identity.laneId]?.state !== 'active') {
return { busy: true, reason: 'opencode_no_active_lane', retryAfterIso };
}
const activeRecord = await this.createOpenCodePromptDeliveryLedger(
input.teamName,
identity.laneId
)
.getActiveForMember({
teamName: input.teamName,
memberName: identity.canonicalMemberName,
laneId: identity.laneId,
})
.catch(() => null);
if (activeRecord) {
return {
busy: true,
reason: `opencode_prompt_delivery_active:${activeRecord.messageKind ?? 'default'}`,
retryAfterIso: activeRecord.nextAttemptAt ?? retryAfterIso,
activeMessageId: activeRecord.inboxMessageId,
activeMessageKind: activeRecord.messageKind,
};
}
return { busy: false };
}
scheduleOpenCodeMemberInboxDeliveryWake(input: {
teamName: string;
memberName: string;
messageId: string;
delayMs?: number;
}): void {
const teamName = input.teamName.trim();
const memberName = input.memberName.trim();
const messageId = input.messageId.trim();
if (!teamName || !memberName || !messageId || !this.isOpenCodePromptDeliveryWatchdogEnabled()) {
return;
}
this.scheduleOpenCodePromptDeliveryWatchdog({
teamName,
memberName,
messageId,
delayMs: Math.max(0, input.delayMs ?? 500),
});
}
private toOpenCodeRuntimeDeliveryStatus(
record: OpenCodePromptDeliveryLedgerRecord
): OpenCodeRuntimeDeliveryStatus {