import { EventEmitter } from 'node:events';
/** Fired by audit-log.logInvocation after a successful (or failed) agent
 *  invocation has been recorded. Mirrors the shape audit-log already
 *  builds, plus a `ts` ISO string for client-side sorting. */
export interface AuditEvent {
    type: 'audit';
    ts: string;
    agent: string;
    intent: string;
    platform: string;
    durationMs: number;
    cost: number;
    success: boolean;
    traceId: string;
    userId: string;
}
/** Fired when approval-bus enqueues a new pending or resolves one. The
 *  /api/approvals snapshot is still authoritative; this event lets the
 *  UI refresh that tab (and the in-chat card) without waiting on the
 *  3 s poll. */
export interface ApprovalEvent {
    type: 'approval';
    phase: 'requested' | 'resolved';
    reqId: string;
    threadId: string;
    platform: string;
    toolName: string;
    /** Present on resolved events — 'allow' / 'deny' / 'timeout' from the
     *  bus's metrics buckets. Absent on `requested`. */
    outcome?: 'allow' | 'deny' | 'timeout';
}
/** Fired on job-board state transitions. The dashboard subscribes to
 *  refresh the Jobs tab without polling. */
export interface JobEvent {
    type: 'job';
    phase: 'created' | 'started' | 'completed' | 'failed' | 'cancelled';
    jobId: number;
    agent: string;
}
/** Periodic metrics tick. Different from individual audit events: this
 *  is a snapshot of the full per-agent state (counters + latency
 *  quantiles) so the Health tab's sparkline doesn't have to derive
 *  everything from raw audits. Emitted by an internal interval, not by
 *  any specific call site. */
export interface MetricsEvent {
    type: 'metrics';
    ts: string;
    agents: Array<{
        agent: string;
        total: number;
        success: number;
        failure: number;
        p50Ms: number;
        p95Ms: number;
        p99Ms: number;
    }>;
}
/** v1.2.86 — long-task goal state changes. Fired when a goal is
 *  created, has its status changed, or gets a progress note appended.
 *  Web /tasks/goals subscribes via SSE so the list refreshes in real
 *  time without a manual reload. */
export interface GoalEvent {
    type: 'goal';
    phase: 'created' | 'status' | 'progress';
    goalId: number;
    platform: string;
    channelId: string;
    threadId: string;
    /** New status when phase='status' or 'created'. */
    status?: 'active' | 'paused' | 'completed' | 'cancelled';
    /** Short headline (truncated title or progress note) for UI consumers. */
    summary?: string;
    ts: string;
}
export type ImhubEvent = AuditEvent | ApprovalEvent | JobEvent | MetricsEvent | GoalEvent;
declare class ImhubEventBus extends EventEmitter {
    /** Bounded recent-event log so a freshly-connected SSE client can
     *  catch up on what happened in the last few seconds without needing
     *  a separate REST poll. Cap at 200 entries — enough for the dashboard
     *  to show a meaningful "what just happened" feed without bloating
     *  process memory. */
    private recent;
    private static readonly RECENT_CAP;
    constructor();
    /**
     * Publish a typed event. Listeners are called synchronously inside
     * EventEmitter.emit; errors thrown from a listener are caught here so
     * a bad subscriber can't break audit-log / approval-bus / job-board.
     */
    publish(event: ImhubEvent): void;
    /** Snapshot of the recent ring buffer. Used by SSE handler on
     *  connection to replay the last N events to a fresh client. */
    getRecent(): ImhubEvent[];
}
export declare const eventBus: ImhubEventBus;
export {};
//# sourceMappingURL=event-bus.d.ts.map