/**
 * ServiceSupervisor (RUSH-3193 P1).
 *
 * Owns the timer for every registered `PeriodicService`, replacing the bare
 * `setInterval` closures in `runDaemon()`. Two failure modes motivated it,
 * both observed in production:
 *
 *  - A throw escaping a tick's local try/catch used to hit the process-wide
 *    `uncaughtException` handler and `process.exit(1)` the whole daemon,
 *    taking every OTHER service down with it. Here, a tick failure is caught
 *    per-service and never propagates past `runTick`.
 *  - A tick that hangs on an unbounded await (SSH, keychain) used to latch its
 *    local in-flight guard `true` forever, silently freezing that one service
 *    for the daemon's life (observed ~51h). Here, every tick races a
 *    `deadlineMs` timeout; when the deadline wins, the service is ABANDONED
 *    (PHNX-3608): its `AbortSignal` is aborted so a cooperating tick can unwind
 *    its own I/O, the in-flight guard is released immediately, and the backoff
 *    restart is scheduled right away — it is NOT gated on the runaway promise
 *    settling. An earlier revision kept the guard held until the real promise
 *    settled, which meant a tick that never settles parked the service forever
 *    and blocked backoff restart, `daemon services restart`, and SIGHUP reload —
 *    the exact 12h-usage-dark class this exists to prevent. The orphaned promise
 *    is drained separately in the background; `finishTick` is version-guarded so
 *    its late settlement can never disturb the fresh tick the restart started.
 *
 * Repeated failures (thrown or timed-out) open a circuit breaker: the service
 * is parked (its timer stopped) and retried on exponential backoff via its own
 * `restart()`, while every sibling service keeps ticking on its own timer,
 * unaffected. `start()`/`stop()`/`restart()` are themselves bounded by
 * {@link ServiceSupervisorOptions.lifecycleDeadlineMs} so a wedged bind or close
 * cannot stall daemon startup or shutdown.
 */
import type { DaemonServiceId } from '../daemon-services.js';
import type { DaemonContext, DaemonService, ServiceHealth } from './service.js';
export interface ServiceSupervisorOptions {
    /** Consecutive thrown tick failures before a service is parked. Deadline breaches park immediately. Default 3. */
    parkAfterFailures?: number;
    /** First restart backoff delay, doubled on each further failed restart attempt. Default 5s. */
    backoffBaseMs?: number;
    /** Backoff ceiling. Default 5 minutes. */
    backoffMaxMs?: number;
    /**
     * Hard cap on a service's `start()`/`stop()`/`restart()` call (PHNX-3608). A
     * wedged bind/close would otherwise stall `startAll()` (which awaits each
     * `startOne` in turn) or `stopAll()` at shutdown. A start/restart that
     * breaches it is treated as a failure (parked + backoff); a stop that breaches
     * it is logged and the service is left marked stopped. Default 30s.
     */
    lifecycleDeadlineMs?: number;
}
export interface RegisterServiceOptions {
    /** Register the lifecycle owner but leave it stopped until a live enable. */
    enabled?: boolean;
}
export declare class ServiceSupervisor {
    private readonly registry;
    private ctx;
    private readonly parkAfterFailures;
    private readonly backoffBaseMs;
    private readonly backoffMaxMs;
    private readonly lifecycleDeadlineMs;
    constructor(opts?: ServiceSupervisorOptions);
    /**
     * Race `op` against a deadline. On breach the returned promise rejects with a
     * labelled error while the real `op` is left to settle in the background —
     * used to bound the lifecycle calls (`start`/`stop`/`restart`) so a wedged one
     * cannot stall startup or shutdown. `Promise.race` cannot cancel `op`; the
     * caller decides what a breach means for that service.
     */
    private withDeadline;
    /**
     * Register a service. Must be called before `startAll()`.
     *
     * Accepts both `PeriodicService` (ticked on a fixed interval) and
     * lifecycle-only `DaemonService` (started once, stopped at shutdown). The
     * supervisor uses `isPeriodicService()` to decide whether to schedule a timer
     * for each registered entry.
     */
    register(service: DaemonService, options?: RegisterServiceOptions): void;
    /**
     * Flip a tick's in-flight guard off and release every `awaitIdle()` waiter in
     * the same synchronous step, so no waiter's continuation can run while
     * `inFlight` is still true (PHNX-3608).
     */
    private clearInFlight;
    /** Start every registered service and begin ticking each on its own timer. */
    startAll(ctx: DaemonContext): Promise<void>;
    /** Stop every registered service and clear all timers. */
    stopAll(): Promise<void>;
    /** Force one service to restart right now, outside its normal backoff schedule. Drives `agents daemon services restart <id>` (RUSH-3193 P4). */
    restartOne(id: DaemonServiceId): Promise<void>;
    /** Whether `id` has a lifecycle owner on this supervisor, running or stopped. */
    isRegistered(id: DaemonServiceId): boolean;
    /** Every currently registered service id. */
    registeredIds(): DaemonServiceId[];
    /**
     * Resolve when the service's current tick has really settled. Daemon control
     * edges use this to queue a requested live transition without polling or
     * treating a deadline race as cancellation.
     */
    awaitIdle(id: DaemonServiceId): Promise<void>;
    /**
     * Start one registered service live — drives `agents daemon services enable
     * <id>` (RUSH-3193 P4). Only affects a service already registered on this
     * supervisor. Callers that need live enable from a boot-disabled state must
     * register the service with `{ enabled: false }`, which gives the supervisor
     * ownership without running its startup side effects.
     */
    start(id: DaemonServiceId): Promise<void>;
    /** Stop one registered service live — drives `agents daemon services disable <id>` (RUSH-3193 P4). */
    stop(id: DaemonServiceId): Promise<void>;
    /** Request an immediate supervised tick, used by event edges that cannot wait for the regular cadence. */
    runNow(id: DaemonServiceId): void;
    /** Health for every registered service, keyed by service id. */
    health(): Record<string, ServiceHealth>;
    private startOne;
    private stopOne;
    private scheduleTimer;
    /**
     * Run one tick under a hard deadline (PHNX-3608). The tick receives an
     * `AbortSignal` that is aborted when the deadline elapses, so a cooperating
     * tick can bound its own I/O and unwind. The deadline itself is still enforced
     * with `Promise.race` — JS cannot forcibly cancel an arbitrary await — but on
     * a breach the service is ABANDONED, not parked-and-held: the in-flight guard
     * is released immediately and the backoff restart is scheduled right away
     * (via `park()`), so a tick that never settles can no longer wedge backoff,
     * `daemon services restart`, or SIGHUP reload. The runaway promise drains in
     * the background; `finishTick` is version-guarded on `activeTick`, so its late
     * settlement can never disturb the fresh tick a restart has since started.
     */
    private runTick;
    private park;
    private scheduleRestart;
    private attemptRestart;
    private recordFailure;
    private finishTick;
}
