/** * Identity-safe, single-winner teardown. * * Every termination trigger — explicit close, process exit, owner cancellation, * idle/lifetime timeout, conversation teardown, application shutdown — funnels * through `FinalizeOnce`, so exactly one execution owns the terminal transition * and repeated Close returns the recorded result without signalling again. */ import { type ProcessIdentityComparison } from "../os/process-identity.js"; import type { RecoveryJournal } from "./recovery-journal.js"; import type { SessionRegistry } from "./registry.js"; import type { SessionRuntime } from "./session-runtime.js"; import { type CloseResult, type TerminationReason } from "./types.js"; export interface CleanupDeps { readonly registry: SessionRegistry; readonly journal: RecoveryJournal; readonly onFinalized?: ((runtime: SessionRuntime) => void) | undefined; readonly process?: Partial | undefined; } export interface CleanupProcessDeps { readonly isAlive: (pid: number | undefined) => boolean; readonly isProcessGroupAlive: (processGroupId: number | undefined) => boolean; readonly compareIdentity: (pid: number | undefined, identity: string | undefined) => ProcessIdentityComparison; readonly hasLiveDescendants: (pid: number) => Promise; } export declare class CleanupCoordinator { private readonly deps; private readonly process; constructor(deps: CleanupDeps); /** Idempotent: later callers join the first execution's promise. */ close(runtime: SessionRuntime, reason: TerminationReason, deadlineMs: number): Promise; private execute; private waitForOutputDrain; private waitForTreeExit; /** True when a verified descendant or the root is still alive. */ private verifyAbsence; }