/*
 * 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 { renderPacketAsPrompt } from './workflow-delegation.js';
const DEFAULT_GUARDRAILS = {
    maxConcurrent: 2,
    maxPerTask: 8,
    maxDelegationDepth: 3,
    contextBudgetTokens: 100_000,
};
const activeSessions = new Map();
export const STALE_SESSION_TTL_MS = 300_000; // 5 minutes
export function cleanStaleSessions() {
    const now = Date.now();
    for (const [id, session] of activeSessions) {
        if (now - session.startedAt >= STALE_SESSION_TTL_MS) {
            activeSessions.delete(id);
        }
    }
}
export function getActiveSessions() {
    return activeSessions;
}
function getTaskSpawnCount(taskId) {
    cleanStaleSessions();
    let count = 0;
    for (const session of activeSessions.values()) {
        if (session.taskId === taskId)
            count++;
    }
    return count;
}
function incrementTaskSpawns(taskId, spawnId) {
    activeSessions.set(spawnId, { taskId, startedAt: Date.now(), spawnId });
}
function decrementTaskSpawns(spawnId) {
    activeSessions.delete(spawnId);
}
// ─── Adapter registry ───────────────────────────────────────────────────────
const adapters = new Map();
export function registerAdapter(adapter) {
    adapters.set(adapter.id, adapter);
}
export function getAdapter(id) {
    return adapters.get(id);
}
export function getAdapterForRuntime(runtime) {
    for (const adapter of adapters.values()) {
        if (adapter.runtime === runtime)
            return adapter;
    }
    return undefined;
}
export function listAdapters() {
    return [...adapters.values()];
}
// ─── Spawn request builder ──────────────────────────────────────────────────
let spawnCounter = 0;
export function buildSpawnRequest(input) {
    const guardrails = { ...DEFAULT_GUARDRAILS, ...input.guardrails };
    const ownershipBoundaries = {
        files: extractOwnershipFiles(input.packet),
        readOnly: ['.setup-agents/config.json', 'sfdx-project.json', 'package.json'],
        forbidden: ['.env', '.env.local', '*.key', '*.pem'],
    };
    const outputContract = {
        expectedType: resolveExpectedOutputType(input.phase),
        maxTokens: guardrails.contextBudgetTokens,
    };
    const evidenceContract = {
        requiredTypes: resolveRequiredEvidenceTypes(input.phase),
        autoRecord: true,
    };
    const queueMetadata = {
        priority: resolvePriority(input.phase),
        maxConcurrent: guardrails.maxConcurrent,
        maxPerTask: guardrails.maxPerTask,
        delegationDepth: input.delegationDepth ?? 0,
        maxDelegationDepth: guardrails.maxDelegationDepth,
        contextBudgetTokens: guardrails.contextBudgetTokens,
    };
    spawnCounter++;
    return {
        id: `spawn-${Date.now()}-${spawnCounter}`,
        taskId: input.taskId,
        runId: input.runId,
        phase: input.phase,
        role: input.role,
        adapterId: input.adapterId,
        contextBundle: JSON.stringify({
            goal: input.packet.context.goal,
            phase: input.phase,
            profile: input.packet.profile,
            decisions: input.packet.context.decisions,
            priorPhases: input.packet.context.priorPhases,
            constraints: input.packet.constraints,
        }),
        renderedPrompt: renderPacketAsPrompt(input.packet),
        ownershipBoundaries,
        outputContract,
        evidenceContract,
        queueMetadata,
        createdAt: new Date().toISOString(),
    };
}
export function validateGuardrails(request, adapter) {
    cleanStaleSessions();
    if (!adapter) {
        return { code: 'no-adapter', message: `No adapter registered for id "${request.adapterId}"` };
    }
    if (adapter.capability === 'unsupported') {
        return {
            code: 'unsupported-runtime',
            message: `Runtime "${adapter.runtime}" does not support native spawn (capability: unsupported)`,
        };
    }
    if (request.queueMetadata.delegationDepth >= request.queueMetadata.maxDelegationDepth) {
        return {
            code: 'max-depth',
            message: `Delegation depth ${request.queueMetadata.delegationDepth} exceeds max ${request.queueMetadata.maxDelegationDepth}`,
        };
    }
    const currentCount = getTaskSpawnCount(request.taskId);
    if (currentCount >= request.queueMetadata.maxPerTask) {
        return {
            code: 'max-per-task',
            message: `Task "${request.taskId}" has reached max spawns (${request.queueMetadata.maxPerTask})`,
        };
    }
    return null;
}
export async function executeSpawn(request, cwd, mode = 'auto') {
    const adapter = getAdapter(request.adapterId);
    const violation = validateGuardrails(request, adapter);
    if (violation) {
        if (mode === 'strict') {
            return { request, violation };
        }
        return {
            request,
            violation,
            fallback: {
                type: 'request-artifact',
                artifact: request,
                reason: violation.message,
            },
        };
    }
    if (adapter.capability === 'request-only') {
        return {
            request,
            fallback: {
                type: 'request-artifact',
                artifact: request,
                reason: `Adapter "${adapter.id}" only supports request artifacts (no native execution)`,
            },
        };
    }
    incrementTaskSpawns(request.taskId, request.id);
    try {
        const result = await adapter.execute(request, cwd);
        return { request, result };
    }
    finally {
        decrementTaskSpawns(request.id);
    }
}
// ─── Helpers ────────────────────────────────────────────────────────────────
function extractOwnershipFiles(packet) {
    const files = [];
    for (const ref of packet.references) {
        if (ref.source === 'doc' || ref.source === 'playbook') {
            files.push(ref.path);
        }
    }
    return files;
}
function resolveExpectedOutputType(phase) {
    switch (phase) {
        case 'qa':
        case 'security-review':
            return 'review';
        default:
            return 'deliverable';
    }
}
function resolveRequiredEvidenceTypes(phase) {
    switch (phase) {
        case 'developer':
            return ['command', 'file'];
        case 'qa':
            return ['command', 'report'];
        case 'architect':
            return ['file'];
        default:
            return ['file'];
    }
}
function resolvePriority(phase) {
    const priorities = {
        pm: 1,
        ba: 2,
        architect: 3,
        ux: 4,
        developer: 5,
        'security-review': 6,
        qa: 7,
        release: 8,
    };
    return priorities[phase] ?? 5;
}
//# sourceMappingURL=spawn-bridge.js.map