import { spawn } from 'node:child_process';
import { getRootLogger } from '../../utils/logger.js';
export class StdioTransport {
    config;
    process = null;
    messageHandlers = [];
    closeHandlers = [];
    errorHandlers = [];
    connected = false;
    buffer = '';
    log;
    constructor(config) {
        this.config = config;
        this.log = getRootLogger().child({ component: 'StdioTransport' });
    }
    async connect() {
        if (this.connected)
            return;
        this.process = spawn(this.config.command, this.config.args ?? [], {
            env: { ...process.env, ...this.config.env },
            cwd: this.config.cwd,
            stdio: ['pipe', 'pipe', 'pipe'],
        });
        this.process.stdout?.on('data', (chunk) => {
            this.buffer += chunk.toString('utf-8');
            this.processBuffer();
        });
        this.process.stderr?.on('data', (chunk) => {
            this.log.warn(`MCP server stderr: ${chunk.toString('utf-8').trim()}`);
        });
        this.process.on('close', (code) => {
            this.connected = false;
            this.log.info(`MCP server process exited with code ${code}`);
            for (const handler of this.closeHandlers)
                handler();
        });
        this.process.on('error', (err) => {
            this.connected = false;
            for (const handler of this.errorHandlers)
                handler(err);
        });
        this.connected = true;
        this.log.info(`StdioTransport connected: ${this.config.command} ${(this.config.args ?? []).join(' ')}`);
    }
    async close() {
        if (!this.process)
            return;
        this.connected = false;
        this.process.kill('SIGTERM');
        this.process = null;
        this.buffer = '';
    }
    async send(message) {
        if (!this.process?.stdin?.writable) {
            throw new Error('StdioTransport: not connected or stdin not writable');
        }
        const data = `${JSON.stringify(message)}\n`;
        this.process.stdin.write(data);
    }
    onMessage(handler) {
        this.messageHandlers.push(handler);
    }
    onClose(handler) {
        this.closeHandlers.push(handler);
    }
    onError(handler) {
        this.errorHandlers.push(handler);
    }
    isConnected() {
        return this.connected;
    }
    processBuffer() {
        const lines = this.buffer.split('\n');
        this.buffer = lines.pop() ?? '';
        for (const line of lines) {
            const trimmed = line.trim();
            if (!trimmed)
                continue;
            try {
                const message = JSON.parse(trimmed);
                for (const handler of this.messageHandlers)
                    handler(message);
            }
            catch {
                this.log.warn(`StdioTransport: invalid JSON-RPC message: ${trimmed.slice(0, 100)}`);
            }
        }
    }
}
//# sourceMappingURL=stdio.js.map