/**
 * CollaborationSurfacer — the single funnel for making Threadline activity
 * visible to the operator WITHOUT spawning a topic per event (CMT-509 §2 +
 * CMT-519 notification routing).
 *
 * Routing spine (operator directives 2026-05-25):
 *  - A conversation WITH a parent topic surfaces THERE via TopicLinkageHandler —
 *    this surfacer does NOT touch its *content* (real replies).
 *  - A PARENTLESS conversation (a peer reached out cold) surfaces to a SINGLE
 *    dedicated "Threadline" Telegram topic — created on demand once and reused,
 *    NEVER the generic attention list, NEVER a per-thread/per-event topic.
 *  - STATUS / housekeeping notices (loop-gate wind-down, etc. — `notify()`) go to
 *    that SAME silent hub, NEVER the parent topic the operator is working in (D1).
 *
 * Near-silent by design (D2): the hub is SILENT — agent-to-agent activity does
 * not buzz the operator and is never framed as "waiting for you" (it isn't the
 * operator's job by default). The hub is a calm, browsable record; the operator
 * engages it on their own schedule ("open this" / "tie this to <topic>"). The
 * only thing that breaks silence is a genuine user-facing escalation, which
 * surfaces normally via its parent topic — not through this surfacer.
 *
 * One post per parentless conversation (`surface()` dedupes per thread). Never
 * emits raw envelope/JSON.
 */
export interface SurfacerTelegram {
    findOrCreateForumTopic(name: string, iconColor?: number, opts?: {
        origin?: 'user' | 'system' | 'auto';
        label?: string;
    }): Promise<{
        topicId: number;
        name: string;
        reused: boolean;
    }>;
    sendToTopic(topicId: number, text: string, options?: {
        silent?: boolean;
        skipStallClear?: boolean;
    }): Promise<unknown>;
}
export interface CollaborationSurfacerConfig {
    telegram: SurfacerTelegram;
    stateDir: string;
    /** Override the state filename (tests). */
    stateFilename?: string;
    /** Dedicated topic display name. */
    topicName?: string;
    log?: {
        warn: (m: string) => void;
    };
}
export interface SurfaceInput {
    threadId: string;
    senderName: string;
    text: string;
    /** True if the conversation is bound to a parent topic (→ surfaced elsewhere). */
    hasParentTopic: boolean;
    /** The warrants-a-reply gate verdict (substantive content). */
    warrants: boolean;
}
export interface SurfaceResult {
    surfaced: boolean;
    reason: string;
    topicId?: number;
}
/** A STATUS / housekeeping notice (loop-gate, etc.) — hub-only, never parent. */
export interface NotifyInput {
    threadId: string;
    title: string;
    body: string;
    peerName?: string;
}
/** Per-conversation record in the hub (replaces the legacy string[] of threadIds). */
export interface SurfacedThreadRecord {
    threadId: string;
    peerName: string;
    subject?: string;
    surfacedAt: string;
    bound: boolean;
}
export declare class CollaborationSurfacer {
    private telegram;
    private filePath;
    private topicName;
    private log;
    constructor(config: CollaborationSurfacerConfig);
    /**
     * Surface a PARENTLESS first-contact conversation to the silent hub. Idempotent
     * per thread. Never throws (best-effort; must not break the inbound path).
     */
    surface(input: SurfaceInput): Promise<SurfaceResult>;
    /**
     * Post a STATUS / housekeeping notice to the SILENT hub. Used by threadline
     * subsystems (loop-gate wind-down, etc.) INSTEAD of `createAttentionItem` —
     * so they never spawn a per-event topic and never clutter the parent topic
     * the operator is working in (D1). Silent (D2). Never throws.
     */
    notify(input: NotifyInput): Promise<SurfaceResult>;
    /** The dedicated hub topic id, if one has been created. */
    getHubTopicId(): number | undefined;
    /**
     * The most-recently-surfaced conversation not yet bound to its own topic —
     * the default target for a bare "open this" in the hub. Returns null when the
     * choice is ambiguous (>1 unbound) so the caller can ask the operator which.
     */
    mostRecentUnbound(): {
        record: SurfacedThreadRecord | null;
        ambiguous: boolean;
    };
    /** Mark a surfaced conversation as bound (after "open this" / "tie this to X"). */
    markBound(threadId: string): void;
    /** Post a one-line note into the hub (e.g. "Opened → topic <name>"). */
    noteInHub(text: string): Promise<void>;
    private ensureHubTopic;
    /** A readable, capped gist — NEVER raw envelope/JSON. */
    private readableGist;
    private readablePeer;
    /**
     * Load state with a READ-TIME MIGRATION from the legacy `surfacedThreads:
     * string[]` shape to the `surfaced: SurfacedThreadRecord[]` shape. A legacy
     * file's threadIds become bound:false records with an unknown peer.
     */
    private load;
    private trimAndSave;
}
//# sourceMappingURL=CollaborationSurfacer.d.ts.map