// orchestrator/agent-spawner.ts — Agent process spawning (SPEC-079 AC-03)
// Launches agents as CLI subprocesses with configurable commands.
/**
 * Build a spawn descriptor for an agent based on spawn method.
 * Language-agnostic: command is fully configurable per agent.
 */
export function buildSpawnDescriptor(agent, context, spawnMethod, timeoutMs) {
    const baseArgs = [...agent.args];
    if (spawnMethod === 'cli-subprocess') {
        // For CLI subprocess, append the context as a prompt argument
        if (agent.command.includes('claude')) {
            baseArgs.push('-p', context);
        }
        else {
            baseArgs.push('--context', context);
        }
    }
    return {
        command: agent.command,
        args: baseArgs,
        env: {
            ORCHESTRATION_AGENT_ID: agent.id,
            ORCHESTRATION_MODEL_TIER: agent.modelTier ?? 'sonnet',
        },
        cwd: agent.workDir ?? process.cwd(),
        timeoutMs,
    };
}
/**
 * Create an initial AgentProcess record in pending state.
 */
export function createAgentProcess(agentId) {
    return {
        agentId,
        pid: 0,
        status: 'pending',
        startedAt: new Date().toISOString(),
        stdout: '',
        stderr: '',
        retryCount: 0,
    };
}
/**
 * Spawn an agent as a child process (real execution).
 * Returns a new RuntimeAgentProcess with the result.
 * In tests, this function should be mocked.
 */
export async function spawnAgent(descriptor, initial, onProgress) {
    // Dynamic import to allow mocking in tests
    const { spawn } = await import('node:child_process');
    return new Promise((resolve) => {
        const result = { ...initial, status: 'spawning' };
        onProgress?.(result.agentId, 'spawning');
        const child = spawn(descriptor.command, descriptor.args, {
            cwd: descriptor.cwd,
            env: { ...process.env, ...descriptor.env },
            stdio: ['pipe', 'pipe', 'pipe'],
        });
        result.pid = child.pid ?? 0;
        result.status = 'running';
        onProgress?.(result.agentId, 'running');
        let stdout = '';
        let stderr = '';
        child.stdout.on('data', (data) => {
            stdout += data.toString();
        });
        child.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        const timer = setTimeout(() => {
            child.kill('SIGTERM');
            result.status = 'failed';
            result.stderr = `${stderr}\n[TIMEOUT]`;
            result.stdout = stdout;
            result.completedAt = new Date().toISOString();
            onProgress?.(result.agentId, 'failed');
            resolve(result);
        }, descriptor.timeoutMs);
        child.on('close', (code) => {
            clearTimeout(timer);
            result.stdout = stdout;
            result.stderr = stderr;
            result.exitCode = code ?? 1;
            result.status = code === 0 ? 'completed' : 'failed';
            result.completedAt = new Date().toISOString();
            onProgress?.(result.agentId, result.status);
            resolve(result);
        });
        child.on('error', (err) => {
            clearTimeout(timer);
            result.status = 'failed';
            result.stderr = `${stderr}\n[SPAWN ERROR] ${err.message}`;
            result.stdout = stdout;
            result.completedAt = new Date().toISOString();
            onProgress?.(result.agentId, 'failed');
            resolve(result);
        });
    });
}
/**
 * Parse token usage from agent stdout.
 * Looks for patterns like "Tokens used: 1234" or JSON with token counts.
 */
export function parseTokenUsage(stdout) {
    // Try structured JSON pattern
    const jsonMatch = /\{[^}]*"tokens"\s*:\s*(\d+)[^}]*\}/u.exec(stdout);
    if (jsonMatch?.[1]) {
        return parseInt(jsonMatch[1], 10);
    }
    // Try plain text pattern
    const textMatch = /tokens?\s*(?:used|consumed|count)\s*[:=]\s*(\d+)/iu.exec(stdout);
    if (textMatch?.[1]) {
        return parseInt(textMatch[1], 10);
    }
    return 0;
}
//# sourceMappingURL=agent-spawner.js.map