/**
 * Agent Process Manager — CC tmux-aligned subprocess isolation.
 *
 * Spawns team member agents as independent child processes, each with:
 *   - Own cwd (set to worktree path for git isolation)
 *   - Own stdin/stdout JSON-RPC transport
 *   - Own memory + tool context (no shared process.cwd)
 *   - Lifecycle tracking (PID, health, abort)
 *
 * CC does this via tmux split-pane + `claudeagent-id ...` commands.
 * We spawn `node dist/cli.js` as child processes with JSON-RPC stdio.
 *
 * Reference: claude-code-haha/src/utils/swarm/spawnMultiAgent.ts
 * Reference: claude-code-haha/src/utils/swarm/spawnUtils.ts
 */
import type { ExternalAgentDescriptor, McpServerConfig } from "../../protocol/wire/acp-agent-management.js";
import type { AgentConfig } from "../../protocol/wire/acp-agent-management.js";
import { AcpUsageTracker } from "./acp-usage-tracker.js";
export interface AgentProcessConfig {
    /** Unique member ID (e.g. "team-research-coder"). */
    memberId: string;
    /** Display name. */
    name: string;
    /** Working directory for this agent (worktree path). */
    cwd: string;
    /** Initial task prompt sent after handshake. */
    prompt: string;
    /** Environment variables to forward (subset of parent env). */
    env?: Record<string, string>;
    /** Agent type hint for the child (sets system prompt behavior). */
    agentType?: string;
    /**
     * Standing LLM config for an internal child. Pushed via session/set_config_option
     * right after session/new so every turn (initial task, team send replies)
     * resolves provider/model/apiKey explicitly. A standalone child has no llmrouter
     * directory to hydrate a model catalog from — without this push its first turn
     * dies with NO_PROVIDER. provider+apiKey are what the child's turn resolution
     * requires (resolveTextGenerationConfig); model rides along for determinism.
     */
    provider?: string;
    /** Model for the child's turns (see provider). */
    model?: string;
    /** API key for the child's turns (see provider). */
    apiKey?: string;
    /** Base URL for the child's LLM API (see provider). */
    baseUrl?: string;
    /** Enable verbose logging in child. */
    verbose?: boolean;
    /** External ACP agent descriptor (if set, spawn via ACP protocol). */
    external?: ExternalAgentDescriptor;
    /** MCP server configs to inject into ACP session (only for external agents). */
    mcpServers?: McpServerConfig[];
    /** System prompt to inject into ACP session. */
    systemPrompt?: string;
}
/** Snapshot of ongoing media generation progress reported by a child agent. */
export interface MediaProgressSnapshot {
    /** Provider-specific task ID (e.g. volcengine job id). */
    taskId: string;
    /** Media type ("video" | "image" | "tts" | "3d"). */
    mediaType: string;
    /** Estimated completion 0-100. */
    percent: number;
    /** Provider status label (e.g. "queuing", "running", "processing"). */
    status: string;
    /** Which provider. */
    provider?: string;
    /** When this snapshot was last updated. */
    updatedAt: number;
}
export interface AgentProcessHandle {
    /** Process identifier for this agent. */
    memberId: string;
    /** Display name. */
    name: string;
    /** OS process ID (-1 if not spawned). */
    pid: number;
    /** Working directory. */
    cwd: string;
    /** Current lifecycle state. */
    state: "starting" | "ready" | "running" | "completed" | "failed" | "killed";
    /** Session ID assigned by the child (after initialize). */
    sessionId?: string;
    /** Final result text (after turn completes). */
    resultText?: string;
    /** Error message if failed. */
    error?: string;
    /** Spawn timestamp. */
    startedAt: number;
    /** End timestamp. */
    endedAt?: number;
    /** Latest media generation progress (auto-captured from child turn.media_progress). */
    mediaProgress?: MediaProgressSnapshot;
    /** Last tool call name seen from child (from turn.tool_call notification). */
    lastToolCall?: string;
    /** Last status text from child (from turn.delta notification). */
    lastDelta?: string;
    /** Last delta timestamp. */
    lastActivityAt?: number;
    /** Whether the ACP agent supports session/resume (D-1). */
    supportsResume?: boolean;
    /** ACP session/update types observed during the current external-agent prompt. */
    acpUpdateTypes?: string[];
    /** Stderr log path for this agent process, when diagnostics logging is enabled. */
    stderrLogPath?: string;
    /** Sanitized external ACP launch details for empty-output diagnostics. */
    acpLaunchDiagnostics?: {
        cliPath: string;
        acpArgs: string[];
        cwd: string;
        env: string;
    };
    /** Last external ACP prompt elapsed time in milliseconds. */
    acpLastPromptElapsedMs?: number;
}
/** Callbacks for process lifecycle events. */
export interface AgentProcessCallbacks {
    /** Called when child emits a JSON-RPC notification. */
    onNotification?: (memberId: string, method: string, params: unknown) => void;
    /** Called when child process state changes. */
    onStateChange?: (memberId: string, state: AgentProcessHandle["state"]) => void;
    /** Called when child process exits. */
    onExit?: (memberId: string, code: number | null, signal: string | null) => void;
    /** Called when MCP bridge server proxies a tool call from an external agent. */
    onMcpToolCall?: (memberId: string, tool: string, args: Record<string, unknown>) => Promise<unknown>;
    /**
     * Called when an external agent requests permission (ACP session/request_permission). When set,
     * it drives interactive approval (forward to user, await decision) instead of the auto-allow
     * host-trust baseline; resolve with the chosen optionId.
     */
    onPermissionRequest?: (memberId: string, params: Record<string, unknown>) => Promise<{
        optionId: string;
    }>;
    /** Logger. */
    log?: {
        info(msg: string): void;
        warn(msg: string): void;
        debug?(msg: string): void;
    };
    /** Session directory for stderr logs. If set, ACP agent stderr is written to {sessionDir}/{agentId}.stderr.log. */
    sessionDir?: string;
}
export declare function ensureLoopbackNoProxy(env: Record<string, string>): Record<string, string>;
/**
 * Build LLM-related environment variables for an external ACP teammate.
 *
 * Priority chain:
 *   1. Per-agent override (AgentConfig.apiKey / baseUrl)
 *   2. Gateway proxy mode (all requests through shared gateway)
 *   3. Inherit from qlogicagent's own env
 *
 * Handles the asymmetry between agents that support base URL override
 * (can redirect to gateway) vs those that don't (only API key forwarding).
 */
export declare function buildLlmEnvForTeammate(agentId: string, agentConfig: AgentConfig | null, gatewayUrl: string | undefined): Record<string, string>;
/** Fault severity levels for ACP agent errors. */
export declare const ACP_FAULT_LEVEL: {
    /** Unrecoverable — agent binary missing, permission denied, etc. */
    readonly FATAL: "fatal";
    /** Retriable — spawn timeout, handshake timeout, transient crash. */
    readonly RETRIABLE: "retriable";
    /** Warning — non-critical issue (e.g. degraded capabilities). */
    readonly WARN: "warn";
};
export type AcpFaultLevel = (typeof ACP_FAULT_LEVEL)[keyof typeof ACP_FAULT_LEVEL];
export declare function sanitizeAgentLogFileName(memberId: string): string;
/**
 * Manages a pool of child agent processes.
 * Each child is a `qlogicagent` subprocess using JSON-RPC over stdio.
 */
export declare class AgentProcessManager {
    private processes;
    private callbacks;
    private cliBinaryPath;
    private mcpBridgeScriptPath;
    constructor(callbacks?: AgentProcessCallbacks);
    /** Format: [ISO] [level] [agent:id] [phase] message */
    private slog;
    /** Spawn a child agent process in the given cwd. */
    spawn(config: AgentProcessConfig): Promise<AgentProcessHandle>;
    /**
     * Send a task to a child agent via ACP session/prompt.
     * Returns the JSON-RPC result (content/usage carried on the response).
     */
    sendTask(memberId: string, prompt: string, options?: {
        sessionId?: string;
        timeout?: number;
    }): Promise<unknown>;
    private buildExternalPromptDiagnostics;
    /** Send a raw JSON-RPC request to a child. */
    sendRpc(memberId: string, method: string, params?: unknown, timeoutMs?: number): Promise<unknown>;
    /**
     * Send a long-running task to a child agent with heartbeat keepalive.
     *
     * Unlike `sendTask()` (which blocks for up to 5 minutes), this method:
     *   1. Dispatches the task via ACP `session/prompt`
     *   2. Periodically sends `ping` RPCs to detect child liveness
     *   3. Supports very long execution times (hours/days) for async work
     *      like video generation, batch processing, etc.
     *
     * The child is expected to emit `turn.delta` / `turn.progress`
     * notifications during long work. If no response to ping within
     * `pingTimeout`, the task is considered failed.
     */
    sendTaskAsync(memberId: string, prompt: string, options?: {
        sessionId?: string;
        /** Total timeout for the task (default: unlimited, 0 = no timeout) */
        timeout?: number;
        /** Ping interval in ms (default: 60_000 = 1 minute) */
        pingInterval?: number;
        /** Ping response timeout in ms (default: 10_000) */
        pingTimeout?: number;
    }): Promise<unknown>;
    /**
     * Ping a child agent to check liveness.
     *
     * Q-2 protocol alignment:
     * - Internal agents: JSON-RPC `ping` request (guaranteed to respond).
     * - ACP agents: Send `notifications/ping` notification, then wait for
     *   `$/alive` notification back. Falls back to `sendRpc("ping")` if
     *   `$/alive` is not received (some ACP agents may support RPC ping).
     */
    ping(memberId: string, timeoutMs?: number): Promise<boolean>;
    /**
     * Get the runtime status of a child agent process.
     * Includes real-time media generation progress if available.
     */
    getStatus(memberId: string): {
        alive: boolean;
        state: AgentProcessHandle["state"];
        runningFor?: number;
        resultText?: string;
        error?: string;
        /** Current media generation progress (from child's turn.media_progress). */
        mediaProgress?: MediaProgressSnapshot;
        /** Last tool the child invoked. */
        lastToolCall?: string;
        /** Seconds since last activity from child. */
        idleFor?: number;
    } | null;
    /**
     * Auto-capture structured progress from child notifications.
     * This is the key mechanism that allows the parent to know:
     *   - Which provider task ID the child is polling (for video/3D/TTS)
     *   - Real progress percentage
     *   - What the child is currently doing (which tool, what delta text)
     */
    /**
     * Respond to a request the child agent makes to the parent (host) over ACP —
     * e.g. session/request_permission. Sub-agents run autonomously under the parent,
     * so tool-permission requests are auto-approved.
     */
    private handleChildHostRequest;
    private captureChildProgress;
    /**
     * Spawn an external ACP agent with retry logic.
     * Retries up to MAX_SPAWN_RETRIES times with exponential backoff.
     */
    private spawnAcpAgentWithRetry;
    /**
     * Spawn an external ACP agent process.
     * Uses the ACP protocol adapter for lifecycle management.
     */
    private spawnAcpAgent;
    /** Kill a specific child agent process. */
    kill(memberId: string): void;
    /** Kill all child processes and clean up. */
    killAll(): void;
    /** Get the handle for a specific member. */
    getHandle(memberId: string): AgentProcessHandle | undefined;
    /** Get all handles. */
    getAllHandles(): AgentProcessHandle[];
    /** Whether a member's process is still spawned and usable (for pool reuse across turns). */
    isAlive(memberId: string): boolean;
    /** Get usage tracker for an ACP agent (returns null for internal agents). */
    getUsageTracker(memberId: string): AcpUsageTracker | null;
    /**
     * Create a named-pipe IPC server for MCP bridge tool-call proxying.
     * External agents' MCP bridge servers connect here to proxy tool calls
     * back to qlogicagent.
     */
    private createMcpIpcServer;
    /** Handle a single JSON-RPC message from the MCP bridge IPC connection. */
    private handleMcpIpcMessage;
    /**
     * Attempt to restart a crashed ACP agent.
     * Re-spawns the child process prepping the same config and env,
     * then re-runs ACP handshake.
     */
    private attemptRuntimeRestart;
    /** Get IPC pipe path for a member's MCP bridge. */
    getMcpIpcPath(memberId: string): string | undefined;
    private heartbeatTimers;
    private missedBeats;
    /** Heartbeat interval (ms). */
    private static readonly HEARTBEAT_INTERVAL;
    /** Number of missed heartbeats before force-kill. */
    private static readonly MAX_MISSED_BEATS;
    /**
     * Start heartbeat monitoring for a running agent.
     * Sends periodic ping RPCs; after MAX_MISSED_BEATS consecutive failures,
     * the agent is force-killed and marked as "hang".
     */
    startHeartbeat(memberId: string, onHang?: (memberId: string) => void): void;
    /** Stop heartbeat monitoring for an agent. */
    stopHeartbeat(memberId: string): void;
    /** Get missed heartbeat count for an agent. */
    getMissedBeats(memberId: string): number;
    /** Get count of active (non-terminal) processes. */
    activeCount(): number;
    /** Remove a terminated process from tracking. */
    remove(memberId: string): void;
    /** Clean up all processes. */
    dispose(): void;
}
