import type { ProviderEngine, ProviderSettingsUpdate, WindowCreateOptions, WindowMutation } from "../instance/provider-engine.js"; import type { ProviderDirectoryList, ProviderFileDeleteOptions, ProviderFileDeleteResult, ProviderFileMkdirOptions, ProviderFileMkdirResult, ProviderFileRenameOptions, ProviderFileRenameResult, ProviderFileStat, ProviderFileWriteOptions, ProviderFileWriteResult } from "@termfleet/core/contracts/files.js"; import type { AgentWindowCreateOptions } from "@termfleet/core/internal/agent-launch.js"; import type { AgentSessionIndexPage } from "@termfleet/core/internal/agent-session-index.js"; import type { AttentionRequest, AttentionUrgency, CooperativeSignalEvent, LifecycleSnapshot } from "@termfleet/core/internal/session-lifecycle.js"; import type { ProviderAccessAttribution } from "@termfleet/core/teams/provider-access-token.js"; import type { Bounds, OrphanSessionPruneResult, ProviderHealth, ProviderSnapshot, ProviderWindow, TerminalEffectKind } from "@termfleet/core/types.js"; import { type AgentSessionSubscription, type AgentSessionWatchEvent } from "@termfleet/core/internal/agent-session-watcher.js"; import { type AgentSessionDetails, type ClaudeAgentSessionDetails } from "@termfleet/core/internal/agent-session.js"; type SnapshotListener = (snapshot: ProviderSnapshot) => void; export type ProviderRuntimeServiceOptions = { observeIntervalMs?: number; slowObservationMs?: number; /** * Max concurrent agent boots ("the door"). Booting an agent is slow and * roughly serial on a single provider; this bounds how many run at once so a * dispatch burst can't stampede `agent:create` and time out. Env override: * TERMFLEET_MAX_CONCURRENT_BOOTS. */ maxConcurrentBoots?: number; /** * Opt-in GC: reclaim a finished agent's tmux session (and its PTY) once it has * been gone this many ms. 0/undefined disables it (the default — sessions are * durable). Env override: TERMFLEET_REAP_ENDED_AFTER_MS. */ reapEndedAfterMs?: number; /** * Opt-in self-heal (issue #7): exit the provider process (non-zero) once the * driver has reported degraded health (`ok: false`) for this many sustained * ms, so a supervisor relaunches it. 0/undefined disables it (the default). * Off by default deliberately because a standalone provider may have no * supervisor. Console-managed iTerm adapters opt in from their GUI-context * launcher; the supervisor then replaces them with bounded backoff. Only a * launch from that valid GUI context (or a LaunchAgent) actually recovers. * Env override: TERMFLEET_EXIT_ON_DEGRADED_AFTER_MS. */ exitOnDegradedAfterMs?: number; /** Test seam for the degraded exit; defaults to process.exit. */ exitProcess?: (code: number) => void; /** * Auto-relaunch persisted agents on startup (the OOM-crash-then-restart bug — * see engine.adoptPersistedAgents). Defaults true. Set false for EPHEMERAL * providers: they clean-room their owned sessions on start and are meant to come * up empty, so a stale persisted layout must NOT resurrect agents into them. */ adoptPersistedAgents?: boolean; }; export declare class ProviderRuntimeService { private readonly engine; private readonly listeners; private readonly observeIntervalMs; private readonly slowObservationMs; private active; private consecutiveObservationFailures; private observationDrainScheduled; private observeFailureLogState; private observeInFlight; private pendingObservation; private snapshot; private timer; private readonly bootQueue; private readonly agentSessions; private readonly reapEndedAfterMs; private readonly exitOnDegradedAfterMs; private readonly exitProcess; private readonly adoptPersistedAgentsOnStart; private degradedSinceMs; constructor(engine: ProviderEngine, options?: ProviderRuntimeServiceOptions); dispose(): void; disposeOwnedSessions(): void; initialize(): Promise; start(): void; stop(): void; onSnapshot(listener: SnapshotListener): () => void; getHealth(): ProviderHealth; getPortholeUpstream(): string | undefined; getBrowserCdpUpstream(terminalId: string): string | undefined; getSnapshot(): ProviderSnapshot; getLifecycle(): LifecycleSnapshot; getWindows(): ProviderWindow[]; getDisplayBounds(): Bounds; createWindow(options?: WindowCreateOptions): Promise; createAgentWindow(options: AgentWindowCreateOptions): Promise; moveWindow(mutation: WindowMutation): unknown; renameWindow(options: { id: number; name: string; }): unknown; replaceWindow(id: number): Promise; closeWindow(id: number): unknown; activateWindow(id: number): Promise; pruneOrphanSessions(): OrphanSessionPruneResult; recordCooperativeSignal(options: { atMs: number; event: CooperativeSignalEvent; sessionId: string; }): void; recordAttentionRequest(options: { agentSessionId: string; detail?: string; reason: string; urgency: AttentionUrgency; }): AttentionRequest; clearAttentionRequest(agentSessionId: string): { agentSessionId: string; ok: true; }; updateProviderSettings(settings: ProviderSettingsUpdate): unknown; resizeDisplay(bounds: Bounds): Bounds; captureTerminal(options: { preserveEscapes?: boolean; terminalId: string; lines?: number; }): Promise; getAgentSession(options: { cwd?: string; sessionId: string; tailItems?: number; }): Promise; getAgentSessionMedia(options: { cwd?: string; index: number; sessionId: string; }): Promise<{ data: Buffer; mediaType: string; } | undefined>; getAgentSubagentSession(options: { agentId: string; sessionId: string; tailItems?: number; }): Promise; listAgentSessions(options?: { cursor?: string | null; limit?: number; query?: string; }): Promise; subscribeAgentSession(options: { cwd?: string; sessionId: string; }, listener: (event: AgentSessionWatchEvent) => void): AgentSessionSubscription; recordRemoteInputAttribution(terminalId: string, attribution: ProviderAccessAttribution | string | undefined): void; sendTerminalInput(options: { terminalId: string; data: string; remoteInputBy?: ProviderAccessAttribution | string; submitMode?: "retry" | "single"; }): unknown | Promise; sendToSession(options: { agentSessionId: string; data: string; expiresAt?: string; ifIdleOnly?: boolean; remoteInputBy?: ProviderAccessAttribution | string; submitMode?: "retry" | "single"; }): Promise; interruptSession(agentSessionId: string): Promise<{ agentSessionId: string; delivery: "interrupt-key" | "harness-runtime"; interrupted: true; terminalId: string; }>; relinquishSession(agentSessionId: string): Promise<{ agentSessionId: string; released: true; terminalId: string; }>; closeSession(agentSessionId: string): unknown; markControlSession(options: { agentSessionId: string; cwd?: string; }): unknown; updateSession(options: { agentSessionId: string; title?: string; }): Promise; private requireSessionWindow; private requireSessionTerminal; setTerminalEffect(options: { durationMs?: number; kind: TerminalEffectKind; terminalId: string; }): unknown; deleteFile(options: ProviderFileDeleteOptions): ProviderFileDeleteResult; deleteFileByFilesystem(options: Omit & { filesystemId: string; }): ProviderFileDeleteResult; listDirectory(options: { terminalId: string; path: string; }): ProviderDirectoryList; listDirectoryByFilesystem(options: { filesystemId: string; path: string; }): ProviderDirectoryList; makeDirectory(options: ProviderFileMkdirOptions): ProviderFileMkdirResult; makeDirectoryByFilesystem(options: Omit & { filesystemId: string; }): ProviderFileMkdirResult; readFile(options: { terminalId: string; path: string; }): Buffer; readFileByFilesystem(options: { filesystemId: string; length?: number; offset?: number; path: string; }): Buffer; renameFile(options: ProviderFileRenameOptions): ProviderFileRenameResult; renameFileByFilesystem(options: Omit & { filesystemId: string; }): ProviderFileRenameResult; statFile(options: { terminalId: string; path: string; }): ProviderFileStat; statFileByFilesystem(options: { filesystemId: string; path: string; }): ProviderFileStat; writeFileByFilesystem(options: Omit & { filesystemId: string; }): ProviderFileWriteResult; writeFile(options: ProviderFileWriteOptions): ProviderFileWriteResult; refreshAfterInput(): void; refreshAfterEffect(): void; observeNow(reason: string, options: { emit: boolean; }): Promise; private performObservation; private scheduleObservationDrain; private startPendingObservation; private finishObservation; private checkDegradedExit; private executeCommand; private executeCommandAsync; private scheduleNextObservation; private observeInBackground; private emitSnapshot; private failedObservationSnapshot; private initializingSnapshot; } export {};