/**
 * DAG supervisor — the continuous dispatch loop that makes the Factory
 * dynamic.
 *
 * `teams start --watch` and `factory run` both use this. Each wave:
 *   1. call startReady(team) to fire any now-ready teammates
 *   2. listByTask(team) to count pending / running / done / failed
 *   3. emit one status event (via the caller's callback)
 *   4. exit when pending + running == 0 (DAG drained)
 *
 * Why a shared function:
 *  - the loop is the orchestration, the thing that lets any worker add
 *    tasks mid-flight via `agents teams add` and have them picked up
 *  - `factory run` is just `teams start --watch` with factory-flavored
 *    presentation; keeping them in sync avoids drift
 *
 * The caller supplies a presenter callback so the same loop can drive
 * terminal output, json-per-wave output, or a TUI.
 */
import type { AgentManager, AgentProcess } from './agents.js';
import type { TeamBudgetWatcher } from '../budget/live-team.js';
import type { BreachInfo } from '../budget/enforce.js';
export interface WaveSummary {
    wave: number;
    timestamp: string;
    team: string;
    launched: AgentProcess[];
    pending: number;
    running: number;
    completed: number;
    failed: number;
    drained: boolean;
}
export interface SupervisorOptions {
    team: string;
    intervalMs?: number;
    maxWaves?: number;
    /** Called once per wave. Return false to stop the loop gracefully. */
    onWave: (summary: WaveSummary) => void | Promise<void> | boolean | Promise<boolean>;
    /**
     * Optional live-spend watcher (issue #399). Polled once per wave; on first
     * breach the supervisor calls `manager.stopByTask(team)` and exits with
     * `stoppedBy: 'budget'`. Dormant when null — supervisor behavior is unchanged
     * for teams that never opt into budget enforcement.
     */
    budgetWatcher?: TeamBudgetWatcher | null;
    /** Called with the breach details when the budget watcher trips. */
    onBudgetBreach?: (breach: BreachInfo) => void;
}
export interface SupervisorResult {
    waves: number;
    stoppedBy: 'drained' | 'max-waves' | 'signal' | 'callback' | 'budget';
    elapsed_ms: number;
    /**
     * Number of teammates in the `failed` state when the team drained. Only set
     * for `stoppedBy === 'drained'`. A drained DAG means nothing is pending or
     * running — NOT that everything succeeded — so callers that treat "drained"
     * as success (e.g. a completion nudge) must check `failed === 0` first.
     */
    failed?: number;
    /** Set when `stoppedBy === 'budget'` — the breach that terminated the team. */
    budgetBreach?: BreachInfo;
}
/**
 * Run the continuous DAG dispatcher until the team drains, the caller
 * returns false from onWave, or SIGINT/SIGTERM arrives.
 */
export declare function runSupervisor(mgr: AgentManager, opts: SupervisorOptions): Promise<SupervisorResult>;
