hen 0.18.1

Run protocol-aware API request collections from the command line or through MCP.
Documentation
use serde_json::{json, Value};

use crate::{
    automation::{self, PromptRequirement},
    error::HenError,
};

use super::{
    artifacts::{request_failure_json, run_record_json},
    common::execution_trace_json,
    redaction::OutputRedactor,
    BodyReportOptions,
};

pub fn run_outcome_json(
    outcome: &automation::RunOutcome,
    body_options: BodyReportOptions,
) -> Value {
    json!({
        "collection": {
            "path": outcome.collection.path.display().to_string(),
            "name": outcome.collection.name,
            "description": outcome.collection.description,
            "availableEnvironments": outcome.collection.available_environments,
            "selectedEnvironment": outcome.collection.selected_environment,
            "requiredInputs": outcome.collection.required_inputs.iter().map(prompt_requirement_json).collect::<Vec<_>>(),
            "requests": outcome.collection.requests.iter().map(|request| {
                let redactor = OutputRedactor::new(&request.sensitive_values);
                json!({
                    "index": request.index,
                    "description": redactor.redact_text(&request.description),
                    "method": request.method,
                    "url": redactor.redact_text(&request.url),
                    "protocol": request.protocol,
                    "protocolContext": request.protocol_context.as_ref().map(|value| redactor.redact_json_value(value)),
                    "dependencies": request.dependencies.iter().map(|dependency| redactor.redact_text(dependency)).collect::<Vec<_>>(),
                })
            }).collect::<Vec<_>>()
        },
        "plan": outcome.plan,
        "selectedRequests": outcome.selected_requests,
        "primaryTarget": outcome.primary_target,
        "executionFailed": outcome.execution_failed,
        "interrupted": outcome.interrupted.is_some(),
        "interruptSignal": outcome.interrupted.map(|signal| signal.as_str()),
        "records": outcome.records.iter().map(|record| run_record_json(record, body_options)).collect::<Vec<_>>(),
        "failures": outcome.failures.iter().map(|failure| request_failure_json(failure, body_options)).collect::<Vec<_>>(),
        "trace": outcome.trace.iter().map(execution_trace_json).collect::<Vec<_>>(),
    })
}

pub fn verification_result_json(result: &automation::VerificationResult) -> Value {
    json!({
        "path": result.path.as_ref().map(|path| path.display().to_string()),
        "name": result.summary.name,
        "description": result.summary.description,
        "availableEnvironments": result.summary.available_environments,
        "requiredInputs": result.required_inputs.iter().map(prompt_requirement_json).collect::<Vec<_>>(),
        "requests": result.summary.requests.iter().map(|request| {
            json!({
                "index": request.index,
                "description": request.description,
                "method": request.method,
                "url": request.url,
                "protocol": request.protocol,
                "protocolContext": request.protocol_context,
            })
        }).collect::<Vec<_>>(),
    })
}

pub fn hen_error_json(error: &HenError) -> Value {
    json!({
        "error": {
            "kind": error.kind().label(),
            "summary": error.summary(),
            "details": error.details(),
            "exitCode": error.exit_code(),
        }
    })
}

fn prompt_requirement_json(prompt: &PromptRequirement) -> Value {
    json!({
        "name": prompt.name,
        "default": prompt.default,
    })
}