/**
 * TelegramBridge — mirrors threadline messages into per-thread Telegram topics.
 *
 * The bridge gives Justin visibility into agent-to-agent conversations:
 * every inbound and outbound threadline message gets relayed into a
 * dedicated Telegram topic so he can watch the exchange in real time.
 *
 * **Relay-only.** The bridge is a pure observer — it never blocks, gates,
 * or vetoes a message. The blocking authority lives in TelegramBridgeConfig
 * (the dashboard toggles + allow/deny list). The bridge simply asks the
 * config "should I post?" and, if yes, posts.
 *
 * **No double-fire.** The bridge does NOT use the existing `telegram-reply`
 * pipeline (which is for agent → user replies). It writes directly through
 * the TelegramAdapter primitives `findOrCreateForumTopic` + `sendToTopic`,
 * and persists thread → topic bindings in
 * `.instar/threadline/telegram-bridge-bindings.json`.
 *
 * **Does NOT replace spawn-session.** The relay handler in server.ts still
 * spawns Claude Code sessions for inbound messages. The bridge runs
 * alongside that path; it's purely additive for user visibility.
 *
 * Topic naming: `{localAgent}↔{remoteAgentName} — {subject}` (truncated to
 * Telegram's 128-char limit). Subject defaults to the first ~40 chars of
 * the inbound message when no explicit subject is supplied.
 */
import type { TelegramBridgeConfig } from './TelegramBridgeConfig.js';
export declare const MAX_BRIDGE_MESSAGE_BODY = 3800;
export interface TelegramBridgeBinding {
    threadId: string;
    topicId: number;
    remoteAgent: string;
    topicName: string;
    createdAt: string;
    lastMessageAt: string;
}
export interface TelegramBridgeBindingsFile {
    version: 1;
    bindings: TelegramBridgeBinding[];
}
/** Subset of TelegramAdapter the bridge needs — keeps tests easy to mock. */
export interface TelegramSink {
    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<{
        ok: boolean;
        messageId?: number;
        reason?: string;
    } | unknown>;
}
export interface BridgeInboundEvent {
    threadId: string;
    remoteAgent: string;
    remoteAgentName?: string;
    text: string;
    subject?: string;
    messageId?: string;
    timestamp?: string;
}
export interface BridgeOutboundEvent {
    threadId: string;
    remoteAgent: string;
    remoteAgentName?: string;
    text: string;
    messageId?: string;
    timestamp?: string;
    /** Optional preview of the agent reply being mirrored (e.g. truncated body). */
    outcome?: string;
}
export interface TelegramBridgeOptions {
    stateDir: string;
    localAgentName: string;
    config: TelegramBridgeConfig;
    telegram: TelegramSink;
    /** Optional override for the bindings filename (testing). */
    bindingsFilename?: string;
    /** Logger; defaults to console. */
    log?: {
        info: (msg: string) => void;
        warn: (msg: string) => void;
        error: (msg: string) => void;
    };
}
export declare class TelegramBridge {
    private readonly stateDir;
    private readonly bindingsPath;
    private readonly localAgentName;
    private readonly cfg;
    private readonly telegram;
    private readonly log;
    private bindings;
    constructor(opts: TelegramBridgeOptions);
    private loadBindings;
    private persistBindings;
    /** Public for inspection (dashboard, observability tab). */
    getBindings(): TelegramBridgeBinding[];
    /** Public for the observability tab to query a single binding. */
    getBindingForThread(threadId: string): TelegramBridgeBinding | null;
    /** Build the topic name for a thread — used at create time. Exposed for tests. */
    buildTopicName(remoteAgentName: string, subject?: string): string;
    /**
     * Mirror an inbound threadline message into Telegram.
     *
     * Decision tree:
     *   1. If the bridge config disallows mirroring AND no existing topic
     *      → no-op.
     *   2. If a topic exists for this thread → post (subject to mirrorExisting).
     *   3. Else (no existing topic) → check shouldAutoCreateTopic; if yes,
     *      create + post; else no-op.
     *
     * Failure-tolerant — never throws. Returns `{posted, topicId}` for
     * observability.
     */
    mirrorInbound(evt: BridgeInboundEvent): Promise<{
        posted: boolean;
        topicId?: number;
        reason?: string;
    }>;
    /**
     * Mirror an outbound threadline message (sent via threadline_send) into
     * the corresponding Telegram topic. Outbound mirroring requires an
     * existing binding — outbound traffic alone never auto-creates topics
     * (the user opted in via inbound or by manual action).
     */
    mirrorOutbound(evt: BridgeOutboundEvent): Promise<{
        posted: boolean;
        topicId?: number;
        reason?: string;
    }>;
    private formatInboundBody;
    private formatOutboundBody;
    private postSafe;
}
//# sourceMappingURL=TelegramBridge.d.ts.map