import { type Page } from "playwright-core";
import type { DipclawConfig } from "../config/types.js";
export declare class BrowserManager {
    private browser;
    private context;
    private chromeProcess;
    private relay;
    /**
     * Materialized OmniFlow runtime extension dir for the current launch. Set by
     * the chrome backend; finishLaunch / waitForOmniFlowReady read it instead of
     * reaching into `chromeProcess`. Null in cloakbrowser mode.
     */
    private extensionPath;
    private config;
    private workspaceLock;
    private launchedAtMs;
    /**
     * Wall-clock of the last browser-touching call (launch, page access,
     * resetTabs). Used by the idle-close watchdog to decide when to tear
     * Chrome down while keeping workspace ownership. Null while Chrome is
     * not launched.
     */
    private lastActivityMs;
    /**
     * In-flight setup promises keyed by Page. Both the `context.on("page")`
     * listener and explicit callers (resetTabs, future openTab fixes) route
     * through `setupPage`; this map ensures they share one promise so an
     * explicit `await setupPage(p)` actually waits for the listener-spawned
     * work to finish, instead of starting a redundant second setup that
     * would attach duplicate Fetch listeners and CDP sessions.
     */
    private setupPromises;
    constructor(config: DipclawConfig);
    /**
     * Claim workspace ownership and clean up orphan Chrome from a previous
     * run. Idempotent. Lets startup fail-fast on workspace conflicts without
     * paying the cost of actually spawning Chrome — Chrome itself is launched
     * lazily by getActivePage/newPage when a browser action is needed, and
     * may also be torn down + relaunched by the idle-close watchdog while
     * this workspace lock stays held.
     */
    /**
     * Per-backend Chromium profile directory.
     *
     * The chrome (real Google Chrome + CDP) and cloakbrowser (patched stealth
     * Chromium 145) backends must NOT share a user-data-dir. A Chromium profile's
     * GPU/shader caches, state LevelDBs, and "Last Version" gate are keyed to the
     * exact engine build that wrote them; pointing a *different* build at it
     * triggers a downgrade/migration path that the weaker, --no-sandbox
     * cloakbrowser mac binary crashes on (SIGTRAP ~1s after launch). Switching
     * backends on the same workspace is exactly that cross-engine collision —
     * hence "切一下就崩,不切正常". Separate dirs keep each engine's profile
     * self-consistent. Login state is unaffected: the cloakbrowser backend
     * re-injects养号 cookies from the session blob on every launch.
     */
    private profileDir;
    prepareWorkspace(): Promise<void>;
    launch(): Promise<void>;
    private spawnAndConnect;
    /**
     * Default backend: spawn a real Google Chrome and attach over CDP — via the
     * extension relay (default) or legacy remote-debug. OmniFlow runs in full mode
     * (proxy + timezone + fingerprint + session import).
     */
    private launchWithChrome;
    /**
     * CloakBrowser backend: launch the patched stealth Chromium as a persistent
     * context. No separate spawn handle (`chromeProcess` stays null) and no CDP
     * Browser handle (`browser` stays null) — the persistent context IS the
     * surface we drive. Fully extension-free: proxy/timezone come from the
     * session blob via CloakBrowser flags, and养号 cookies are injected with
     * Playwright's native `addCookies` inside launchCloakBrowserContext (so
     * there's no OmniFlow extension and no "extension present" fingerprint).
     */
    private launchWithCloakBrowser;
    /** Shared post-launch setup for both backends. */
    private finishLaunch;
    getActivePage(): Promise<Page>;
    getPages(): Promise<Page[]>;
    newPage(): Promise<Page>;
    private withExtensionRelayReconnect;
    private isRecoverableExtensionRelayDisconnect;
    /**
     * Close every open tab and leave a single fresh about:blank.
     *
     * Each Chrome tab runs in its own renderer process; closing the tab is
     * what releases that renderer's anonymous memory (V8 heap, decoded
     * images, DOM). Long-running scheduled tasks accumulate this growth
     * over hours, so we call this at the start of every scheduled task to
     * return renderers to a clean slate.
     *
     * Order matters: open the fresh page first, then close the old ones.
     * If we did it the other way around, Chrome could see "zero pages" for
     * a moment and decide to exit (it doesn't always, but the behavior is
     * version-dependent — opening first sidesteps the question).
     *
     * Safe to call when no tabs are open: returns immediately.
     */
    resetTabs(): Promise<void>;
    /**
     * Tear down Chrome + Playwright handle while retaining workspace
     * ownership. Used by the idle-close watchdog: a later getActivePage()
     * re-spawns Chrome in-place without re-claiming the lock or rescanning
     * for orphans (this process is still the owner).
     *
     * Safe to call when Chrome was never launched: returns immediately.
     * Page references the caller may still hold become detached and any
     * subsequent operation on them will throw — element refs (`[ref=eN]`)
     * are also invalidated.
     */
    closeKeepLock(): Promise<void>;
    close(): Promise<void>;
    restart(): Promise<void>;
    getUptimeMs(): number | null;
    /**
     * Ms since the last browser-touching operation, or null if Chrome is
     * not currently launched. Used by the idle-close watchdog.
     */
    getIdleMs(): number | null;
    /**
     * Idempotent per-page setup entry point.
     *
     * The context "page" event listener fires synchronously on emit, but its
     * setup work is async and
     * not awaited by the emitter. Without coordination, an explicit caller
     * that awaits `newPage()` and then navigates can race against that
     * listener-spawned work.
     *
     * We coalesce by Page: the first call (whichever wins the race) starts
     * the real setup and stashes the Promise; subsequent calls return the
     * same Promise, so awaiting it produces correct happens-before.
     */
    private setupPage;
    private doSetupPage;
    /**
     * Force the Accept-Language header to match the engine locale (en-US, set via
     * Chrome's --lang launch flag). Uses the high-level Playwright API, which
     * rides the page's existing CDP session and works over both connection modes
     * (confirmed over extension-relay via Network.setExtraHTTPHeaders). Guarded so
     * a transport that rejects it can't break page setup.
     */
    private applyAcceptLanguage;
    private waitForOmniFlowReady;
    isLaunched(): boolean;
}
