/** * EventBus — observe-only typed event bus. * Subscribers cannot modify or cancel. Subscriber exceptions are caught. */ import type { AgentEventMap } from './events/agent-events.js'; import type { BrainEventMap } from './events/brain-events.js'; import type { FileEventMap } from './events/file-events.js'; import type { FleetEventMap } from './events/fleet-events.js'; import type { MemoryEventMap } from './events/memory-events.js'; import type { ProviderEventMap } from './events/provider-events.js'; import type { ProcessEventMap } from './events/process-events.js'; import type { NetworkEventMap } from './events/network-events.js'; import type { SddEventMap } from './events/sdd-events.js'; import type { SessionEventMap } from './events/session-events.js'; import type { ToolEventMap } from './events/tool-events.js'; import type { WorktreeEventMap } from './events/worktree-events.js'; /** Distress signals the BrainMonitor watches. See `coordination/brain-monitor.ts`. */ export type BrainInterventionKind = 'tool_failure_streak' | 'error_storm' | 'agent_stall' | 'file_churn'; /** * Structural shape of a tracked agent as flushed by AgentStatusTracker. Kept * structural (not imported from the root `session-registry` module) so the * low-level kernel layer takes on no dependency on composition modules. The * real `AgentEntry` is assignable to this. */ export interface TrackedAgentSnapshot { id: string; name: string; startedAt?: string | undefined; status: string; currentTool?: string | undefined; currentTask?: string | undefined; taskId?: string | undefined; iterations: number; toolCalls: number; costUsd?: number | undefined; tokensIn?: number | undefined; tokensOut?: number | undefined; ctxPct?: number | undefined; model?: string | undefined; partialText?: string | undefined; todos?: Array<{ id: string; content: string; status: 'pending' | 'in_progress' | 'completed'; activeForm?: string | undefined; }> | undefined; latestPrompt?: string | undefined; latestPromptAt?: number | undefined; lastActivityAt: string; } export interface EventMap extends AgentEventMap, BrainEventMap, SessionEventMap, ProviderEventMap, ProcessEventMap, NetworkEventMap, FileEventMap, ToolEventMap, MemoryEventMap, SddEventMap, WorktreeEventMap, FleetEventMap { } export type EventName = keyof EventMap; export type Listener = (payload: EventMap[E]) => void; export interface EventLogger { error(msg: string, ctx?: unknown): void | undefined; } export declare class EventBus { private readonly listeners; private readonly wildcards; private logger?; setLogger(logger: EventLogger): void; on(event: E, fn: Listener): () => void; off(event: E, fn: Listener): void; once(event: E, fn: Listener): () => void; /** * Subscribe to all events, regardless of name. Short-hand for * `onPattern('*')`. Use for logging, debugging, or forwarding every * event to another bus (as FleetBus does). * * Returns an unsubscribe function. */ onAny(fn: (event: string, payload: unknown) => void): () => void; /** * Subscribe to all events whose name matches a glob-style prefix. * `'tool.*'` matches `tool.started`, `tool.executed`, `tool.progress`, etc. * `'*'` matches every event. * * The handler receives `(eventName, payload)` with the event name as a * string and the payload as `unknown`. Use for logging, debugging, or * metrics collection across a family of events. * * Returns an unsubscribe function. */ onPattern(pattern: string, fn: (event: string, payload: unknown) => void): () => void; /** * Subscribe to all events whose name matches a RegExp. * More flexible than `onPattern` — use when you need regex features * (alternation, character classes, capture groups). * * Returns an unsubscribe function. */ onRegex(regex: RegExp, fn: (event: string, payload: unknown) => void): () => void; emit(event: E, payload: EventMap[E]): void; /** * Emit a plugin-defined event that is intentionally outside EventMap. * Custom events are delivered to wildcard/pattern listeners only; typed * listeners remain reserved for core EventMap keys. */ emitCustom(event: string, payload: unknown): void; clear(): void; /** * V2-D: introspection helper. Pass an `event` to count handlers for a * single key, or omit to get the total across every event. Used by the * leak-detection smoke test to flag handler accumulation across runs. * Does NOT include wildcard listeners. */ listenerCount(event?: EventName): number; /** * Number of wildcard listeners currently registered. */ wildcardCount(): number; /** * True if anything would receive an emit for `event` — a named listener * OR a wildcard/regex pattern that matches the event name. Unlike * `listenerCount`, this DOES account for wildcards, so callers that gate * behavior on "is anyone listening?" (e.g. SubagentBudget deciding whether * to negotiate a soft limit vs hard-stop) don't misfire when the only * subscriber is a pattern listener like the FleetBus's `onPattern('*')`. */ hasListenerFor(event: string): boolean; } /** * A decorator over `EventBus` that records every listener registration * (`.on`, `.once`, `.onPattern`, `.onRegex`) so that `teardown()` can * remove all of them at once — preventing the memory leaks that occur * when dynamic plugins or long-lived TUI/WebUI interfaces forget to * call `.off()` during session termination. * * Usage: * ```ts * const bus = new ScopedEventBus(); * bus.on('tool.executed', handler1); // tracked * bus.on('provider.response', handler2); // tracked * bus.onPattern('subagent.*', handler3); // tracked * // ... later, when the plugin or session is torn down: * bus.teardown(); // removes all three listeners * ``` * * Also implements `Disposable` (via `[Symbol.dispose]`) for use with * the `using` keyword in Node ≥ 22, or can be used manually with * `bus.teardown()`. */ export declare class ScopedEventBus extends EventBus { private readonly registrations; private nextKey; /** * Identical to `EventBus.on` but the listener is tracked so that * `teardown()` will remove it automatically. */ on(event: E, fn: Listener): () => void; /** * Identical to `EventBus.once` but the listener is tracked so that * `teardown()` will remove it automatically. * * Uses EventBus's public API directly to avoid triggering our own `on()` * override (which would consume a key slot for the wrapper, then orphan * our registration entry under a different key). * * When the wrapper fires, it cleans up BOTH the underlying EventBus * listener AND the tracking entry — so `scopedListenerCount` returns to * its pre-`once()` value without requiring the caller to invoke the * returned unsubscribe. The returned `unsub` is still safe to call * after auto-removal (its delete is a no-op and its off() finds * nothing to remove). */ once(event: E, fn: Listener): () => void; /** * Subscribe to all events. Alias for `onPattern('*')` — the listener is * tracked so that `teardown()` will remove it automatically. */ onAny(fn: (event: string, payload: unknown) => void): () => void; /** * Identical to `EventBus.onPattern` but the listener is tracked so that * `teardown()` will remove it automatically. */ onPattern(pattern: string, fn: (event: string, payload: unknown) => void): () => void; /** * Identical to `EventBus.onRegex` but the listener is tracked so that * `teardown()` will remove it automatically. */ onRegex(regex: RegExp, fn: (event: string, payload: unknown) => void): () => void; /** * Remove every listener that was registered through this scoped bus. * Idempotent — calling it multiple times is safe. * * Also available as `[Symbol.dispose]` for explicit resource management: * ```ts * using scope = new ScopedEventBus(); * scope.on('tool.executed', handler); * // automatically teardown()'d when scope exits * ``` */ teardown(): void; /** Alias for `teardown()` — enables `using new ScopedEventBus()` in Node ≥ 22. */ [Symbol.dispose](): void; /** Number of tracked registrations. */ get scopedListenerCount(): number; } //# sourceMappingURL=events.d.ts.map