/*
 * 文件定位：storagePool / baseToolStorage / shell.processSpawning bestPractice。
 * 核心目的：比较三家来源实践，并给 baseTools 入口提供稳定的进程控制调用面。
 */
import { createShellBaseToolDefinition, createShellCoreHandler, injectRuntimeInvocationMetadata, jsonSchema } from "../../_shared/baseToolAdapter.js";
import { plainJsonRecord, readRecord, safeMetadata, trimmedString } from "../_shared/processControlJson.js";
import { anthropicShellProcessSpawningPractice } from "./anthropic.js";
import { deepmindShellProcessSpawningPractice } from "./deepmind.js";
import { openaiShellProcessSpawningPractice } from "./openai.js";
import { planShellProcessSpawn, } from "./core.js";
import { shellProcessSpawningDependencyDeclarations, } from "./dependencies.js";
export * from "./core.js";
export const shellProcessSpawningProviderPractices = [
    anthropicShellProcessSpawningPractice,
    openaiShellProcessSpawningPractice,
    deepmindShellProcessSpawningPractice,
];
export const shellProcessSpawningBestPracticeDescriptor = {
    toolId: "shell.processSpawning",
    bestPractice: "runtime-governed-process-control",
    sourcePriority: ["cli", "agent-sdk", "api-sdk", "praxis-native"],
    providerOrder: ["anthropic", "openai", "deepmind"],
    dependencies: shellProcessSpawningDependencyDeclarations,
};
function orderedPractices(preferredProvider) {
    if (preferredProvider === undefined) {
        return shellProcessSpawningProviderPractices;
    }
    return [
        ...shellProcessSpawningProviderPractices.filter((practice) => practice.providerName === preferredProvider),
        ...shellProcessSpawningProviderPractices.filter((practice) => practice.providerName !== preferredProvider),
    ];
}
export function selectShellProcessSpawningPractice(dependencies = {}) {
    for (const practice of orderedPractices(dependencies.preferredProvider)) {
        const provider = practice.createProvider(dependencies);
        if (provider !== undefined) {
            return { providerName: practice.providerName, practice, provider };
        }
    }
    return {
        providerName: "praxis-native",
        practice: {
            providerName: "praxis-native",
            source: { kind: "praxis-native", label: "Praxis dry-run fallback" },
            directCliSupport: false,
            sideEffectPolicy: "runtime-governed",
            notes: ["No injected or host process-control provider is currently available; dry-run remains available."],
            createProvider: () => undefined,
        },
    };
}
function stringValue(value) {
    return typeof value === "string" ? value : undefined;
}
function requestRecord(input) {
    return readRecord(input) ?? {};
}
function bestPracticeRequest(input) {
    return requestRecord(input);
}
function runtimeContext(input) {
    return (readRecord(requestRecord(input).context) ?? {});
}
function realExecutionRequested(input) {
    return readRecord(requestRecord(input).context)?.dryRun === false;
}
function guardAllows(context) {
    return context.guard?.allowed === true || context.guard?.accepted === true;
}
function auditEvent(type, context, metadata) {
    return {
        type,
        toolId: "shell.processSpawning",
        invocationId: trimmedString(context.invocationId) || "shell.processSpawning:dry-run",
        dryRun: context.dryRun !== false,
        metadata: {
            ...safeMetadata(context.auditMetadata),
            ...(metadata ?? {}),
        },
    };
}
function failure(code, message, boundary, context) {
    return {
        ok: false,
        toolId: "shell.processSpawning",
        error: { code, message, boundary, safeForRuntimeInspection: true, internalDetailExposed: false },
        audit: [auditEvent("agentCore.basicTool.shell.processSpawning.rejected", context ?? {}, { code, boundary })],
        events: ["basicTool.shell.processSpawning.rejected"],
    };
}
function convertPlanResult(result) {
    if (!result.ok) {
        return {
            ok: false,
            toolId: "shell.processSpawning",
            error: {
                code: result.error.code,
                message: result.error.message,
                boundary: (result.error.boundary === "approval" ? "governance" : result.error.boundary),
                safeForRuntimeInspection: true,
                internalDetailExposed: false,
            },
            audit: result.audit,
            events: result.events,
        };
    }
    return { ok: true, toolId: "shell.processSpawning", output: result.output, audit: result.audit, events: result.events };
}
function normalizedEnv(value) {
    const env = readRecord(value);
    if (env === undefined || Object.values(env).some((item) => typeof item !== "string")) {
        return undefined;
    }
    return Object.fromEntries(Object.entries(env).map(([name, item]) => [name, item]));
}
function normalizedProviderRequest(request, plannedOutput) {
    const requestInput = requestRecord(request);
    const originalTarget = readRecord(requestInput.target);
    const providerRequest = {
        target: {
            executable: plannedOutput.target.executable,
            command: plannedOutput.target.command,
            args: plannedOutput.target.args,
            workingDirectory: plannedOutput.target.workingDirectory,
            shell: plannedOutput.target.shell,
            env: normalizedEnv(originalTarget?.env),
            stdio: plannedOutput.target.stdio,
        },
        launchMode: plannedOutput.launchMode,
        context: { ...(readRecord(requestInput.context) ?? {}), dryRun: false },
    };
    if (requestInput.riskLevel === "low" || requestInput.riskLevel === "medium" || requestInput.riskLevel === "high") {
        providerRequest.riskLevel = requestInput.riskLevel;
    }
    return providerRequest;
}
function normalizeProviderResult(providerResult) {
    const resultRecord = readRecord(providerResult);
    if (resultRecord === undefined) {
        return undefined;
    }
    const resultEnvelope = plainJsonRecord(resultRecord.resultEnvelope);
    if (resultEnvelope === undefined || resultEnvelope.planned === true) {
        return undefined;
    }
    return { resultEnvelope, metadata: safeMetadata(resultRecord.metadata) };
}
export async function executeShellProcessSpawning(request = {}) {
    const normalizedRequest = bestPracticeRequest(request);
    if (!realExecutionRequested(normalizedRequest)) {
        return convertPlanResult(planShellProcessSpawn(normalizedRequest));
    }
    const context = runtimeContext(normalizedRequest);
    const runtimeId = stringValue(context.runtimeId)?.trim();
    if (runtimeId === undefined || runtimeId.length === 0) {
        return failure("MISSING_RUNTIME_ID", "shell.processSpawning requires context.runtimeId for real execution audit", "input", context);
    }
    if (!guardAllows(context)) {
        return failure("GOVERNANCE_REJECTED", "shell.processSpawning requires an allowed runtime governance guard when dryRun is false", "governance", context);
    }
    const planned = planShellProcessSpawn({ ...normalizedRequest, context: { ...runtimeContext(normalizedRequest), dryRun: true } });
    if (!planned.ok) {
        return convertPlanResult(planned);
    }
    const selection = selectShellProcessSpawningPractice({ executor: normalizedRequest.executor, provider: normalizedRequest.provider, preferredProvider: normalizedRequest.preferredProvider });
    if (selection.provider === undefined) {
        return failure("PROVIDER_UNAVAILABLE", "shell.processSpawning requires a runtime-provided process-control provider when dryRun is false", "provider", context);
    }
    try {
        const providerResult = normalizeProviderResult(await selection.provider(normalizedProviderRequest(request, planned.output), context));
        if (providerResult === undefined) {
            return failure("PROVIDER_REJECTED", "shell.processSpawning provider must return a plain JSON runtime envelope", "provider", context);
        }
        return {
            ok: true,
            toolId: "shell.processSpawning",
            output: {
                ...planned.output,
                dryRun: false,
                executionBlocked: false,
                providerCalled: true,
                resultEnvelope: providerResult.resultEnvelope,
            },
            audit: [auditEvent("agentCore.basicTool.shell.processSpawning.provider", context, { providerName: selection.providerName, ...providerResult.metadata })],
            events: ["basicTool.shell.processSpawning.providerCalled"],
        };
    }
    catch (error) {
        return failure("PROVIDER_REJECTED", "shell.processSpawning provider rejected the invocation", "provider", context);
    }
}
export const shellProcessSpawningBaseToolDefinition = createShellBaseToolDefinition({
    toolId: "shell.processSpawning",
    title: "Process Spawning",
    description: "Plan or execute shell process spawning through a governed runtime provider.",
    summary: "Use shell.processSpawning when TAP/runtime has approved this process-control primitive.",
    storageGroup: "processControl",
    riskLevel: "risky",
    permissionHints: ["shell:execute"],
    dependencies: shellProcessSpawningDependencyDeclarations,
    inputSchema: jsonSchema("shell.processSpawning.input", {
        type: "object",
        additionalProperties: true,
        properties: {
            target: {
                type: "object",
                additionalProperties: true,
                properties: {
                    executable: { type: "string", minLength: 1 },
                    command: { type: "string", minLength: 1 },
                    args: { type: "array", items: { type: "string" } },
                    workingDirectory: { type: "string" },
                    shell: { type: "string", enum: ["sh", "bash", "zsh"] },
                    env: { type: "object", additionalProperties: { type: "string" } },
                    stdio: { type: "string", enum: ["pipe", "inherit", "ignore"] },
                },
            },
            launchMode: { type: "string", enum: ["foreground", "background", "detached"] },
            riskLevel: { type: "string", enum: ["low", "medium", "high"] },
            context: { type: "object", additionalProperties: true },
            preferredProvider: { type: "string", enum: ["anthropic", "openai", "deepmind", "praxis-native"] },
        },
    }),
    outputSchema: jsonSchema("shell.processSpawning.output", {
        type: "object",
        additionalProperties: true,
        required: ["kind", "dryRun", "executionBlocked"],
        properties: {
            kind: { const: "agentCore.basicTool.shell.processSpawning" },
            dryRun: { type: "boolean" },
            executionBlocked: { type: "boolean" },
        },
    }),
});
export const shellProcessSpawningHandler = createShellCoreHandler(shellProcessSpawningBaseToolDefinition, async (request) => executeShellProcessSpawning({
    ...request.input,
    executor: request.executor,
    context: {
        ...(readRecord(request.input.context) ?? {}),
        runtimeId: trimmedString(readRecord(request.input.context)?.runtimeId) ?? request.runtimeId,
        ...({ sessionId: trimmedString(readRecord(request.input.context)?.sessionId) ?? request.sessionId }),
        invocationId: trimmedString(readRecord(request.input.context)?.invocationId) ?? request.toolCallId,
        auditMetadata: injectRuntimeInvocationMetadata(request.metadata, safeMetadata(readRecord(request.input.context)?.auditMetadata), request),
    },
}));
