import { StatelogClient } from "../../statelogClient.js";
import { MessageThread, MessageThreadJSON } from "./messageThread.js";
export type ThreadStoreJSON = {
    threads: Record<string, MessageThreadJSON>;
    counter: number;
    activeStack: string[];
    /** session-name → thread-id map. Populated by openSession on first
     *  entry; subsequent entries with the same name resume the recorded
     *  thread via resumeExisting. Round-tripped so sessions survive
     *  interrupt resume / cross-node hops. */
    sessions?: Record<string, string>;
};
export type MessageThreadID = string;
export declare class ThreadStore {
    threads: Record<MessageThreadID, MessageThread>;
    counter: number;
    activeStack: MessageThreadID[];
    /** session-name → thread-id. See ThreadStoreJSON.sessions for docs.
     *  Backed by `Object.create(null)` so user-supplied session names
     *  like `"__proto__"` or `"constructor"` cannot mutate the
     *  Object prototype (prototype pollution). */
    sessions: Record<string, MessageThreadID>;
    private statelogClient?;
    constructor();
    setStatelogClient(client: StatelogClient): void;
    static withDefaultActive(client?: StatelogClient): ThreadStore;
    create(): MessageThreadID;
    createAndReturnThread(): MessageThread;
    createSubthread(): MessageThreadID;
    createAndReturnSubthread(): MessageThread;
    get(id: MessageThreadID): MessageThread;
    pushActive(id: MessageThreadID): void;
    popActive(): MessageThreadID | undefined;
    activeId(): MessageThreadID | undefined;
    active(): MessageThread | undefined;
    getOrCreateActive(): MessageThread;
    /** Re-activate a previously-closed thread. Pushes `id` onto the
     *  active stack (same path as pushActive) without creating a new
     *  MessageThread. Throws if `id` is unknown — a silent fallback to
     *  create-new would mask a real bug (typo, hallucinated id) at the
     *  call site.
     *
     *  v1: rejects subthreads. A subthread's identity is tied to its
     *  parent's context at the time it was created; resuming one
     *  outside that context could surface confusing message ordering.
     *  If a user wants to continue inside a subthread, they should
     *  resume the parent thread and open a fresh `subthread {}` block.
     */
    resumeExisting(id: MessageThreadID): void;
    /** Open a named session. Returns `{id, existed}` — `existed` is
     *  `true` when this name already mapped to a thread. Always leaves
     *  the session's thread on top of `activeStack`. First entry
     *  creates a top-level thread (never a subthread); later entries
     *  resume via `resumeExisting` (which already rejects subthreads —
     *  sessions can only map to top-level threads). */
    openSession(name: string): {
        id: MessageThreadID;
        existed: boolean;
    };
    toJSON(): ThreadStoreJSON;
    static fromJSON(json: ThreadStoreJSON | ThreadStore): ThreadStore;
}
