import type { MessengerAdapter } from './types.js';
import { type ApprovalNotification, type Decision } from './approval-bus.js';
/**
 * Classify an inbound IM reply as an approval decision. Returns null when the
 * reply doesn't match any known pattern — the caller should treat that as
 * "user changed topic" and route normally.
 */
export declare function parseApprovalReply(text: string): Decision | null;
/**
 * Render an approval request as a plain text message. We keep this format
 * stable across IM platforms; richer flows (Feishu cards with buttons) can
 * layer on later by checking platform/sendCard.
 *
 * Two flavors:
 *   - Normal: y/n/all action box with timeout footer
 *   - Auto-allow grace mode (n.autoAllow set): "⏱ 自动放行中…" with deny option
 */
export declare function formatApprovalPrompt(n: ApprovalNotification): string;
/**
 * Map an IM platform name to its messenger registration. WeChat is special-
 * cased because the messenger is registered as "wechat-ilink" but messages
 * carry platform="wechat".
 */
export declare function platformToMessengerName(platform: string): string;
export interface InstallOptions {
    resolveMessenger: (platform: string) => MessengerAdapter | undefined;
    /** Optional. Platform names whose messengers should have button-callback
     *  support bound at install time. Adapters that don't implement
     *  onButtonCallback are silently skipped. Defaults to all known IM
     *  platforms; existing tests / callers don't need to pass this. */
    buttonCallbackPlatforms?: string[];
}
/**
 * Wire approval-bus.notifier to the messenger layer. Idempotent: calling
 * install() twice replaces the previous wiring.
 *
 * Notifier prefers the rich-card path (sendApprovalCard) when the resolved
 * adapter implements it; otherwise it falls back to the plain-text path
 * (sendMessage with formatApprovalPrompt). The text path is the canonical
 * approval channel for adapters without native interactive buttons (Feishu
 * cards aren't wired for buttons yet, WeChat iLink can't render them).
 *
 * Button callbacks: for each platform listed in buttonCallbackPlatforms
 * whose adapter implements onButtonCallback, we subscribe a handler that
 * parses callback_data of the form `apv:<reqId>:<y|n|a>` and resolves the
 * matching pending. Subscribing happens once at install — adapters started
 * later won't receive button wiring until install() is called again.
 */
export declare function install(opts: InstallOptions): void;
export declare function uninstall(): void;
/**
 * Bind the inline-button handler for a single platform's messenger. The
 * install() loop calls this for every default platform at boot; callers
 * (e.g. web/server.ts) that register their messenger AFTER install have
 * to call this themselves to get button-click → resolvePending wiring.
 *
 * Idempotent at the messenger level — onButtonCallback's contract is
 * "replace previous handler", so re-calling this on the same platform
 * just rewires.
 *
 * Silent no-op when the messenger isn't registered yet, has no
 * onButtonCallback, or the router hasn't been install()'d.
 */
export declare function bindButtonHandlerForPlatform(platform: string): void;
/**
 * Called by cli's onMessage handler before it routes to the agent.
 * Returns true when this message was an approval reply (so the caller should
 * stop and not invoke the normal router).
 *
 * Behavior:
 *   - If thread has no pending approval → return false, do nothing
 *   - If thread has pending AND text parses as decision → resolve, return true
 *   - If thread has pending AND text does NOT parse → auto-deny pending
 *     (user is moving on), return false so the message routes normally
 *
 * Receipt: when the resolution adds or revokes an auto-allow rule, also
 * sends a one-line confirmation back to the IM thread so the user knows
 * the rule landed (or got cleared). Best-effort: a missing messenger or
 * sendMessage failure is logged and ignored — the approval itself already
 * resolved successfully.
 */
/**
 * Called by cli's onMessage handler before it routes to the agent.
 * `key` must be a composite key from `threadKey(platform, channelId, threadId)`
 * — same value the bus stored under at registerRun/registerSyntheticPending
 * time. A bare threadId will miss in multi-platform deployments.
 */
export declare function tryHandleApprovalReply(key: string, text: string): boolean;
/**
 * Parse callback_data of the form `apv:<reqId>:<y|n|a>`. reqId may itself
 * contain characters but never `:` in practice (UUID / opaque sidecar id);
 * we still split on the LAST colon to be safe, leaving the choice as the
 * single trailing letter.
 */
export declare function parseCallbackData(data: string): {
    reqId: string;
    choice: 'y' | 'n' | 'a';
} | null;
/** Test helper — not exported from index. */
export declare function _isInstalled(): boolean;
//# sourceMappingURL=approval-router.d.ts.map