/**
 * @fileoverview Cloudflare Tunnel Manager
 *
 * Manages a cloudflared child process for remote access to Codeman.
 * Spawns `cloudflared tunnel --url` as a child process and parses
 * the trycloudflare.com URL from its stderr output.
 *
 * Follows the same lifecycle pattern as ImageWatcher/SubagentWatcher:
 * extends EventEmitter, start()/stop(), emits typed events.
 *
 * Lifecycle states:
 *   IDLE → STARTING → RUNNING → (crash) → RESTARTING → STARTING → ...
 *   Any state → stop() → IDLE
 */
import { EventEmitter } from 'node:events';
interface TunnelStatus {
    running: boolean;
    url: string | null;
}
export declare class TunnelManager extends EventEmitter {
    private process;
    private url;
    private cloudflaredPath;
    private urlTimeoutTimer;
    private restartTimer;
    private forceKillTimer;
    /** True when the user explicitly requested stop — suppresses auto-restart */
    private stopped;
    private localPort;
    private useHttps;
    /** Map-based lookup: shortCode → QrTokenRecord (hash-based, timing-safe) */
    private qrTokensByCode;
    private currentShortCode;
    private rotationTimer;
    /** SVG cache — regenerated only on token rotation, not per request */
    private cachedQrSvg;
    /** Global rate limit counter (separate from Basic Auth rate limiting) */
    private qrAttemptCount;
    private qrRateLimitResetTimer;
    /**
     * Resolve cloudflared binary path.
     * Checks ~/.local/bin first, then falls back to PATH.
     */
    private resolveCloudflared;
    /** Clear all pending timers */
    private clearTimers;
    /**
     * Start the cloudflared tunnel process.
     */
    start(localPort: number, https: boolean): void;
    /**
     * Schedule an auto-restart if the user hasn't requested stop.
     */
    private maybeScheduleRestart;
    /**
     * Stop the cloudflared tunnel process. Safe to call from any state.
     */
    stop(): void;
    /** Start token rotation — called after tunnel URL is acquired */
    startTokenRotation(): void;
    /** Stop token rotation and clear all tokens */
    stopTokenRotation(): void;
    /** Create a new token, evict expired/consumed ones, emit rotation event */
    private rotateToken;
    /** Get the current (newest) token's short code for QR URL */
    getCurrentShortCode(): string | undefined;
    /** Get cached QR SVG, regenerating only if the short code changed */
    getQrSvg(tunnelUrl: string): Promise<string>;
    /**
     * Validate and atomically consume a token by short code.
     * Map.get() is hash-based — no timing side-channel from string comparison.
     */
    consumeToken(shortCode: string): boolean;
    /** Force-regenerate (manual revocation via API) */
    regenerateQrToken(): void;
    isRunning(): boolean;
    getUrl(): string | null;
    getStatus(): TunnelStatus;
}
export {};
//# sourceMappingURL=tunnel-manager.d.ts.map