import type { EffortLevel, MemberLaunchState, OpenCodeAppManagedBootstrapCandidate, OpenCodeBootstrapEvidenceSource, OpenCodeBootstrapMode, PersistedTeamLaunchPhase, PersistedTeamLaunchSnapshot, TeamAgentRuntimeBackendType, TeamAgentRuntimeDiagnosticSeverity, TeamAgentRuntimeLivenessKind, TeamAgentRuntimePidSource, TeamLaunchAggregateState, TeamProvisioningSupportDiagnostic, } from '@shared/types'; export const TEAM_RUNTIME_PROVIDER_IDS = ['anthropic', 'codex', 'gemini', 'opencode'] as const; export type TeamRuntimeProviderId = (typeof TEAM_RUNTIME_PROVIDER_IDS)[number]; export interface TeamRuntimeMemberSpec { name: string; role?: string; workflow?: string; isolation?: 'worktree'; providerId: TeamRuntimeProviderId; model?: string; effort?: EffortLevel; cwd: string; } export type TeamRuntimeApprovalProviderId = 'anthropic' | 'opencode' | 'codex'; export interface TeamRuntimePendingApproval { providerId: Extract; requestId: string; sessionId?: string | null; tool?: string | null; title?: string | null; kind?: string | null; raw?: Record; } export type TeamRuntimePendingPermission = TeamRuntimePendingApproval; export interface TeamRuntimePermissionAnswerInput { runId: string; teamName: string; laneId?: string; cwd: string; providerId: Extract; memberName: string; requestId: string; decision: 'allow' | 'reject'; expectedMembers: TeamRuntimeMemberSpec[]; previousLaunchState: PersistedTeamLaunchSnapshot | null; } export interface TeamRuntimeLaunchInput { runId: string; teamName: string; laneId?: string; cwd: string; prompt?: string; providerId: TeamRuntimeProviderId; model?: string; effort?: EffortLevel; /** * Runtime-only readiness skips extra model execution probes. * Use when a separate preflight or the real launch prompt is the authority. */ runtimeOnly?: boolean; /** * Skip the adapter-level readiness bridge before launch. * Use only when the launch bridge performs equivalent runtime/provider/MCP validation. */ skipReadinessPreflight?: boolean; skipPermissions: boolean; expectedMembers: TeamRuntimeMemberSpec[]; previousLaunchState: PersistedTeamLaunchSnapshot | null; } export interface TeamRuntimePrepareSuccess { ok: true; providerId: TeamRuntimeProviderId; modelId: string | null; diagnostics: string[]; warnings: string[]; supportDiagnostics?: TeamProvisioningSupportDiagnostic[]; } export interface TeamRuntimePrepareFailure { ok: false; providerId: TeamRuntimeProviderId; reason: string; diagnostics: string[]; warnings: string[]; retryable: boolean; supportDiagnostics?: TeamProvisioningSupportDiagnostic[]; } export type TeamRuntimePrepareResult = TeamRuntimePrepareSuccess | TeamRuntimePrepareFailure; export interface TeamRuntimeMemberLaunchEvidence { memberName: string; providerId: TeamRuntimeProviderId; model?: string; launchState: MemberLaunchState; agentToolAccepted: boolean; runtimeAlive: boolean; bootstrapConfirmed: boolean; hardFailure: boolean; hardFailureReason?: string; pendingPermissionRequestIds?: string[]; pendingApprovals?: TeamRuntimePendingApproval[]; pendingPermissions?: TeamRuntimePendingApproval[]; sessionId?: string; bootstrapEvidenceSource?: OpenCodeBootstrapEvidenceSource; bootstrapMode?: OpenCodeBootstrapMode; appManagedBootstrapCandidate?: OpenCodeAppManagedBootstrapCandidate; backendType?: TeamAgentRuntimeBackendType; runtimePid?: number; livenessKind?: TeamAgentRuntimeLivenessKind; pidSource?: TeamAgentRuntimePidSource; runtimeDiagnostic?: string; runtimeDiagnosticSeverity?: TeamAgentRuntimeDiagnosticSeverity; diagnostics: string[]; } export interface TeamRuntimeLaunchResult { runId: string; teamName: string; leadSessionId?: string; launchPhase: PersistedTeamLaunchPhase; teamLaunchState: TeamLaunchAggregateState; members: Record; warnings: string[]; diagnostics: string[]; } export type TeamRuntimeReconcileReason = | 'startup_recovery' | 'manual_refresh' | 'launch_progress' | 'provider_event' | 'watcher_event' | 'stop'; export interface TeamRuntimeReconcileInput { runId: string; teamName: string; laneId?: string; providerId: TeamRuntimeProviderId; expectedMembers: TeamRuntimeMemberSpec[]; previousLaunchState: PersistedTeamLaunchSnapshot | null; reason: TeamRuntimeReconcileReason; } export interface TeamRuntimeReconcileResult { runId: string; teamName: string; launchPhase: PersistedTeamLaunchPhase; teamLaunchState: TeamLaunchAggregateState; members: Record; snapshot: PersistedTeamLaunchSnapshot | null; warnings: string[]; diagnostics: string[]; } export type TeamRuntimeStopReason = 'user_requested' | 'relaunch' | 'cleanup' | 'app_shutdown'; export interface TeamRuntimeStopInput { runId: string; teamName: string; laneId?: string; cwd?: string; providerId: TeamRuntimeProviderId; reason: TeamRuntimeStopReason; previousLaunchState: PersistedTeamLaunchSnapshot | null; force?: boolean; } export interface TeamRuntimeMemberStopEvidence { memberName: string; providerId: TeamRuntimeProviderId; stopped: boolean; sessionId?: string; diagnostics: string[]; } export interface TeamRuntimeStopResult { runId: string; teamName: string; stopped: boolean; members: Record; warnings: string[]; diagnostics: string[]; } export interface TeamLaunchRuntimeAdapter { readonly providerId: TeamRuntimeProviderId; prepare(input: TeamRuntimeLaunchInput): Promise; launch(input: TeamRuntimeLaunchInput): Promise; reconcile(input: TeamRuntimeReconcileInput): Promise; stop(input: TeamRuntimeStopInput): Promise; answerRuntimePermission?( input: TeamRuntimePermissionAnswerInput ): Promise; } export function isTeamRuntimeProviderId(value: unknown): value is TeamRuntimeProviderId { return value === 'anthropic' || value === 'codex' || value === 'gemini' || value === 'opencode'; } export class TeamRuntimeAdapterRegistry { private readonly adapters = new Map(); constructor(adapters: readonly TeamLaunchRuntimeAdapter[] = []) { for (const adapter of adapters) { this.register(adapter); } } register(adapter: TeamLaunchRuntimeAdapter): void { if (!isTeamRuntimeProviderId(adapter.providerId)) { throw new Error(`Invalid runtime adapter provider: ${String(adapter.providerId)}`); } if (this.adapters.has(adapter.providerId)) { throw new Error(`Runtime adapter already registered: ${adapter.providerId}`); } this.adapters.set(adapter.providerId, adapter); } get(providerId: TeamRuntimeProviderId): TeamLaunchRuntimeAdapter { const adapter = this.adapters.get(providerId); if (!adapter) { throw new Error(`Runtime adapter is not available for provider ${providerId}`); } return adapter; } has(providerId: TeamRuntimeProviderId): boolean { return this.adapters.has(providerId); } providers(): TeamRuntimeProviderId[] { return Array.from(this.adapters.keys()); } }