import type { PluginInput } from '@opencode-ai/plugin'; import type { BackgroundJobRecord, ContextFile } from '../../utils/background-job-board'; import type { BackgroundJobStore } from '../../utils/background-job-store'; import type { BackgroundJobSupervisor } from '../../utils/background-job-supervisor'; import type { SessionSelection } from '../../utils/session-selection'; export interface RevivedRunTracker { captureBaseline(taskID: string): Promise; register(input: { taskID: string; generation: number; parentSessionID: string; baselineMessageID?: string; description: string; }): void; isTracked(taskID: string, generation: number): boolean; /** Baseline anchor for a tracked run, so transcript-evidence consumers * (stop gate) can attribute the trailing answer to THIS run instead of * a substituted attempt. Undefined for untracked/stale generations. */ baselineFor(taskID: string, generation: number): string | undefined; probe(taskID: string, generation: number): Promise; onTerminal(record: BackgroundJobRecord): void; /** Fallback observation handoff: prepare before the admission await * so the stop gate defers terminal publication until a delivery owner * exists. Admit converts the preparation into a tracked run * (immediate probe, no reinstall). Reject withdraws on an explicit * host refusal (error envelope / capability rejection). A hung * admission PROMOTES the preparation into the owning run instead of * dropping it. `isObservationPending` stays true until admit/reject * OR a bounded unresolved-admission timer lifts the fence (owner * kept) so a valid empty transcript can still confirm stopped. */ prepareObservation(input: { taskID: string; generation: number; parentSessionID: string; baselineMessageID?: string; description: string; }): boolean; admitObservation(taskID: string, generation: number): boolean; /** Explicit host refusal (error envelope / capability rejection): * nothing was admitted, ownership is released. */ rejectObservation(taskID: string, generation: number): void; /** Unknown admission outcome (transport failed without a response): * the prepared ownership CONVERTS into a tracked run instead of being * dropped — the host may still have accepted the replay. The gate * fence lifts after one more expiry window if admit/reject never * arrive; the owner stays. */ settleObservationUnresolved(taskID: string, generation: number): boolean; isObservationPending(taskID: string, generation: number): boolean; /** Observation-identity fence for the stop gate: a monotonic * revision per tracked run; changes on re-registration even when the * baseline value is identical (especially undefined). */ revisionFor(taskID: string, generation: number): number | undefined; dispose(): void; } export declare function createRevivedRunTracker(options: { input: PluginInput; backgroundJobBoard: BackgroundJobStore; backgroundJobSupervisor?: BackgroundJobSupervisor; maxNotificationRetries?: number; notificationRetryDelayMs?: number; maxStabilizationProbes?: number; stabilizationProbeDelayMs?: number; handoffExpiryMs?: number; onRegister?: (taskID: string) => void; onSettled?: (taskID: string) => void; contextFilesForPrompt?: (taskID: string) => ContextFile[]; pruneContext?: () => void; /** Resolve the parent session's CURRENT agent/model selection at send * time (#1079): a terminal notification must continue the parent in * the mode the session uses now, never a hardcoded `orchestrator`. * Resolved on EVERY attempt (retries re-enter the send path). When * absent or unresolved, behavior falls back to `orchestrator`. */ resolveSelection?: (sessionID: string) => Promise; }): RevivedRunTracker;