import { CrewlyAgentExternalRuntimeService } from './crewly-agent/crewly-agent-external-runtime.service.js';
import { StorageService } from '../core/storage.service.js';
import { CREWLY_CONSTANTS, RuntimeType } from '../../constants.js';
export interface OrchestratorConfig {
    sessionName: string;
    projectPath: string;
    windowName?: string;
}
/**
 * Error thrown when an agent role cannot be resolved to a valid value.
 *
 * Indicates a member with no `role` field in storage, or a caller passing
 * `undefined`/empty/literal-"undefined". Surfaces the failure loudly so it
 * cannot manifest as the silent "empty Claude prompt" symptom (Bug #1).
 */
export declare class InvalidAgentRoleError extends Error {
    readonly received: unknown;
    constructor(received: unknown, context?: string);
}
/**
 * Validate that an agent role is a usable string before it flows into session
 * creation, env-var injection, or prompt-template path resolution.
 *
 * Rejects: undefined, null, non-strings, empty/whitespace strings, and the
 * literal string "undefined" (which results from JS coercion when an undefined
 * is interpolated into a template literal — the exact failure mode behind
 * `CREWLY_ROLE="undefined"` in tmux env).
 *
 * @param role - The candidate role value
 * @param context - Optional caller context for the error message (e.g. "startTeamMember")
 * @throws {InvalidAgentRoleError} when role is unusable
 */
export declare function validateAgentRole(role: unknown, context?: string): asserts role is string;
/**
 * Service responsible for the complex, multi-step process of agent initialization and registration.
 * Isolates the complex state management of agent startup with progressive escalation.
 *
 * Key capabilities:
 * - Agent session creation and management
 * - Runtime initialization and registration
 * - Reliable message delivery to Claude Code with retry logic
 * - Health checking and status management
 */
export declare class AgentRegistrationService {
    private logger;
    private _sessionHelper;
    private storageService;
    private projectRoot;
    private promptCache;
    private sessionCreationLocks;
    private registrationAbortControllers;
    private stuckMessageDetectorTimer;
    private tuiSessionRegistry;
    private sentMessageTracker;
    private sessionDeliveryMutex;
    private lastSentMessageHash;
    private inProcessRuntimes;
    /** #167: Optional scheduler service for DLQ drain on agent activation. */
    private schedulerService;
    /** Architecture Upgrade Phase 6: EventBusService for standing task subscriptions. */
    private eventBusService;
    private static get CLAUDE_PROMPT_INDICATORS();
    constructor(_legacyTmuxService: unknown, // Legacy parameter for backwards compatibility
    projectRoot: string | null, storageService: StorageService);
    /**
     * #167: Inject scheduler service for dead-letter queue drain on agent activation.
     *
     * @param scheduler - Scheduler service with drainDeadLetterQueue method
     */
    setSchedulerService(scheduler: {
        drainDeadLetterQueue(sessionName: string): Promise<number>;
    }): void;
    /**
     * Inject EventBusService for standing task workflow subscriptions at agent registration.
     *
     * @param eventBus - EventBusService instance with subscribe method
     */
    setEventBusService(eventBus: {
        subscribe(input: import('../../types/event-bus.types.js').CreateSubscriptionInput): import('../../types/event-bus.types.js').EventSubscription;
    }): void;
    /**
     * Cancel a pending registration prompt for a session.
     * Called by RuntimeExitMonitorService when a runtime exit is detected.
     *
     * @param sessionName - The session whose registration to cancel
     */
    cancelPendingRegistration(sessionName: string): void;
    /**
     * Get or create the session helper with lazy initialization
     */
    private getSessionHelper;
    /**
     * Get session helper synchronously (may throw if not initialized)
     */
    private getSessionHelperSync;
    /**
     * Resolve the runtime type for a session from storage.
     * Checks orchestrator status first, then team member data.
     * Falls back to CLAUDE_CODE if nothing is found.
     *
     * IMPORTANT: Callers should prefer passing runtimeType explicitly.
     * This method exists as a safety net so that Ctrl+C (Claude Code
     * cleanup) is never sent to a Gemini CLI session, which would
     * trigger /quit and kill the agent.
     */
    private resolveSessionRuntimeType;
    /**
     * Route a crewly-agent in-process response to the originating chat conversation.
     *
     * PTY-based runtimes emit [NOTIFY] markers that the terminal gateway parses.
     * In-process crewly-agents have no terminal output, so this method provides
     * the equivalent routing for their text responses.
     *
     * @param sessionName - Agent session that produced the response
     * @param text - Response text from the agent
     * @param conversationId - Chat conversation to route the response to
     */
    private routeInProcessResponseToChat;
    /**
     * Auto-route an in-process agent's text response back to Slack.
     *
     * Mirrors the post-send side effects of POST /slack/send so that the
     * Slack reply, thread-status bookkeeping, and V3 SLA cascade all stay in
     * sync. Used as a finish-event hook for the in-process Crewly Agent
     * runtime when:
     *   1. The inbound message carried a `[SLACK:channelId:threadTs]` marker
     *   2. The agent produced text output (`result.text` non-empty)
     *   3. The agent did NOT explicitly call the `reply_slack` tool
     *
     * Without this hook, AI SDK agents that finish with `toolCalls=0,
     * finishReason=stop` would drop their reply on the floor — unlike the
     * claude-code PTY path, the in-process runtime has no stdout stream the
     * SlackBridge can tail.
     *
     * Best-effort: a Slack-not-connected condition or a downstream
     * bookkeeping failure is logged and swallowed; never throws. The chat
     * route (`routeInProcessResponseToChat`) handles persistence to the chat
     * service separately.
     *
     * @param sessionName - Agent session that produced the response
     * @param text - Response text from the agent
     * @param slackContext - Slack channel + thread metadata captured from the
     *                       inbound `[SLACK:channelId:threadTs]` marker
     */
    private routeInProcessResponseToSlack;
    /**
     * Find the project root by looking for package.json
     */
    private findProjectRoot;
    /**
     * Resolve runtime flags from the agent's effective skills.
     * Reads role config and skill configs to collect flags compatible with the runtime.
     *
     * @param role - The agent's role name
     * @param runtimeType - The agent's runtime type (e.g. 'claude-code')
     * @param skillOverrides - Additional skills assigned to the member
     * @param excludedRoleSkills - Skills excluded from the role's default set
     * @returns Array of CLI flags to inject (e.g. ['--chrome'])
     */
    private resolveRuntimeFlags;
    /**
     * Search known skill directories for a skill's skill.json file.
     * Skills live under `config/skills/agent/core/` or `config/skills/agent/marketplace/`.
     *
     * @param skillId - The skill identifier (directory name)
     * @returns Absolute path to skill.json, or null if not found
     */
    private findSkillJsonPath;
    /**
     * Create a runtime service instance for the given runtime type.
     * Centralizes RuntimeServiceFactory creation to reduce code duplication.
     */
    private createRuntimeService;
    /**
     * Get an in-process Crewly Agent runtime by session name.
     * Used by the terminal controller for force-delivery to in-process agents.
     *
     * @param sessionName - Session name to look up
     * @returns The CrewlyAgentExternalRuntimeService if it exists, undefined otherwise
     */
    getInProcessRuntime(sessionName: string): CrewlyAgentExternalRuntimeService | undefined;
    /**
     * Check if an in-process Crewly Agent runtime is active and ready for a given session.
     *
     * Used by team status resolution to correctly report active status for
     * crewly-agent runtimes that have no PTY session.
     *
     * @param sessionName - The session name to check
     * @returns True if an in-process runtime exists and is ready
     */
    isInProcessRuntimeActive(sessionName: string): boolean;
    /**
     * Get the check interval based on environment.
     * Uses shorter intervals in test environment for faster tests.
     */
    private getCheckInterval;
    /**
     * Update agent status with safe error handling (non-blocking).
     * Returns true if successful, false if failed.
     */
    private updateAgentStatusSafe;
    /**
     * Role aliases — common synonyms users naturally type in team configs
     * mapped to the canonical directory name under `config/roles/`. Without
     * these, a team-config role like `"tech-lead"` would fall through to a
     * non-existent directory and trigger the ENOENT fallback path on every
     * agent registration (Steve 2026-05-15 dogfood: CE team config used
     * `role: "tech-lead"` while the canonical directory is `team-leader`,
     * producing a steady drip of "Could not load prompt from config" warns
     * for every member-start with no actionable resolution short of editing
     * user data).
     *
     * Keep keys lowercased + dash-normalized (matches the post-normalization
     * shape used by `getPromptFileForRole`).
     */
    private static readonly ROLE_DIR_ALIASES;
    /**
     * Get prompt file path for a specific role
     * Uses the unified config/roles/{role}/prompt.md structure
     */
    private getPromptFileForRole;
    /**
     * Initialize agent with optimized 2-step escalation process
     * Reduced from 4-step to 2-step with shorter timeouts for better concurrency
     */
    initializeAgentWithRegistration(sessionName: string, role: string, projectPath?: string, timeout?: number, memberId?: string, runtimeType?: RuntimeType, runtimeFlags?: string[], additionalAllowlistPaths?: string[]): Promise<{
        success: boolean;
        message?: string;
        error?: string;
    }>;
    /**
     * Step 1: Try direct registration prompt
     * Assumes Claude is already running and just needs a registration prompt
     */
    private tryDirectRegistration;
    /**
     * Step 2: Cleanup with Ctrl+C and reinitialize
     * Tries to reset the runtime session and start fresh
     */
    private tryCleanupAndReinit;
    /**
     * Detect and store the Claude Code session ID by scanning the filesystem.
     * Claude Code stores conversations as <UUID>.jsonl files in
     * ~/.claude/projects/<path-slug>/ where path-slug is the absolute
     * project path with / replaced by -.
     *
     * Runs in background after agent init to capture the session ID
     * for resume-on-restart support.
     *
     * @param sessionName - PTY session name
     * @param projectPath - Absolute path to the agent's project directory
     */
    private detectAndStoreSessionId;
    /**
     * Provision the runtime-specific project config file.
     *
     * Each agent CLI reads a different file for project configuration:
     * - Claude Code  → .crewly/CLAUDE.md
     * - Gemini CLI   → GEMINI.md (project root)
     * - Codex        → AGENTS.md (project root)
     *
     * Uses 'wx' flag to avoid overwriting existing files.
     *
     * @param projectPath - Project directory path
     * @param runtimeType - Agent runtime type
     */
    private provisionRuntimeConfigFile;
    /**
     * Send registration prompt asynchronously (non-blocking).
     * Uses an AbortController so the operation can be cancelled if the
     * runtime exits before registration completes.
     */
    private sendRegistrationPromptAsync;
    /**
     * Step 3: Kill session and recreate completely
     * Most aggressive approach - completely recreates the session from scratch
     */
    private tryFullRecreation;
    /**
     * Register a crewly-agent member as active by updating its team config directly.
     * In-process agents cannot run bash scripts, so this performs the registration
     * that the register-self skill would normally do for PTY-based runtimes.
     *
     * @param sessionName - Agent session name
     * @param role - Agent role
     * @param memberId - Optional member UUID
     * @returns True if registration succeeded
     */
    private registerMemberActive;
    /**
     * Set up standing event subscriptions for task workflow events based on org role.
     * Called once at agent registration. Subscriptions are long-lived (24h TTL)
     * and NOT oneShot — they persist for the agent's session lifetime.
     *
     * Orchestrator: task:verified, task:blocked, task:failed (all teams)
     * Team Lead: task:done, task:blocked, task:failed, task:needs_clarification (own team)
     * Executor: task:assigned (self scope)
     *
     * @param sessionName - Agent session name
     * @param orgRole - Organizational role (orchestrator, team-lead, executor)
     * @param teamId - Team ID for scoping (optional for orchestrator)
     */
    private setupStandingSubscriptions;
    /**
     * Load registration prompt from config files (with caching to prevent file I/O contention)
     */
    private loadRegistrationPrompt;
    /**
     * Write the registration prompt to a file on disk.
     *
     * For Claude Code agents (#207): writes to `{projectPath}/.claude/agents/{sessionName}.md`
     * with YAML frontmatter so the `--agent` flag can load it as a custom agent definition.
     * For other runtimes: writes to `~/.crewly/prompts/{sessionName}-init.md`.
     *
     * @param sessionName - Session name (used for filename)
     * @param prompt - The full prompt content
     * @param options - Optional: projectPath, runtimeType, and role for claude-code agent mode
     * @returns The absolute path to the written file, or undefined on error
     */
    private writePromptFile;
    /**
     * Build the unified init prompt path used by non-Claude-Code runtimes.
     *
     * Anchored on {@link getCrewlyHomePath} so test profiles, KR3 livewalk
     * dry-runs, and ESTestNode acceptance harnesses that export
     * `CREWLY_HOME=/tmp/...` write into the test profile, not the
     * developer's real `~/.crewly/prompts`. WI-F (2026-05-07): the
     * previous `path.join(os.homedir(), CREWLY_CONSTANTS.PATHS.CREWLY_HOME,
     * ...)` form ignored the env var and let Mia's KR3 livewalk overwrite
     * 27 occurrences of `~/.crewly/prompts/crewly-orc-init.md` and 26 of
     * `crewly-auditor-init.md` in Steve's user-prod tree at 02:37Z.
     */
    private getInitPromptFilePath;
    /**
     * Wait for agent registration to complete
     */
    private waitForRegistration;
    /**
     * Check if agent is properly registered
     */
    private checkAgentRegistration;
    /**
     * Fast registration with verification and retry mechanism
     * Sends system prompt to runtime which triggers MCP registration via teams.json
     * @param skipInitialCleanup If true, skips Ctrl+C on first attempt (when runtime was just initialized)
     */
    private attemptRegistrationWithVerification;
    /**
     * Fast registration polling with shorter intervals
     */
    private waitForRegistrationFast;
    /**
     * Create orchestrator session - extracted from the original tmux service
     */
    private createOrchestratorSession;
    /**
     * Unified session creation that handles both orchestrator and team members
     * @param config Session configuration
     * @returns Promise with success/error information
     */
    createAgentSession(config: {
        sessionName: string;
        role: string;
        projectPath?: string;
        windowName?: string;
        memberId?: string;
        runtimeType?: RuntimeType;
        teamId?: string;
        /**
         * Skip intelligent recovery and force immediate session kill + recreation.
         * Use during server startup to avoid expensive recovery on stale sessions.
         * @default false
         */
        forceRecreate?: boolean;
        /**
         * Additional paths to add to Gemini CLI's /directory allowlist during
         * postInitialize, before the registration prompt is sent. Used by the
         * orchestrator to include all existing project paths so they don't
         * race with the "Read the file..." prompt.
         */
        additionalAllowlistPaths?: string[];
    }): Promise<{
        success: boolean;
        sessionName?: string;
        message?: string;
        error?: string;
    }>;
    /**
     * Internal implementation of createAgentSession, guarded by sessionCreationLocks.
     * @param config Session configuration
     * @returns Promise with success/error information
     */
    private _createAgentSessionImpl;
    /**
     * Unified session termination that handles both orchestrator and team members
     * @param sessionName The session to terminate
     * @param role The role for proper status updates
     * @returns Promise with success/error information
     */
    terminateAgentSession(sessionName: string, role?: string): Promise<{
        success: boolean;
        message?: string;
        error?: string;
    }>;
    /**
     * Send a message to any agent session with reliable delivery.
     * Uses robust delivery mechanism with retry logic to ensure messages
     * are properly delivered to Claude Code's input.
     *
     * @param sessionName - The agent session name
     * @param message - The message to send
     * @returns Promise with success status and optional error message
     *
     * @example
     * ```typescript
     * const result = await agentRegistrationService.sendMessageToAgent(
     *   'crewly-orc',
     *   '[CHAT:123] Hello, orchestrator!'
     * );
     * if (result.success) {
     *   console.log('Message delivered');
     * } else {
     *   console.error('Delivery failed:', result.error);
     * }
     * ```
     */
    sendMessageToAgent(sessionName: string, message: string, runtimeType?: RuntimeType): Promise<{
        success: boolean;
        message?: string;
        error?: string;
        queued?: boolean;
    }>;
    /**
     * Wait for an agent session to be at a ready prompt before sending messages.
     *
     * Subscribes to terminal output and polls capturePane to detect when the
     * agent returns to an input prompt. This is critical for sequential message
     * processing: after the orchestrator responds to a message it may continue
     * working (managing agents, running commands) before returning to prompt.
     *
     * @param sessionName - The session name to wait on
     * @param timeoutMs - Maximum time to wait (default 120s)
     * @returns true if agent is ready, false if timed out
     */
    waitForAgentReady(sessionName: string, timeoutMs?: number, runtimeType?: RuntimeType): Promise<boolean>;
    /**
     * Send message with retry logic for reliable delivery to Claude Code.
     * Uses SessionCommandHelper.sendMessage() (proven two-step write pattern)
     * with stuck-message detection and retry on failure.
     *
     * @param sessionName - The session name
     * @param message - The message to send
     * @param maxAttempts - Maximum number of delivery attempts
     * @returns true if message was delivered successfully
     */
    private sendMessageWithRetry;
    /**
     * Check if a sent message is stuck at the terminal prompt (Enter was not accepted).
     *
     * Captures the current terminal pane and looks for the message text still visible
     * on the last few lines. If the text is found, Enter was not processed and the
     * message is stuck.
     *
     * @param sessionName - The session to check
     * @param message - The original message that was sent
     * @returns true if the message text is still visible at the prompt (stuck)
     */
    private isMessageStuckAtPrompt;
    /**
     * Check if message text is stuck at the TUI prompt line (Enter was not pressed).
     *
     * Unlike `isMessageStuckAtPrompt` which checks the last 20 lines for the message
     * text ANYWHERE, this method specifically checks whether the message text appears
     * ON the prompt line itself (the line starting with `> ` or `│ > `).
     *
     * After Enter is successfully pressed, the text moves from the prompt line to the
     * chat history area. So if the text is still on the prompt line, Enter was dropped.
     *
     * This avoids the false positive problem where `isMessageStuckAtPrompt` matches
     * the message text in the TUI's chat history (which echoes submitted messages).
     *
     * @param sessionName - The session to check
     * @param message - The original message that was sent
     * @returns true if the message text is visible on the TUI prompt line (stuck)
     */
    private isTextStuckAtTuiPrompt;
    /**
     * Attempt to recover from text stuck at TUI prompt by pressing Enter.
     * Checks if text is stuck, sends Enter, waits, then verifies.
     *
     * @param sessionName - The session to recover
     * @param message - The original message
     * @returns true if recovery succeeded (text is no longer at prompt)
     */
    private recoverStuckTuiMessage;
    /**
     * Start a background scanner that periodically checks all registered TUI
     * sessions for text stuck at the prompt (Enter not pressed).
     *
     * This is a safety net that catches messages missed by the per-send
     * verification in `sendMessageWithRetry`. It scans every 30 seconds.
     *
     * When stuck text is detected, the scanner presses Enter to recover.
     * If text has been sitting at the prompt for multiple consecutive scans,
     * it escalates to Tab + Enter (TUI focus recovery).
     */
    startStuckMessageDetector(): void;
    /**
     * Stop the background stuck-message detector.
     */
    stopStuckMessageDetector(): void;
    /**
     * Scan all sessions for stuck messages. Two complementary strategies:
     *
     * 1. TUI prompt-line scanning (existing): checks registered TUI sessions
     *    for text sitting on the `> ` prompt line.
     * 2. Tracked-message scanning (new, all runtimes): checks if any recently
     *    sent message text is still visible at the bottom of the terminal
     *    after 15+ seconds — runtime-agnostic Enter-drop detection.
     */
    private scanForStuckMessages;
    /**
     * Unregister a TUI session from the stuck-message detector.
     * Call this when a session is destroyed or agent is stopped.
     *
     * @param sessionName - The session to unregister
     */
    unregisterTuiSession(sessionName: string): void;
    /**
     * Register a message that was sent to a session for background
     * stuck-detection. The scanner will periodically check if the
     * message text is still visible at the bottom of the terminal.
     *
     * @param sessionName - The session the message was sent to
     * @param message - The full message text
     */
    trackSentMessage(sessionName: string, message: string): void;
    /**
     * Check if the agent appears to be at an input prompt.
     * Delegates to the regex-free isAgentAtPrompt() from terminal-string-ops,
     * with additional logging and per-line prompt detection using isPromptLine().
     *
     * @param terminalOutput - The terminal output to check
     * @param runtimeType - The runtime type for pattern selection
     * @returns true if the agent appears to be at a prompt
     */
    private isClaudeAtPrompt;
    /**
     * Detect if Gemini CLI is currently in shell mode.
     *
     * In shell mode, Gemini CLI changes its prompt from `>` to `!`. Any input
     * sent in this mode is executed as a shell command instead of being passed
     * to the model. This method examines the last few lines of terminal output
     * for shell mode prompt indicators.
     *
     * @param terminalOutput - Captured terminal pane content
     * @returns true if the terminal shows a shell mode prompt
     */
    private isGeminiInShellMode;
    /**
     * Escape from Gemini CLI shell mode by sending Escape key.
     *
     * Sends Escape and waits for the prompt to change from `!` back to `>`.
     * Retries up to MAX_ESCAPE_ATTEMPTS times.
     *
     * @param sessionName - The session running Gemini CLI
     * @param sessionHelper - SessionCommandHelper instance
     * @returns true if successfully escaped shell mode, false if still in shell mode
     */
    private escapeGeminiShellMode;
    /**
     * Generic key sending to any agent session
     * @param sessionName The agent session name
     * @param key The key to send (e.g., 'Enter', 'Ctrl+C')
     * @returns Promise with success/error information
     */
    sendKeyToAgent(sessionName: string, key: string): Promise<{
        success: boolean;
        message?: string;
        error?: string;
    }>;
    /**
     * Generic health check for any agent session
     * @param sessionName The agent session name
     * @param role The agent role for additional context
     * @param timeout Timeout for health check in milliseconds
     * @returns Promise with health status information
     */
    checkAgentHealth(sessionName: string, role?: string, timeout?: number): Promise<{
        success: boolean;
        data?: {
            agent: {
                sessionName: string;
                role?: string;
                running: boolean;
                status: (typeof CREWLY_CONSTANTS.AGENT_STATUSES)[keyof typeof CREWLY_CONSTANTS.AGENT_STATUSES];
            };
            timestamp: string;
        };
        error?: string;
    }>;
    /**
     * Write the prompt to a file and send a short instruction to the agent to read it.
     *
     * Instead of pasting large multi-line prompts directly into the terminal (which
     * causes bracketed paste issues, shell interpretation errors, and truncation),
     * we write the prompt to ~/.crewly/prompts/{sessionName}-init.md and send a
     * single-line instruction telling the agent to read that file.
     *
     * @param sessionName The session name
     * @param prompt The full system prompt to deliver
     * @param runtimeType The agent runtime type
     * @param abortSignal Optional signal to cancel the operation (e.g. on runtime exit)
     * @returns true if the instruction was delivered successfully
     */
    private sendPromptRobustly;
    /**
     * Capture the current PTY output of a running agent session.
     *
     * Used by the queue processor to verify that a force-delivered message
     * was actually seen by the agent (pending-ack verification).
     *
     * @param sessionName - The agent session name
     * @param lines - Number of lines to capture (default 200)
     * @returns The captured terminal output, or empty string if session not found
     */
    captureAgentOutput(sessionName: string, lines?: number): Promise<string>;
}
//# sourceMappingURL=agent-registration.service.d.ts.map