/**
 * Slack-Orchestrator Bridge
 *
 * Routes messages between Slack and the Crewly orchestrator,
 * enabling mobile control of AI teams.
 *
 * @module services/slack/bridge
 */
import { EventEmitter } from 'events';
import { SlackNotification, ParsedSlackCommand } from '../../types/slack.types.js';
import type { MessageQueueService } from '../messaging/message-queue.service.js';
import type { SlackThreadStoreService } from './slack-thread-store.service.js';
import type { ThreadStatusQueueService } from '../messaging/thread-status-queue.service.js';
/**
 * Bridge configuration
 */
export interface SlackBridgeConfig {
    /** Orchestrator session name */
    orchestratorSession: string;
    /** Enable typing indicators */
    showTypingIndicator: boolean;
    /** Maximum response length before truncation */
    maxResponseLength: number;
    /** Enable proactive notifications */
    enableNotifications: boolean;
    /** Response timeout in ms */
    responseTimeoutMs: number;
    /** Time to wait for reply-slack skill before fallback delivery (ms) */
    skillDeliveryWaitMs: number;
}
/**
 * Pure pre-fetch gates for auto-Request suppression (Patch D). Exported for
 * focused unit testing — the full thread-continuation gate also lives in
 * {@link SlackOrchestratorBridge.shouldSuppressAutoRequest} but requires a
 * RequestService lookup so cannot be a pure function.
 *
 * Each function returns the suppression reason string (matches the values
 * logged at debug level) or `null` when the gate does not match.
 */
export declare function suppressTrivialOrShort(rawText: string): string | null;
export declare function suppressFileOnly(rawText: string): string | null;
/**
 * Derive a short, readable chat-v2 channel name from a Slack thread's first
 * message — so the consolidated chat shows a meaningful title rather than the
 * synthesized `slack-<chan>-<ts>` id (which is identical across a channel's
 * threads). Collapses whitespace and truncates; falls back to "Slack thread".
 *
 * @param content - The first inbound message of the thread.
 * @returns A title like `Slack: ship the v2 launch deck`.
 */
export declare function deriveSlackThreadName(content: string | undefined): string;
/**
 * SlackOrchestratorBridge class
 *
 * Routes messages between Slack and the Crewly orchestrator.
 * Handles command parsing, response formatting, and proactive notifications.
 *
 * @example
 * ```typescript
 * const bridge = getSlackOrchestratorBridge();
 * await bridge.initialize();
 *
 * // Send notification when task completes
 * await bridge.notifyTaskCompleted('Fix bug', 'Developer', 'MyProject');
 * ```
 */
export declare class SlackOrchestratorBridge extends EventEmitter {
    private logger;
    private slackService;
    private chatV2;
    private messageQueueService;
    private threadStatusQueue;
    private threadStore;
    private config;
    private initialized;
    /** Track if we've already logged the missing scope warning */
    private loggedMissingScope;
    /**
     * Pending completion reactions keyed by "channelId:threadTs".
     * Stores the original message ts so that the ✅ reaction is added to the
     * correct message when the reply-slack skill delivers a response.
     */
    private pendingReactions;
    /**
     * Track channel+thread pairs where Slack delivery was already handled
     * by the reply-slack skill (execute.sh). Used by sendSlackResponse to
     * avoid sending a duplicate fallback message to the same thread.
     */
    /**
     * Create a new SlackOrchestratorBridge
     *
     * @param config - Partial configuration to override defaults
     */
    constructor(config?: Partial<SlackBridgeConfig>);
    /**
     * Initialize the bridge
     *
     * Sets up message listeners and orchestrator subscriptions.
     *
     * @returns Promise that resolves when initialized
     */
    initialize(): Promise<void>;
    /**
     * Check if bridge is initialized
     *
     * @returns True if initialized
     */
    isInitialized(): boolean;
    /**
     * Set the message queue service for enqueuing messages to the orchestrator.
     * Called during server initialization.
     *
     * @param service - The MessageQueueService instance
     */
    setMessageQueueService(service: MessageQueueService): void;
    /**
     * Set the thread status queue service for tracking inbound message lifecycle.
     * Called during server initialization.
     *
     * @param service - The ThreadStatusQueueService instance
     */
    setThreadStatusQueue(service: ThreadStatusQueueService): void;
    /**
     * Set the Slack thread store service for persisting thread conversations.
     * Called during server initialization.
     *
     * @param store - The SlackThreadStoreService instance
     */
    setSlackThreadStore(store: SlackThreadStoreService): void;
    /**
     * Get current configuration
     *
     * @returns A copy of the current configuration
     */
    getConfig(): SlackBridgeConfig;
    /**
     * Handle incoming Slack message
     *
     * Parses the command, routes to appropriate handler, and sends response.
     *
     * @param message - Incoming Slack message
     */
    private handleSlackMessage;
    /**
     * Handle an incoming cross-machine message.
     * Routes the message payload to the local orchestrator via the message queue.
     *
     * @param msg - Parsed cross-machine message
     */
    private handleCrossMachineMessage;
    /**
     * Parse command from message text
     *
     * Cleans the message and extracts the command intent.
     *
     * @param text - Raw message text
     * @returns Parsed command with intent and parameters
     */
    parseCommand(text: string): ParsedSlackCommand;
    /**
     * Extract parameters from command text
     *
     * @param text - Command text
     * @returns Extracted parameters
     */
    private extractParameters;
    /**
     * Get help message
     *
     * @returns Formatted help message for Slack
     */
    getHelpMessage(): string;
    /**
     * Determine whether an inbound Slack message should be suppressed from
     * auto-Request creation. Returns a reason string when the message should
     * be skipped, or `null` when a Request should be created normally.
     *
     * Three gates (Pipeline-#4 fix, spec
     * 2026-05-05-request-decompose-pipeline-gap.md, Patch D):
     *
     *   1. **Length / acknowledgement gate.** Trimmed text is shorter than
     *      {@link MIN_AUTO_REQUEST_TEXT_LENGTH} OR matches the trivial
     *      acknowledgement allowlist ({@link TRIVIAL_ACK_PATTERN}). Catches
     *      "好的", "ok", "👍", "thx" — class noise that is never actionable.
     *
     *   2. **Thread continuation gate.** When the inbound message is a reply
     *      inside an existing thread (`message.threadTs` ≠ `message.ts`) AND a
     *      Request already exists for the **parent** message, suppress to
     *      prevent every "are we still in this thread?" follow-up from creating
     *      a new sibling Request. Existing Request continues to receive
     *      orchestrator routing.
     *
     *   3. **File-only / synthetic-title gate.** Messages whose text is a
     *      synthetic `[Slack File: …]` placeholder with no narrative are
     *      artefacts of slack-bridge file-handling, not user requests.
     *
     * Each gate returns a stable reason string for log auditability. The
     * caller logs at `debug` so suppression decisions are observable without
     * noise.
     *
     * @param message - The incoming Slack message (already validated)
     * @param rawText - The raw text body, trimmed by caller if needed
     * @param svc - The RequestService instance for the thread-continuation lookup
     * @returns A reason string when suppressed; `null` when allowed
     */
    private shouldSuppressAutoRequest;
    /**
     * Handle status command
     *
     * @param command - Parsed command
     * @param context - Conversation context
     * @returns Status response
     */
    private handleStatusCommand;
    /**
     * Handle list commands (projects, teams, agents)
     *
     * @param command - Parsed command
     * @param context - Conversation context
     * @returns List response
     */
    private handleListCommand;
    /**
     * Handle control commands (pause, resume)
     *
     * @param command - Parsed command
     * @param context - Conversation context
     * @returns Control response
     */
    private handleControlCommand;
    /**
     * Attempt to auto-recover the orchestrator with a hard timeout.
     *
     * Calls `triggerOrchestratorSetup()` from the orchestrator service module
     * directly (bypassing HTTP). Wraps the attempt in a 5-second deadline so
     * a wedged setup cannot stall the Slack message ingress thread.
     *
     * Behavior:
     * - Timeout: rejects with a TimeoutError-like message after 5s.
     * - Setup error: rejects with the underlying error.
     * - Setup returning `success: false`: rejects with the recorded error
     *   (the caller treats this the same as a thrown error and falls
     *   through to the offline path).
     *
     * Caller is expected to wrap the call in try/catch and continue down
     * the offline path on rejection — auto-recovery is best-effort.
     *
     * @returns Resolves when setup completes successfully (or was skipped
     *          because the orc was already healthy)
     * @throws Error on timeout or setup failure
     * @internal Visible for tests via class member access.
     */
    private attemptAutoRecovery;
    /**
     * Send message to orchestrator via the message queue and wait for response.
     *
     * Checks if the orchestrator is active before sending. Enqueues the message
     * and waits for the response via a resolve callback injected into sourceMetadata.
     *
     * @param message - Message to send
     * @param context - Optional conversation context
     * @returns Orchestrator response or offline/error message
     */
    private sendToOrchestrator;
    /**
     * Route a message to the Auditor agent as a fallback when the orchestrator is offline.
     *
     * Enqueues the message targeting the Auditor's session so the queue processor
     * delivers it to the Auditor PTY instead of the orchestrator. Includes Slack
     * context (channel, thread) so the Auditor can respond.
     *
     * **Thread file enrichment (parity with `sendToOrchestrator` ~line 712):**
     * When a `threadStore` and Slack `context` are available, the enriched
     * message also carries a `[Thread context file: <path>]` line. Without
     * this, the Auditor receives only the bare `[SLACK_CONTEXT:...]` prefix
     * and cannot read prior thread history, causing context-blind replies.
     * This is the bug Steve hit on 2026-04-25 (StevesPrompt deploy thread):
     * orchestrator dropped, Slack fell through here, Auditor responded with
     * "I cannot see the rest of the conversation" because the thread file
     * pointer was missing. Bringing the enrichment in line with the
     * orchestrator path closes the gap.
     *
     * @param message - Original user message
     * @param context - Slack conversation context
     * @returns Acknowledgement message to the user
     */
    private sendToAuditorFallback;
    /**
     * Refresh file download URLs via the Slack files.info API.
     * The event payload URLs may not work with just the bot token — the
     * files.info API returns authenticated URLs and validates scope.
     *
     * @param files - Slack file objects to refresh URLs for (mutated in place)
     * @returns true if downloads can proceed, false if scope is missing
     */
    private refreshFileUrls;
    /**
     * Download image files from a Slack message using SlackImageService.
     * Populates `message.images` with successfully downloaded image info.
     * Downloads are batched with a concurrency limit of MAX_CONCURRENT_DOWNLOADS.
     *
     * @param message - Incoming message to attach downloaded images to
     * @param imageFiles - Pre-filtered list of image files to download
     */
    private downloadMessageImages;
    /**
     * Download non-image file attachments from a Slack message.
     * Uses authenticated fetch (same pattern as SlackImageService) to download
     * files to a temp directory. Populates `message.attachments` with results.
     * Skips magic-byte validation since these are generic files.
     *
     * @param message - Incoming message to populate with downloaded file info
     * @param nonImageFiles - Non-image SlackFile objects to download
     */
    private downloadMessageFiles;
    /**
     * Enrich message text with file path references so agents
     * can read them via their file-reading tools (Claude Code Read, Gemini @file).
     * Includes both images and non-image file attachments.
     *
     * @param message - Message with optional downloaded images and files
     * @returns Enriched text with file references appended
     */
    private enrichTextWithFiles;
    /**
     * Extract text content from a downloaded PDF file.
     * Returns undefined if extraction fails or produces no text.
     *
     * @param filePath - Absolute path to the downloaded PDF
     * @param fileName - Original file name (for logging)
     * @returns Extracted text (possibly truncated) or undefined
     */
    extractPdfText(filePath: string, fileName: string): Promise<string | undefined>;
    /**
     * Add typing indicator to message
     *
     * @param message - Message to add indicator to
     */
    private addTypingIndicator;
    /**
     * Mark message as complete
     *
     * @param message - Message to mark complete
     */
    private markComplete;
    /**
     * Add a completion reaction (✅) to a message that was previously
     * stored as a pending reaction. Consumes the pending reaction.
     *
     * @param channelId - Slack channel ID
     * @param threadTs - Thread timestamp (key for lookup)
     */
    addCompletionReaction(channelId: string, threadTs: string): Promise<void>;
    /**
     * Record response to thread store. Slack delivery is handled exclusively
     * by the reply-slack skill via the API — no terminal output fallback needed.
     *
     * The `fromOrcReply` flag gates the V3 SLA auto-resolve hook
     * (`markResolvedByThread`). Only real orc replies (delivered via the
     * orc's reply-slack skill → `slackResolve` callback) may auto-resolve
     * the SLA tracker. Placeholder / timeout / offline / fallback responses
     * must NOT trigger the cascade — doing so closes the parent Request to
     * `done` even though the orc never actually replied (Steve 2026-04-30
     * incident: false-done Request, paired with Bug 1 silent-drop in
     * agent-registration.service.ts).
     *
     * Default `fromOrcReply = true` preserves the legacy behaviour for the
     * mention-routing call site (line ~327) which currently has no
     * placeholder semantics — its `sendToAgent` path delivers a direct
     * agent reply when reachable. If that path later grows a timeout
     * fallback, the call site should pass `false` explicitly.
     *
     * @param originalMessage - Original incoming message
     * @param response        - Response content (real reply or placeholder)
     * @param fromOrcReply    - `true` only when the response came from a
     *   real agent/orc reply path. `false` for any timeout / fallback /
     *   offline acknowledgement. Drives whether the SLA tracker is
     *   auto-resolved for the matching Slack thread.
     */
    private sendSlackResponse;
    /**
     * Send error response
     *
     * @param message - Original message
     * @param error - Error that occurred
     */
    private sendErrorResponse;
    /**
     * Format response for Slack
     *
     * Converts markdown to Slack-compatible formatting.
     *
     * @param text - Text to format
     * @returns Formatted text
     */
    formatForSlack(text: string): string;
    /**
     * Persist Slack reply content to the thread store when available.
     */
    private recordThreadReply;
    /**
     * Send proactive notification to Slack
     *
     * @param notification - Notification to send
     */
    sendNotification(notification: SlackNotification): Promise<void>;
    /**
     * Send a content approval notification to Slack with Block Kit buttons.
     *
     * Posts a rich message with content preview and approve/reject buttons.
     * Links the Slack message back to the approval record so interactive
     * button clicks can resolve the approval.
     *
     * @param approvalId - The content approval ID
     * @param channelId - Slack channel ID
     * @param threadTs - Optional thread timestamp
     * @returns The Slack message timestamp, or null if failed
     */
    sendContentApproval(approvalId: string, channelId?: string, threadTs?: string): Promise<string | null>;
    /**
     * Notify about task completion
     *
     * @param taskTitle - Title of completed task
     * @param agentName - Name of agent that completed the task
     * @param projectName - Name of the project
     */
    notifyTaskCompleted(taskTitle: string, agentName: string, projectName: string): Promise<void>;
    /**
     * Notify about agent needing assistance
     *
     * @param agentName - Name of agent with question
     * @param question - The question from the agent
     * @param projectName - Name of the project
     */
    notifyAgentQuestion(agentName: string, question: string, projectName: string): Promise<void>;
    /**
     * Notify about errors
     *
     * @param errorMessage - Error message
     * @param agentName - Optional agent name
     * @param projectName - Optional project name
     */
    notifyError(errorMessage: string, agentName?: string, projectName?: string): Promise<void>;
    /**
     * Notify about daily summary
     *
     * @param summary - Summary content
     */
    notifyDailySummary(summary: string): Promise<void>;
    /**
     * Resolve @mention in message text to an agent session (#177).
     *
     * Matches patterns: @assistant, @auditor, @sam, @leo, etc.
     * Looks up the agent name in team configs to find the session name.
     *
     * @param text - Message text to scan for @mentions
     * @returns Target agent info, or null if no mention found
     */
    private resolveMentionTarget;
    /**
     * Send a message to a specific agent session via terminal deliver (#177).
     *
     * @param sessionName - Target agent session
     * @param message - Message to send
     * @param context - Slack context for response routing
     * @returns OrcResponse envelope — `fromOrcReply` is `true` ONLY when the
     *   reply came from the agent's `slackResolve` callback (a real reply
     *   via the reply-slack skill). Timeout / direct-delivery / error
     *   placeholders return `fromOrcReply: false` so callers can gate the
     *   SLA cascade. Issue #394.
     */
    private sendToAgent;
    /**
     * Persist a Slack inbound user message to chat-v2 and return the
     * `(conversationId, messageId)` pair callers thread downstream
     * into `MessageQueueService.enqueue` and `ThreadStatusQueueService.trackInbound`.
     *
     * Phase 6c of unified-chat-message-store spec: replaces the
     * legacy `chatService.sendMessage` call sites on this bridge.
     * Synthesizes a stable conversationId from Slack channel + thread
     * ts when the caller didn't supply one, so re-enqueue paths
     * (offline replay, recovery) reuse the same channel.
     *
     * @param args - Persistence inputs (content + slack context + recipient agent)
     * @returns The chat-v2 channelId and the freshly persisted messageId
     */
    private persistSlackInbound;
}
/**
 * Get bridge singleton
 *
 * @returns SlackOrchestratorBridge instance
 */
export declare function getSlackOrchestratorBridge(): SlackOrchestratorBridge;
/**
 * Reset bridge (for testing)
 */
export declare function resetSlackOrchestratorBridge(): void;
//# sourceMappingURL=slack-orchestrator-bridge.d.ts.map