import type { ContentMessageItemImage, ContentMessageItemResource, ContentMessageItemText, RecordFrameToolInput, TimelineEventCategory, TimelineRecording } from "#ai-utils";
import type { ReplayActionUploader } from "./replay-action-uploader";
interface TimelineCollectorOptions {
    framesDir: string;
    debug?: boolean;
    enableCdnUpload?: boolean;
}
interface CollectedFrame {
    image: ContentMessageItemImage;
    title: string;
    category: TimelineEventCategory;
    eventId: number;
    explicit: boolean;
    timestamp: number;
    fileName: string;
    imageUrl?: string;
    uploadPromise?: Promise<void>;
    cursorX?: number;
    cursorY?: number;
    viewportWidth?: number;
    viewportHeight?: number;
}
interface ProgressSnapshot {
    eventCount: number;
    frameCount: number;
    lastLabel: string;
    lastFrameFileName?: string;
    lastThinking?: string;
}
export interface StateEntry {
    ts: number;
    agentId: string;
    kind: "test_outcome";
    status?: "accepted" | "rejected";
    reason?: string;
    test_case_id?: string;
    [key: string]: any;
}
export declare class TimelineCollector {
    #private;
    constructor(sessionId: string, options: TimelineCollectorOptions);
    setReplayUploader(uploader: ReplayActionUploader): void;
    /**
     * Reset all collected state so the collector can be reused for a new recording cycle
     * (e.g., on reused QA branches that handle multiple review messages).
     */
    reset(): void;
    onToolCall(name: string, input: string): void;
    /** Stage the latest screenshot image so the paired RecordFrame can capture it. */
    onToolResult(result: {
        tool_name?: string;
        content: string | (ContentMessageItemText | ContentMessageItemImage | ContentMessageItemResource)[];
    }): void;
    onRecordFrame(input: RecordFrameToolInput): void;
    onThinking(content: string): void;
    getLastCapturedImage(): ContentMessageItemImage | null;
    getExplicitFrames(): Array<{
        image: ContentMessageItemImage | null;
        title: string;
    }>;
    getExplicitImages(): ContentMessageItemImage[];
    getAllImages(): ContentMessageItemImage[];
    getLegacyMetadataFrames(): Array<{
        hasImage: boolean;
        title: string;
    }>;
    getExplicitFrameDurations(): string[];
    getProgressSnapshot(): ProgressSnapshot;
    getEventCount(): number;
    getFrameCount(): number;
    getLastLabel(): string;
    hasExplicitFrames(): boolean;
    hasAnyFrames(): boolean;
    /**
     * Merge all events and frames from a child agent's timeline into this one.
     * Used to combine parallel executor timelines into a single planner recording.
     * Adds section markers and prefixes labels with the phase name.
     */
    mergeChildTimeline(child: TimelineCollector, label: string, opts?: {
        summary?: string;
        sessionId?: string;
        testCaseIds?: string[];
        replayId?: string;
    }): {
        startEventId: number;
        endEventId: number;
    };
    /** Merge a child executor's test plan into this timeline for recording submission. */
    mergeTestPlan(plan: {
        mode: string;
        test_cases: Array<{
            id: string;
            description?: string;
            title?: string;
            expected_outcome: string;
            priority: string;
        }>;
    }): void;
    /** Returns the merged test plan from child executors, if any. */
    getMergedTestPlan(): {
        mode: string;
        test_cases: Array<{
            id: string;
            description?: string;
            title?: string;
            expected_outcome: string;
            priority: string;
        }>;
    } | null;
    /** Merge child executor test case results into this timeline. Last write wins by test_case_id. */
    mergeTestCaseResults(results: Array<Record<string, any>>): void;
    /** Returns all merged test case results from child executors. */
    getMergedTestCaseResults(): Record<string, any>[];
    /**
     * Path to this collector's append-only state file. One JSONL line per
     * `ReportTestOutcome` call (accepted or rejected)
     */
    getStateFilePath(): string;
    /** Record a test outcome (accepted or rejected) to the state file. */
    onTestOutcome(input: Record<string, any>, status: "accepted" | "rejected", reason?: string): void;
    /**
     * Merge a child agent's state file into this one. Called from
     * mergeChildTimeline so parent's finalize() sees both own and child state.
     */
    mergeChildStateFile(childPath: string): void;
    /**
     * Read all state entries from disk. Used by finalize-from-disk on
     * crash recovery. Malformed lines are skipped silently.
     */
    readState(): StateEntry[];
    getHighlightFrames(): CollectedFrame[];
    getHighlightImages(): ContentMessageItemImage[];
    getHighlightMetadataFrames(): Array<{
        hasImage: boolean;
        title: string;
    }>;
    getHighlightFrameDurations(): string[];
    /**
     * Removes all local frame files and metadata for this session.
     * Safe to call after timeline has been persisted to the backend (frames are on CDN).
     */
    cleanupSessionFiles(): Promise<void>;
    finalize(): Promise<TimelineRecording>;
}
export {};
