/** Serve a cached snapshot without recomputing while it is younger than this. */
export declare const DOCTOR_OVERVIEW_FRESH_MS = 90000;
/** Injectable IO + clock so tests exercise the real fs at a temp dir, no mocks. */
export interface DoctorOverviewCacheDeps {
    /** Cache directory (default: the real `~/.agents/.cache`). */
    dir?: string;
    /** Clock (default: {@link Date.now}). */
    now?: () => number;
}
/** Read the last snapshot (best-effort; missing/corrupt/wrong-version → null). */
export declare function readDoctorOverviewCache(deps?: DoctorOverviewCacheDeps): {
    fetchedAt: number;
    payload: unknown;
} | null;
/** Persist a fresh overview payload (best-effort; tmp+rename so reads are atomic). */
export declare function writeDoctorOverviewCache(payload: unknown, deps?: DoctorOverviewCacheDeps): void;
/**
 * Drop the cached overview after a doctor repair attempt changes (or fails to
 * change) live health. Best-effort and deliberately narrow: it never touches
 * the singleflight lock, so an in-progress overview compute remains owned by
 * its holder and no repair can create a retry loop.
 */
export declare function invalidateDoctorOverviewCache(deps?: DoctorOverviewCacheDeps): void;
/**
 * Result of {@link enterDoctorOverviewGate}.
 *  - `cached` non-null → the caller MUST print this string and return; no compute.
 *  - `cached` null     → the caller holds the singleflight lock: compute the
 *    overview, call {@link writeDoctorOverviewCache}, and invoke `release()` on
 *    the way out. Call `release()` in a `finally` so a compute that throws still
 *    frees the lock promptly (idempotent).
 */
export interface OverviewGate {
    cached: string | null;
    release?: () => void;
}
/**
 * Enter the doctor-overview singleflight gate. Returns a cached string to print,
 * or a lock token telling the caller to compute (and then write + release).
 *
 * Contract:
 *  - Fresh snapshot present (and not `forceRefresh`) → `{ cached }`, no lock.
 *  - Otherwise exactly one caller holds the lock and gets `{ cached: null,
 *    release }`; everyone else blocks on the lock, then (on acquiring it)
 *    double-checks and serves the winner's fresh write — or, if the winner runs
 *    past the wait budget, serves the last snapshot — rather than recomputing.
 *  - Never throws: any IO/lock failure degrades to a compute token or a served
 *    snapshot.
 */
export declare function enterDoctorOverviewGate(opts?: {
    forceRefresh?: boolean;
    freshMs?: number;
}, deps?: DoctorOverviewCacheDeps): Promise<OverviewGate>;
