/**
 * RelayAdapter — high-level interface over the broker SDK.
 *
 * Wraps AgentRelayClient with auto-start, safe result patterns,
 * and convenience methods. Usable by any integration: dashboard,
 * MCP, ACP bridge, CLI, or custom tooling.
 *
 * Usage:
 *   import { RelayAdapter } from '@agent-relay/sdk';
 *
 *   const relay = new RelayAdapter({ cwd: projectRoot });
 *   await relay.start();
 *
 *   await relay.spawn({ name: 'Worker1', cli: 'claude', task: 'Build auth' });
 *   const agents = await relay.listAgents();
 *   await relay.sendMessage({ to: 'Worker1', text: 'status?' });
 *   await relay.release('Worker1');
 *
 *   await relay.shutdown();
 */
import { AgentRelayClient, } from './client.js';
const WORKFLOW_BOOTSTRAP_TASK = 'You are connected to Agent Relay. Do not reply to this message and wait for relay messages and respond using Relaycast MCP tools.';
const WORKFLOW_CONVENTIONS = [
    'Messaging requirements:',
    '- When you receive `Relay message from <sender> ...`, reply using `mcp__relaycast__dm_send(to: "<sender>", text: "...")`.',
    '- Send `ACK: ...` when you receive a task.',
    '- Send `DONE: ...` when the task is complete.',
    '- Do not reply only in terminal text; send the response via mcp__relaycast__dm_send.',
    '- Use mcp__relaycast__inbox_check() and mcp__relaycast__agent_list() when context is missing.',
].join('\n');
function hasWorkflowConventions(task) {
    const lower = task.toLowerCase();
    return lower.includes('mcp__relaycast__dm_send(') || lower.includes('relay_send(') || (lower.includes('ack:') && lower.includes('done:'));
}
function buildSpawnTask(task, includeWorkflowConventions) {
    const normalized = typeof task === 'string' ? task.trim() : '';
    if (!includeWorkflowConventions) {
        return normalized.length > 0 ? normalized : undefined;
    }
    if (normalized.length === 0) {
        return `${WORKFLOW_BOOTSTRAP_TASK}\n\n${WORKFLOW_CONVENTIONS}`;
    }
    if (hasWorkflowConventions(normalized)) {
        return normalized;
    }
    return `${normalized}\n\n${WORKFLOW_CONVENTIONS}`;
}
// ── Adapter ─────────────────────────────────────────────────────────
export class RelayAdapter {
    client;
    started = false;
    constructor(opts) {
        const clientOpts = {
            binaryPath: opts.binaryPath,
            channels: opts.channels ?? ['general'],
            cwd: opts.cwd,
            env: opts.env,
            clientName: opts.clientName ?? 'relay-adapter',
        };
        this.client = new AgentRelayClient(clientOpts);
    }
    // ── Lifecycle ───────────────────────────────────────────────────
    /** Start the broker process. Idempotent. */
    async start() {
        if (this.started)
            return;
        await this.client.start();
        this.started = true;
    }
    /** Shut down the broker and all spawned agents. */
    async shutdown() {
        await this.client.shutdown();
        this.started = false;
    }
    // ── Spawn / Release ─────────────────────────────────────────────
    /** Spawn an agent via the broker's PTY runtime. */
    async spawn(req) {
        await this.start();
        try {
            const input = {
                name: req.name,
                cli: req.cli,
                task: buildSpawnTask(req.task, req.includeWorkflowConventions),
                channels: ['general'],
                model: req.model,
                cwd: req.cwd,
                team: req.team,
                shadowOf: req.shadowOf,
                shadowMode: req.shadowMode,
            };
            const result = await this.client.spawnPty(input);
            // Try to get PID from agent list
            let pid;
            try {
                const agents = await this.client.listAgents();
                pid = agents.find((a) => a.name === req.name)?.pid;
            }
            catch {
                // Non-fatal — PID is informational
            }
            return { success: true, name: result.name, pid };
        }
        catch (err) {
            return { success: false, name: req.name, error: err?.message ?? String(err) };
        }
    }
    /** Release (stop) a spawned agent. */
    async release(name, reason) {
        await this.start();
        try {
            await this.client.release(name, reason);
            return { success: true, name };
        }
        catch (err) {
            return { success: false, name, error: err?.message ?? String(err) };
        }
    }
    // ── Query ───────────────────────────────────────────────────────
    /** List all agents managed by this broker instance. */
    async listAgents() {
        await this.start();
        const agents = await this.client.listAgents();
        return agents.map((a) => ({
            name: a.name,
            cli: undefined, // Rust binary doesn't track CLI in list_agents response
            pid: a.pid,
            channels: a.channels,
            parent: a.parent,
            runtime: a.runtime,
        }));
    }
    /** Check if a specific agent is spawned. */
    async hasAgent(name) {
        const agents = await this.listAgents();
        return agents.some((a) => a.name === name);
    }
    /** Get broker status (agent count, pending deliveries). */
    async getStatus() {
        await this.start();
        return this.client.getStatus();
    }
    // ── Messaging ───────────────────────────────────────────────────
    /** Send a message to an agent or channel. */
    async sendMessage(input) {
        await this.start();
        return this.client.sendMessage(input);
    }
    // ── PTY Input ───────────────────────────────────────────────────
    /**
     * Send raw input to an agent's PTY stdin.
     * Useful for interrupts (ESC sequences), confirmations, etc.
     */
    async sendInput(name, data) {
        await this.start();
        await this.client.sendInput(name, data);
    }
    /**
     * Send an interrupt (ESC ESC) to an agent.
     * Convenience wrapper around sendInput.
     */
    async interruptAgent(name) {
        try {
            await this.sendInput(name, '\x1b\x1b');
            return true;
        }
        catch {
            return false;
        }
    }
    // ── Model ───────────────────────────────────────────────────────
    /** Switch an agent's model at runtime. */
    async setModel(name, model, opts) {
        await this.start();
        return this.client.setModel(name, model, opts);
    }
    // ── Metrics ─────────────────────────────────────────────────────
    /** Get resource metrics for agents (memory, uptime) and broker stats. */
    async getMetrics(agent) {
        await this.start();
        return this.client.getMetrics(agent);
    }
    /** Get crash insights: recent crashes, patterns, and health score. */
    async getCrashInsights() {
        await this.start();
        return this.client.getCrashInsights();
    }
    // ── Events ──────────────────────────────────────────────────────
    /**
     * Subscribe to broker events (agent_spawned, agent_released,
     * relay_inbound, worker_stream, etc.).
     *
     * Returns an unsubscribe function.
     */
    onEvent(listener) {
        return this.client.onEvent(listener);
    }
    /**
     * Subscribe to broker stderr output (debug logs from the Rust binary).
     * Returns an unsubscribe function.
     */
    onStderr(listener) {
        return this.client.onBrokerStderr(listener);
    }
    // ── Underlying client (escape hatch) ────────────────────────────
    /** Access the underlying AgentRelayClient for advanced operations. */
    get raw() {
        return this.client;
    }
}
//# sourceMappingURL=relay-adapter.js.map