/**
 * Core Event Bus
 *
 * UI-agnostic pub/sub system for operations feed.
 * All visible output goes through the EventBus.
 *
 * Rules:
 * - In-memory only (no persistence)
 * - No UI imports inside bus. Bus is pure logic.
 * - Must support multiple subscribers.
 * - Must return an unsubscribe() function.
 */
class EventBus {
    subscribers = new Set();
    eventCounter = 0; // Monotonic counter for IDs
    /**
     * Emit an event
     * Generates id and ts if missing, then calls all subscribers synchronously
     */
    emit(e) {
        // Generate id if missing
        const id = e.id || `evt-${++this.eventCounter}`;
        // Set ts = Date.now() if missing
        const ts = e.ts ?? Date.now();
        // Default level to INFO if not provided
        const level = e.level || 'INFO';
        const event = {
            id,
            ts,
            tag: e.tag,
            level,
            msg: e.msg,
        };
        // Call all subscribers synchronously
        // Wrap in try/catch so one bad subscriber doesn't kill updates
        this.subscribers.forEach(subscriber => {
            try {
                subscriber(event);
            }
            catch (error) {
                // Don't let subscriber errors break the bus
                // In TUI mode, we can't log, so we silently continue
                // In debug mode, we could log to stderr
                if (process.env.DEBUG_NO_TUI === '1') {
                    // In non-TUI mode, it's safe to use console.error (goes to stderr, not stdout)
                    console.error('[EventBus] Handler error:', error);
                }
            }
        });
    }
    /**
     * Subscribe to events
     * Returns unsubscribe function
     */
    subscribe(fn) {
        this.subscribers.add(fn);
        // Return unsubscribe function
        return () => {
            this.subscribers.delete(fn);
        };
    }
    /**
     * Helper: emit with tag and message (for compatibility)
     */
    emitTag(tag, msg, level = 'INFO') {
        this.emit({ tag, msg, level });
    }
    /**
     * Get subscriber count (for debugging)
     */
    getSubscriberCount() {
        return this.subscribers.size;
    }
    /**
     * Clear all handlers (for testing)
     */
    clear() {
        this.subscribers.clear();
    }
}
/**
 * Global event bus instance
 */
export const eventBus = new EventBus();
//# sourceMappingURL=eventBus.js.map