/**
 * GatewayConfigCoordinator — owns config persistence, hot-reload, and the
 * per-section reload handlers.
 *
 * Was 350 lines of `GatewayService` covering nine concerns:
 *   - manual `reloadConfig()` (CLI/UI trigger)
 *   - `saveConfig()` / `updateConfig()` (PATCH /api/config)
 *   - `setBundledExtensionActivationTarget` (extension store install)
 *   - `afterWeixinCredentialsPersisted` / `afterFeishuCredentialsPersisted`
 *     (QR-login follow-ups that bypass the watcher)
 *   - `ConfigHotReloader` (fs.watch → debounced per-section dispatch)
 *   - Eight section reload handlers (models / agents / channels / cron /
 *     heartbeat / tools / mcp / extensions)
 *   - `scheduleChannelPluginsAfterPersist` (coalesces rapid saves so
 *     Telegram/Weixin do not stop/start repeatedly)
 *
 * Pulled out so the gateway composition root stays focused on lifecycle, and
 * each handler is reachable from one place when adding a new config section.
 *
 * **Config state ownership.** `GatewayService.config` is still the single
 * source of truth — this coordinator reads it via `getConfig()` and writes it
 * back via `setConfig()` after every reload / persist. We pass through rather
 * than holding our own copy so other coordinators (sessions, marketplace,
 * agent runner) see the latest config the moment a reload commits.
 */
import type { Config } from '../../config/schema.js';
import type { AgentService } from '../../agent/service.js';
import type { ChannelManager } from '../../channels/manager.js';
import type { CronService } from '../../cron/index.js';
import type { HeartbeatService } from '../heartbeat/index.js';
import type { ExtensionLoader } from '../../extensions/loader.js';
import type { MessageBus } from '../../infra/bus/index.js';
export interface GatewayConfigCoordinatorOptions {
    configPath: string;
    bus: MessageBus;
    /** Hot reload (fs.watch) — disabled in tests / certain CLI modes. */
    enableHotReload: boolean;
    getConfig: () => Config;
    /** Writes the new config back into `GatewayService.config`. */
    setConfig: (next: Config) => void;
    getAgentService: () => AgentService;
    getChannelManager: () => ChannelManager;
    getCronService: () => CronService;
    getHeartbeatService: () => HeartbeatService | null;
    getExtensionLoader: () => ExtensionLoader | null;
    /** Re-evaluate browser-extension server attachment after agent defaults change. */
    reconcileBrowserExtensionServer: () => Promise<void>;
    /** Latest channel status snapshot for the `channels.status` SSE event. */
    getChannelsStatus: () => unknown;
    /** SSE emit (used for `config.reload` + `channels.status`). */
    emit: (type: string, payload: unknown) => void;
}
export declare class GatewayConfigCoordinator {
    private readonly opts;
    private configReloader;
    private channelReloadFlushPromise;
    private channelReloadPending;
    constructor(opts: GatewayConfigCoordinatorOptions);
    /** Start the fs.watch-based reloader (idempotent — only starts once). */
    startHotReloader(): void;
    stopHotReloader(): Promise<void>;
    reloadConfig(): Promise<{
        reloaded: boolean;
        error?: string;
    }>;
    saveConfig(config: Config): Promise<{
        saved: boolean;
        error?: string;
    }>;
    /** Merge partial updates into `currentConfig` and persist. */
    updateConfig(updates: Partial<Config>): Promise<{
        updated: boolean;
        error?: string;
    }>;
    /**
     * App store (phase 1): persist `extensions.enabled` / `extensions.disabled`
     * for a bundled extension. Marketplace-only extensions hot-load on enable;
     * disable still needs a gateway restart to unload.
     */
    setBundledExtensionActivationTarget(extensionId: string, wanted: boolean): Promise<{
        ok: boolean;
        error?: string;
        requiresGatewayRestart: boolean;
    }>;
    afterWeixinCredentialsPersisted(): Promise<void>;
    afterFeishuCredentialsPersisted(): Promise<void>;
    /**
     * Apply `latest.channels` to every registered channel plugin (Telegram,
     * Weixin, extensions). Single runtime path for: file watcher hot reload, API
     * saves, and Weixin QR follow-up.
     */
    handleChannelsReload(newConfig: Config): Promise<void>;
    /**
     * Apply `gateway.heartbeat` from current config after PATCH /api/config (and
     * when hot reload is off). File watcher uses `handleHeartbeatReload` with
     * the same effect when paths match.
     */
    reloadHeartbeatFromCurrentConfig(): void;
    private handleModelsReload;
    private handleAgentDefaultsReload;
    /**
     * Coalesces rapid saves so Telegram/Weixin do not stop/start repeatedly.
     * The persist path schedules the channel apply; the same coalescer absorbs
     * follow-up saves until the first flush settles.
     */
    private scheduleChannelPluginsAfterPersist;
    private handleCronReload;
    private handleHeartbeatReload;
    private handleToolsReload;
    private handleMcpReload;
    /** Dispatch config hot reload to extensions that registered `registerReload`. */
    private handleExtensionsReload;
    /**
     * Persist and replace `currentConfig` with the validated file contents so
     * runtime matches disk (PATCH merge objects can drift from Zod-normalized
     * output).
     */
    private writeConfigAndReloadFromDisk;
}
