import type { CDPClient } from './cdp.js';
export interface RefOpts {
    interactive?: boolean;
    limit?: number;
    compact?: boolean;
}
export interface RefNode {
    ref: number;
    role: string;
    name: string;
    attrs: string[];
    backendNodeId?: number;
    editor?: string;
}
/**
 * Stable, navigation-surviving identity for a ref. Unlike {@link RefNode}, this
 * carries no `backendNodeId` (which goes stale the moment the DOM re-renders) —
 * only the accessible descriptor a fresh `getRefs` can be re-matched against.
 * Cached in per-task state so a later `click <ref>` can self-heal when the
 * integer ref has drifted (see {@link healRef}).
 */
export interface RefDescriptor {
    ref: number;
    role: string;
    name: string;
    attrs: string[];
    /**
     * Best-effort CSS selector captured via DOM. Reserved for future
     * selector-based healing; matching today is role+name+attrs+position.
     */
    selector?: string;
}
/**
 * A cached ref listing for one tab: the stable descriptors plus the resolved
 * {@link RefOpts} the listing was built with. A later `click`/`type` MUST
 * rebuild its node map with these same opts, or the integer refs it looks up
 * are numbered against a *different* accessibility filter than the one the
 * user saw in `browser refs` — the drift that makes self-heal silently click
 * the wrong element on the second click.
 */
export interface RefSnapshot {
    descriptors: RefDescriptor[];
    opts: {
        interactive: boolean;
        limit: number;
    };
}
/** Snapshot the stable descriptor for every ref in a freshly-built node map. */
export declare function describeRefs(nodeMap: Map<number, RefNode>): RefDescriptor[];
/**
 * Re-resolve a stale ref against a freshly-built node map by matching the
 * cached descriptor. Pure — no CDP, no DOM.
 *
 * The integer ref assigned by {@link getRefs} is positional: it shifts whenever
 * the accessibility tree changes (navigation, re-render, or even a different
 * `interactive` filter). The descriptor's (role, name) pair is the coarse
 * identity, but a page can carry duplicate (role, name) elements — two "Submit"
 * buttons, one action button per repeated list row. Matching on (role, name)
 * alone would heal to whichever duplicate the fresh scan happens to hit first,
 * which can be the wrong one. So among (role, name) matches we tie-break, in
 * priority order:
 *
 *   1. **DOM-backed** — a candidate with a `backendNodeId` is resolvable to
 *      coordinates; one without is unclickable, so healing to it is useless.
 *   2. **Attribute similarity** — the cached `attrs` (disabled / checked /
 *      selected / …) disambiguate otherwise-identical twins (the *disabled*
 *      Submit vs the enabled one).
 *   3. **Positional proximity** — the fresh ref closest to the original cached
 *      ref index wins, so a repeated list-row action heals to its nearest
 *      positional twin rather than jumping across the page.
 *
 * Returns the new integer ref, or `null` when no node with the same role+name
 * exists in the fresh map (unhealable — the element is genuinely gone).
 */
export declare function healRef(descriptor: Pick<RefDescriptor, 'ref' | 'role' | 'name' | 'attrs'>, freshNodeMap: Map<number, RefNode>): number | null;
export declare function getRefs(cdp: CDPClient, sessionId: string, opts?: RefOpts): Promise<{
    refs: string;
    nodeMap: Map<number, RefNode>;
    opts: {
        interactive: boolean;
        limit: number;
    };
}>;
export declare function resolveRefToCoords(cdp: CDPClient, sessionId: string, nodeMap: Map<number, RefNode>, ref: number): Promise<{
    x: number;
    y: number;
}>;
