interface StorageAdapter {
    open(name: string): Promise<void>;
    get<T = unknown>(key: string): Promise<T | undefined>;
    set(key: string, value: unknown): Promise<void>;
    delete(key: string): Promise<void>;
    iterate(prefix: string): AsyncIterable<[string, unknown]>;
    close(): Promise<void>;
}
type StorageKind = 'memory' | 'indexeddb' | 'localstorage' | StorageAdapter;

type Drawer = {
    id: string;
    text: string;
    ts: number;
    wing?: string;
    room?: string;
    meta?: Record<string, unknown>;
};
type MemoryOpts = {
    customerId: string;
    storage?: StorageKind;
    /**
     * Optional host-supplied tokeniser. Receives the drawer text, returns
     * the feature list used for BM25 recall. Default handles 200+ languages
     * out of the box (no per-locale packs). See `dddk/utils/text`.
     */
    extractFeatures?: (text: string) => string[];
    sync?: {
        bootstrap?: () => Promise<{
            drawers: Drawer[];
        }>;
        pushChange?: (change: {
            op: 'add' | 'remove';
            drawer?: Drawer;
            id?: string;
        }) => Promise<void>;
    };
};
type MemorySearchOpts = {
    topK?: number;
    scope?: {
        wing?: string;
        room?: string;
    };
    recencyBoost?: boolean;
};
declare class Memory {
    private customerId;
    private storage;
    private drawers;
    private features;
    private opened;
    private opts;
    private extract;
    constructor(opts: MemoryOpts);
    init(): Promise<void>;
    private indexDrawer;
    wing(name: string): WingScope;
    addDrawer(d: Omit<Drawer, 'id'> & {
        id?: string;
    }): Promise<Drawer>;
    removeDrawer(id: string): Promise<void>;
    search(query: string, opts?: MemorySearchOpts): Promise<Drawer[]>;
    recent(opts?: {
        wing?: string;
        room?: string;
        days?: number;
        limit?: number;
    }): Drawer[];
    private persist;
    dispose(): Promise<void>;
}
declare class WingScope {
    private mem;
    name: string;
    constructor(mem: Memory, name: string);
    room(name: string): RoomScope;
    search(q: string, opts?: MemorySearchOpts): Promise<Drawer[]>;
    recent(opts?: {
        days?: number;
        limit?: number;
    }): Drawer[];
}
declare class RoomScope {
    private mem;
    wing: string;
    room: string;
    constructor(mem: Memory, wing: string, room: string);
    addDrawer(d: {
        text: string;
        ts?: number;
        meta?: Record<string, unknown>;
    }): Promise<Drawer>;
    search(q: string, opts?: MemorySearchOpts): Promise<Drawer[]>;
}

/**
 * Bridge between `Proactive` and dddk's PieceSurface render system.
 *
 * Usage:
 *   const proactive = createProactive({
 *     render: createPieceRender({ mount: dddk.mountSurface, locale: 'zh-TW' }),
 *   });
 *
 * The host supplies a `mount` function — anything that takes a PieceSurface and resolves
 * the user's response ('yes' | 'no' | 'dismiss').
 */

type PieceNode = {
    kind: string;
    text?: string;
    action?: string;
    shortcut?: string;
    children?: PieceNode[];
    [k: string]: unknown;
};
type PieceSurface = {
    root: PieceNode;
    data?: Record<string, unknown>;
};
type SurfaceMountFn = (surface: PieceSurface, opts: {
    placement?: 'inline' | 'dock' | 'modal';
    timeoutMs?: number;
}) => Promise<{
    action: string;
    data?: Record<string, unknown>;
}>;
declare function createPieceRender(opts: {
    mount: SurfaceMountFn;
    locale?: string;
    keys?: {
        yes?: string;
        no?: string;
        dismiss?: string;
    };
}): (prompt: PromptDefinition, surface: PromptSurface, ctx?: TriggerContext) => Promise<'yes' | 'no' | 'dismiss'>;

/**
 * Structural Analytics interface — the subset of `Analytics` that
 * proactive needs. Declared here (not imported from the analytics
 * module) so consumers passing a `dddk/modules/analytics` instance
 * aren't blocked by TypeScript's nominal-typing on private fields.
 */
interface AnalyticsLike {
    track(event: string, payload?: Record<string, unknown>): void;
}
type Trigger = {
    id: string;
    condition: (ctx: TriggerContext) => boolean | Promise<boolean>;
};
type TriggerContext = {
    now: number;
    page?: string;
    dwellMs?: number;
    scrollDepth?: number;
    user?: Record<string, unknown>;
    memory?: Memory;
    customMeta?: Record<string, unknown>;
};
type PromptSurface = {
    text: string | ((ctx: TriggerContext) => string);
    placement?: 'inline' | 'dock' | 'modal';
    yesLabel?: string;
    noLabel?: string;
    dismissable?: boolean;
    autoTimeoutMs?: number;
    /**
     * Rich content surface. When provided, the renderer ignores `text` /
     * `yesLabel` / `noLabel` and renders this PieceSurface tree directly.
     * Use for recommendation grids (`OptionGroup` of `MediaCard`s),
     * confirm summaries, multi-option pickers — anything that benefits
     * from image + structured layout instead of plain text + yes/no.
     *
     * The piece tree should `trigger('choose', { value, index })` (or a
     * similar action) — the bridge maps any non-`yes` / non-`no` action
     * to `'dismiss'` for the standard 3-way response. Host can use the
     * `data` model to capture the picked value separately via analytics.
     */
    pieces?: {
        /** Standard PieceSurface shape: { root: PieceNode, data?: object } */
        root: {
            kind: string;
            [k: string]: unknown;
        };
        data?: Record<string, unknown>;
    };
};
type PromptDefinition = {
    id: string;
    category?: string;
    priority?: number;
    triggers: Trigger[];
    triggerLogic?: 'AND' | 'OR';
    surface: PromptSurface;
    onResponse?: (response: 'yes' | 'no' | 'dismiss', ctx: TriggerContext) => Promise<void> | void;
    variants?: Array<{
        id: string;
        surface: PromptSurface;
    }>;
    variantSelector?: 'random' | 'epsilon_greedy' | 'thompson_sampling';
};
type FatigueConfig = {
    maxPerSession?: number;
    cooldownMs?: number;
    dismissPenalty?: {
        sameId?: 'session' | number;
        sameCategory?: number;
    };
    consecutiveDismissCap?: number;
};
type ProactiveOpts = {
    analytics?: AnalyticsLike;
    memory?: Memory;
    storage?: StorageKind;
    fatigue?: FatigueConfig;
    keys?: {
        yes?: string;
        no?: string;
        dismiss?: string;
    };
    identity?: () => Record<string, unknown>;
    /** Locale for the default Yes / No prompt labels when a prompt's
     *  surface doesn't supply its own. `en` / `zh-TW` ship bundled. */
    locale?: string;
    render?: (prompt: PromptDefinition, variantSurface: PromptSurface) => Promise<'yes' | 'no' | 'dismiss'>;
    /**
     * Behavior when the dddk palette (or a PanelSkill) is currently open.
     *
     * - `suppress` (default)     — do not trigger any proactive prompt
     * - `blur_palette`           — visually blur/dim the palette and overlay
     *                              the proactive prompt (host renderer choice)
     * - `subtitle_only`          — only show prompts via subtitle bar placement;
     *                              only Space counts as a response; any other
     *                              input is treated as "user didn't see it"
     *                              and palette flow continues unaffected.
     */
    whenPaletteOpen?: 'suppress' | 'blur_palette' | 'subtitle_only';
    /**
     * Callback that returns whether the palette is currently open. Wired by
     * dddk orchestrator (`isPaletteOpen()` / `isPanelOpen()`) so proactive can
     * respect palette state without a hard dependency on dddk's class.
     */
    isPaletteOpen?: () => boolean;
};
declare class Proactive {
    private prompts;
    private state;
    private storage;
    private analytics?;
    private memory?;
    private opts;
    private opened;
    private sessionShown;
    private sessionDismisses;
    private lastShownAt;
    private paused;
    constructor(opts?: ProactiveOpts);
    init(): Promise<void>;
    register(p: PromptDefinition): void;
    unregister(id: string): void;
    pause(): void;
    resume(): void;
    /** Evaluate all prompts; fire the highest-priority eligible one. Returns the prompt id if fired. */
    tick(ctx?: Omit<TriggerContext, 'now' | 'memory'>): Promise<string | undefined>;
    ask(opts: {
        text: string;
        yesLabel?: string;
        noLabel?: string;
    }): Promise<'yes' | 'no' | 'dismiss'>;
    explain(id: string): {
        promptId: string;
        lastShownAt: number;
        dismissedInSession: boolean;
        variantStats: Record<string, {
            yes: number;
            no: number;
            dismiss: number;
        }>;
        fatigue: {
            sessionShown: number;
            sessionDismisses: number;
            timeSinceLastShown: number;
        };
    } | undefined;
    private selectVariant;
    private fire;
    dispose(): Promise<void>;
}
declare const triggers: {
    dwell(opts: {
        ms: number;
        scope?: "page" | "session";
    }): Trigger;
    idleTime(opts: {
        ms: number;
    }): Trigger;
    scrollDepth(opts: {
        percent: number;
    }): Trigger;
    pageMatch(opts: {
        path: RegExp | string;
    }): Trigger;
    exitIntent(): Trigger;
    schedule(opts: {
        everyN: number;
    }): Trigger;
};
declare const builtin: {
    triggers: {
        dwell(opts: {
            ms: number;
            scope?: "page" | "session";
        }): Trigger;
        idleTime(opts: {
            ms: number;
        }): Trigger;
        scrollDepth(opts: {
            percent: number;
        }): Trigger;
        pageMatch(opts: {
            path: RegExp | string;
        }): Trigger;
        exitIntent(): Trigger;
        schedule(opts: {
            everyN: number;
        }): Trigger;
    };
};

declare function createProactive(opts?: ProactiveOpts): Proactive;

export { type AnalyticsLike, type FatigueConfig, type PieceNode, type PieceSurface, Proactive, type ProactiveOpts, type PromptDefinition, type PromptSurface, type SurfaceMountFn, type Trigger, type TriggerContext, builtin, createPieceRender, createProactive, triggers };
