/** * Delegation state-machine helpers and store extracted from `delegation-manager.ts` * to enforce the project's max-500-LOC architectural rule (Phase 36 PH36-03). * * This module owns: * * 1. Pure helpers used by `DelegationManager` and the dual-mode dispatch handlers * (`canTransitionDelegationStatus`, `deriveDelegationSurface`, * `deriveRecoveryGuarantee`, `withContractDefaults`, `buildDelegationResult`). * 2. `DelegationStateMachine` — the in-memory delegation store plus its terminal * state-transition + timer machinery (safety ceiling, grace period cleanup, * pruning). `DelegationManager` composes one instance and forwards public * queries/operations to it. * * No new behavior is introduced here — every code path is a verbatim move from * the previous `delegation-manager.ts` implementation, with `this.delegations`, * `this.delegationsBySession`, `this.safetyTimers`, and `this.gracePeriodTimers` * relocated onto this class. */ import { type OpenCodeClient } from "../../shared/session-api.js"; import { type Delegation, type DelegationRecoveryGuarantee, type DelegationResult, type DelegationStatus, type DelegationSurface, type DelegationTerminalKind } from "../../shared/types.js"; /** * Allowed delegation status transitions. * * Terminal states (`completed`, `error`, `timeout`) cannot transition further. */ export declare const VALID_DELEGATION_TRANSITIONS: Record; /** * Returns true when transitioning a delegation from `from` to `to` is allowed * by {@link VALID_DELEGATION_TRANSITIONS}. */ export declare function canTransitionDelegationStatus(from: DelegationStatus, to: DelegationStatus): boolean; /** * Map a delegation's execution mode to its observable delegation surface. * * - `sdk` → `agent-delegation` * - `pty`/`headless` → `command-process` */ export declare function deriveDelegationSurface(executionMode: Delegation["executionMode"]): DelegationSurface; /** * Map a delegation's execution mode to its recovery guarantee classification. * * - `sdk` → `resumable` (parent can poll OpenCode session after restart) * - `pty` → `best-effort` (PTY survives only while harness is alive) * - `headless` → `non-resumable-after-restart` */ export declare function deriveRecoveryGuarantee(executionMode: Delegation["executionMode"]): DelegationRecoveryGuarantee; /** * Fill in default contract fields (`surface`, `recoveryGuarantee`, * `explicitCancellation`) on a delegation read from a non-trusted source * (persistence file, recovery, etc.). */ export declare function withContractDefaults(delegation: Delegation): Delegation; /** * Project a {@link Delegation} record onto the public {@link DelegationResult} * shape returned to delegation tools. Pure projection — no side effects. */ export declare function buildDelegationResult(delegation: Delegation): DelegationResult; /** * Constructor options for {@link DelegationStateMachine}. * * - `client` — OpenCode SDK client used by `handleSafetyCeiling()` to abort * timed-out child sessions. * - `clearExternalTimers` — invoked by {@link DelegationStateMachine.clearAllTimers} * so the SDK and command delegation handlers can clear their per-delegation * timer maps without this module importing them directly. */ export interface DelegationStateMachineOptions { client: OpenCodeClient; clearExternalTimers?: (delegationId: string) => void; } /** * Owns the in-memory delegation store and its lifecycle/timer machinery. * * Responsibilities: * * - Hold the `delegations` and `delegationsBySession` maps. * - Persist the full delegation set whenever it mutates. * - Schedule and cancel safety-ceiling and grace-period timers. * - Apply guarded status transitions, including the unified * {@link DelegationStateMachine.transitionToTerminal} that terminates a * delegation, persists, cleans timers, and fires the parent notification. * * Composed by `DelegationManager`, which retains all dispatch + concurrency * logic. */ export declare class DelegationStateMachine { /** All delegations indexed by delegation id. */ readonly delegations: Map; /** Reverse lookup: child session id → owning delegation id. */ readonly delegationsBySession: Map; /** @internal Test-only — exposed read-only via {@link DelegationManager.safetyTimers}. */ readonly safetyTimers: Map; private readonly gracePeriodTimers; private readonly client; private readonly clearExternalTimers; constructor(options: DelegationStateMachineOptions); /** Get a delegation by id, or `undefined` if unknown. */ get(delegationId: string): Delegation | undefined; /** Snapshot of every delegation currently in memory. */ getAll(): Delegation[]; /** Reverse lookup: get the delegation id owning `sessionId`, if any. */ getDelegationIdForSession(sessionId: string): string | undefined; /** * Register a new delegation, fill in contract defaults, link the child * session id back to it, and optionally arm the safety-ceiling timer. */ registerDelegation(delegation: Delegation, scheduleSafetyCeiling: boolean): void; /** * Persist all in-memory delegations to disk. Runs an opportunistic prune * first when the store is over {@link MAX_DELEGATIONS_BEFORE_PRUNE}. */ persistAll(): void; /** * Hydrate a single delegation from persistence (used by recovery flows). * Does not schedule timers. */ hydrateFromPersistence(delegation: Delegation): void; /** Track a session-id → delegation-id mapping (used by recovery flows). */ trackSession(childSessionId: string, delegationId: string): void; /** * Apply a guarded delegation status transition without terminal side effects. * Returns `true` when the transition was applied. */ transition(delegationId: string, nextStatus: DelegationStatus): boolean; /** * Unified terminal transition for all delegation completion paths. Sets * status, persists, clears timers, schedules grace-period cleanup, logs the * transition, and fires parent notification. */ transitionToTerminal(delegationId: string, newState: DelegationStatus, error?: string, terminalDetail?: { terminalKind?: DelegationTerminalKind; terminationSignal?: string; explicitCancellation?: boolean; }): void; /** Arm the safety-ceiling timer for a delegation. */ scheduleSafetyCeiling(delegation: Delegation): void; /** * Schedule grace-period cleanup for a terminal delegation. Removes the * delegation from in-memory state only — does NOT touch persistence (R-LC-03). */ scheduleGracePeriodCleanup(delegationId: string): void; /** * Clear safety + grace-period timers and any external timers (SDK/command * stability polls) registered with this state machine. */ clearAllTimers(delegationId: string): void; /** * Clear timers and drop the child-session → delegation-id mapping. * The delegation record itself is retained so the parent can still query * its terminal state until grace-period cleanup runs. */ cleanupTracking(delegationId: string, childSessionId: string): void; /** * Remove terminal delegations (`completed`, `error`, `timeout`) whose * `completedAt` timestamp is older than `maxAgeMs`. Prevents unbounded * memory growth in the in-memory delegations map. Syncs durable state after * pruning. * * @param maxAgeMs - Maximum age in ms for keeping terminal delegations. * Defaults to {@link DEFAULT_PRUNE_MAX_AGE_MS} (30 minutes). * @returns Number of delegations pruned. */ pruneCompletedDelegations(maxAgeMs?: number): number; /** * Mark a delegation as user-cancelled via its PTY session id. Returns the * resulting {@link DelegationResult} when the PTY session is recognised, or * `undefined` otherwise. If the delegation is already terminal, returns its * current result without mutating state. */ markCommandCancellationForPtySession(ptySessionId: string): DelegationResult | undefined; /** * Find the active delegation that owns a PTY session id, or `undefined` * when none does. */ findByPtySession(ptySessionId: string): Delegation | undefined; private handleSafetyCeiling; } //# sourceMappingURL=state-machine.d.ts.map