/*
 * Copyright 2026, Jaime Terrats.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { spawn } from 'node:child_process';
const MAX_OUTPUT_CHARS = 32_000;
function extractOutput(stdout) {
    const fenceStart = stdout.lastIndexOf('```json');
    if (fenceStart !== -1) {
        const afterFence = stdout.indexOf('\n', fenceStart) + 1;
        const lastBrace = stdout.lastIndexOf('}');
        if (lastBrace > afterFence) {
            const fenceEnd = stdout.indexOf('```', lastBrace);
            const end = fenceEnd !== -1 ? fenceEnd + 3 : stdout.length;
            return stdout.slice(fenceStart, end);
        }
    }
    return stdout.slice(-MAX_OUTPUT_CHARS);
}
// ─── Claude Adapter (parent-tool) ──────────────────────────────────────────
export const claudeAdapter = {
    id: 'claude',
    runtime: 'claude',
    capability: 'parent-tool',
    async execute(request, cwd) {
        const startMs = Date.now();
        try {
            const { exitCode, stdout } = await spawnProcess('claude', ['-p', request.renderedPrompt, '--bare', '--allowedTools', 'Read,Bash(find *),Bash(grep *)'], cwd, request);
            return {
                requestId: request.id,
                status: exitCode === 0 ? 'completed' : 'failed',
                runtime: 'claude',
                role: request.role,
                phase: request.phase,
                output: extractOutput(stdout),
                elapsedMs: Date.now() - startMs,
                closeStatus: exitCode === 0 ? 'success' : 'error',
            };
        }
        catch {
            return {
                requestId: request.id,
                status: 'failed',
                runtime: 'claude',
                role: request.role,
                phase: request.phase,
                elapsedMs: Date.now() - startMs,
                closeStatus: 'error',
            };
        }
    },
};
// ─── Codex Adapter (parent-tool) ────────────────────────────────────────────
export const codexAdapter = {
    id: 'codex',
    runtime: 'codex',
    capability: 'parent-tool',
    async execute(request, cwd) {
        const startMs = Date.now();
        try {
            const { exitCode, stdout } = await spawnProcess('codex', ['--approval-mode=suggest', request.renderedPrompt], cwd, request);
            return {
                requestId: request.id,
                status: exitCode === 0 ? 'completed' : 'failed',
                runtime: 'codex',
                role: request.role,
                phase: request.phase,
                output: extractOutput(stdout),
                elapsedMs: Date.now() - startMs,
                closeStatus: exitCode === 0 ? 'success' : 'error',
            };
        }
        catch {
            return {
                requestId: request.id,
                status: 'failed',
                runtime: 'codex',
                role: request.role,
                phase: request.phase,
                elapsedMs: Date.now() - startMs,
                closeStatus: 'error',
            };
        }
    },
};
// ─── Cursor Adapter (request-only) ─────────────────────────────────────────
export const cursorAdapter = {
    id: 'cursor',
    runtime: 'cursor',
    capability: 'request-only',
    execute(request) {
        return Promise.resolve({
            requestId: request.id,
            status: 'rejected',
            runtime: 'cursor',
            role: request.role,
            phase: request.phase,
            elapsedMs: 0,
            closeStatus: 'cancelled',
        });
    },
};
// ─── Agentforce Adapter (request-only) ────────────────────────────────────
export const agentforceAdapter = {
    id: 'agentforce',
    runtime: 'agentforce',
    capability: 'request-only',
    execute(request) {
        return Promise.resolve({
            requestId: request.id,
            status: 'rejected',
            runtime: 'agentforce',
            role: request.role,
            phase: request.phase,
            elapsedMs: 0,
            closeStatus: 'cancelled',
        });
    },
};
// ─── Windsurf Adapter (request-only) ──────────────────────────────────────
export const windsurfAdapter = {
    id: 'windsurf',
    runtime: 'windsurf',
    capability: 'request-only',
    execute(request) {
        return Promise.resolve({
            requestId: request.id,
            status: 'rejected',
            runtime: 'windsurf',
            role: request.role,
            phase: request.phase,
            elapsedMs: 0,
            closeStatus: 'cancelled',
        });
    },
};
// ─── Generic Adapter (unsupported) ─────────────────────────────────────────
export const genericAdapter = {
    id: 'generic',
    runtime: 'generic',
    capability: 'unsupported',
    execute(request) {
        return Promise.resolve({
            requestId: request.id,
            status: 'rejected',
            runtime: 'generic',
            role: request.role,
            phase: request.phase,
            elapsedMs: 0,
            closeStatus: 'cancelled',
        });
    },
};
// ─── All built-in adapters ──────────────────────────────────────────────────
export const BUILTIN_ADAPTERS = [
    claudeAdapter,
    codexAdapter,
    cursorAdapter,
    agentforceAdapter,
    windsurfAdapter,
    genericAdapter,
];
// ─── Process spawn helper ───────────────────────────────────────────────────
const DEFAULT_TIMEOUT_MS = 600_000;
function spawnProcess(command, args, cwd, request) {
    const timeoutMs = DEFAULT_TIMEOUT_MS;
    return new Promise((resolve) => {
        const stdoutChunks = [];
        let settled = false;
        let child;
        try {
            child = spawn(command, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
        }
        catch {
            resolve({ exitCode: 127, stdout: `Runtime "${command}" not found for spawn request ${request.id}` });
            return;
        }
        child.on('error', () => {
            if (settled)
                return;
            settled = true;
            resolve({ exitCode: 127, stdout: `Spawn error for ${command}` });
        });
        const killTimer = setTimeout(() => {
            if (settled)
                return;
            settled = true;
            child.kill('SIGTERM');
            resolve({ exitCode: 124, stdout: Buffer.concat(stdoutChunks).toString() });
        }, timeoutMs);
        child.stdout?.on('data', (chunk) => {
            stdoutChunks.push(chunk);
        });
        child.on('close', (code) => {
            if (settled)
                return;
            settled = true;
            clearTimeout(killTimer);
            resolve({ exitCode: code ?? 1, stdout: Buffer.concat(stdoutChunks).toString() });
        });
    });
}
//# sourceMappingURL=spawn-adapters.js.map