/**
 * Transform a Claude Code-style agent definition (Markdown with YAML
 * frontmatter) into a Codex CLI agent role TOML file.
 *
 * Claude Code agent shape:
 * ```
 * ---
 * name: bug-fixer
 * description: ...
 * tools: Read, Bash             # optional; preserved as compatibility context
 * model: sonnet                 # optional; preserved as compatibility context
 * skills: [skill-a, skill-b]    # optional; preserved in body as context
 * ---
 * # Body becomes developer_instructions
 * ```
 *
 * Codex agent shape (per `RawAgentRoleFileToml`, see
 * https://github.com/openai/codex/blob/main/codex-rs/core/src/config/agent_roles.rs):
 * ```toml
 * name = "lisa-bug-fixer"
 * description = "..."
 * developer_instructions = """
 * # Body...
 * """
 * ```
 *
 * The Codex deserializer rejects unknown top-level fields
 * (`#[serde(deny_unknown_fields)]`), so this transformer emits ONLY keys that
 * Codex's loader accepts.
 * @module codex/agent-transformer
 */
import { loadYaml } from "../utils/yaml.js";
/**
 * Prefix applied to every Lisa-owned Codex agent name. Provides
 * defense-in-depth on top of the directory-based ownership boundary
 * (`.codex/agents/lisa/`); makes it unambiguous in transcripts/logs which
 * agents Lisa manages.
 */
export const LISA_AGENT_NAME_PREFIX = "lisa-";
/**
 * Parse a Lisa agent Markdown source string into frontmatter + body.
 *
 * Throws on missing/malformed frontmatter or missing required fields, since
 * these would silently produce broken Codex agent files otherwise.
 * @param source - Raw contents of an agent .md file
 * @returns Parsed frontmatter and body
 */
export function parseAgentMarkdown(source) {
    const match = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/.exec(source);
    if (match === null || match[1] === undefined || match[2] === undefined) {
        throw new Error("Agent markdown is missing YAML frontmatter (expected leading --- block)");
    }
    const rawFrontmatter = match[1];
    const rawBody = match[2];
    const parsed = loadYaml(rawFrontmatter);
    const frontmatter = validateFrontmatter(parsed);
    return { frontmatter, body: rawBody.trimStart() };
}
/**
 * Transform a parsed agent into the Codex TOML representation as a string.
 * @param parsed - Output of parseAgentMarkdown
 * @param options - Transform options
 * @returns Serialized TOML matching Codex's `RawAgentRoleFileToml` schema
 */
export function transformAgentToToml(parsed, options = {}) {
    const applyPrefix = options.applyNamePrefix ?? true;
    const baseName = parsed.frontmatter.name;
    const codexName = applyPrefix
        ? `${LISA_AGENT_NAME_PREFIX}${baseName}`
        : baseName;
    const developerInstructions = composeDeveloperInstructions(parsed);
    const lines = [
        `name = ${tomlString(codexName)}`,
        `description = ${tomlString(parsed.frontmatter.description)}`,
        `developer_instructions = ${tomlMultilineString(developerInstructions)}`,
    ];
    return `${lines.join("\n")}\n`;
}
/**
 * One-shot helper: parse + transform.
 * @param source - Raw contents of an agent .md file
 * @param options - Transform options
 * @returns Serialized Codex agent TOML
 */
export function transformAgentMarkdownToToml(source, options = {}) {
    return transformAgentToToml(parseAgentMarkdown(source), options);
}
/**
 * Build the `developer_instructions` body. Claude Code agents sometimes carry
 * `skills:`, `tools:`, and `model:` in frontmatter. Codex rejects unknown TOML
 * fields, so Lisa preserves that metadata as normal instructions instead of
 * dropping it on the floor.
 * @param parsed - Output of parseAgentMarkdown for the source agent file
 * @returns The composed body to write into `developer_instructions`
 */
function composeDeveloperInstructions(parsed) {
    const compatibilityBlock = formatCompatibilityBlock(parsed.frontmatter);
    const skills = parsed.frontmatter.skills;
    const skillsBlock = skills === undefined || skills.length === 0
        ? ""
        : [
            "## Available Lisa Skills",
            "",
            "This agent operates in a Lisa-managed Codex environment with access to the following skills:",
            "",
            ...skills.map(s => `- ${s}`),
            "",
        ].join("\n");
    return [compatibilityBlock, skillsBlock, parsed.body.trimEnd()]
        .filter(block => block.length > 0)
        .join("\n\n");
}
/**
 * Validate frontmatter shape, throwing on missing required fields or wrong
 * types. Unknown fields are ignored to allow Lisa agents to carry harness-
 * specific keys without breaking the transformer.
 * @param parsed - Untrusted YAML mapping parsed from the agent's frontmatter
 * @returns The validated frontmatter with only the keys we recognize
 */
function validateFrontmatter(parsed) {
    if (parsed === null || typeof parsed !== "object") {
        throw new Error("Agent frontmatter must be a YAML mapping");
    }
    const obj = parsed;
    if (typeof obj.name !== "string" || obj.name.trim().length === 0) {
        throw new Error('Agent frontmatter is missing required "name" field');
    }
    if (typeof obj.description !== "string" ||
        obj.description.trim().length === 0) {
        throw new Error('Agent frontmatter is missing required "description" field');
    }
    const skills = parseSkills(obj.skills);
    return {
        name: obj.name,
        description: obj.description,
        ...(typeof obj.tools === "string" ? { tools: obj.tools } : {}),
        ...(typeof obj.model === "string" ? { model: obj.model } : {}),
        ...(skills !== undefined ? { skills } : {}),
    };
}
/**
 * Coerce the `skills` frontmatter field into a string array, or undefined.
 * @param raw - Untrusted value from the `skills` key (may be missing/wrong type)
 * @returns A frozen string array, or undefined if absent/empty
 */
function parseSkills(raw) {
    if (!Array.isArray(raw)) {
        return undefined;
    }
    const filtered = raw
        .filter((entry) => typeof entry === "string" && entry.length > 0)
        .map(entry => entry.startsWith(LISA_AGENT_NAME_PREFIX)
        ? entry
        : `${LISA_AGENT_NAME_PREFIX}${entry}`);
    return filtered.length > 0 ? Object.freeze(filtered) : undefined;
}
/**
 * Preserve Claude-only agent frontmatter inside Codex instructions.
 * @param frontmatter - Validated Claude agent metadata
 * @returns Markdown compatibility block, or an empty string when unnecessary
 */
function formatCompatibilityBlock(frontmatter) {
    const modelLines = frontmatter.model === undefined
        ? []
        : [
            `- Claude requested model: \`${frontmatter.model}\`. Use the active Codex model unless the host supplies a Codex agent override.`,
        ];
    const toolLines = frontmatter.tools === undefined
        ? []
        : [
            `- Claude allowed tools: \`${frontmatter.tools}\`. Codex tool access is governed by the active Codex runtime, sandbox, and project policy.`,
        ];
    const lines = [...modelLines, ...toolLines];
    if (lines.length === 0) {
        return "";
    }
    return ["## Claude Agent Compatibility", "", ...lines].join("\n");
}
/**
 * Emit a TOML basic string with proper escaping. Uses double-quoted form so
 * we can rely on standard escape sequences without worrying about literal
 * (single-quoted) string limitations.
 * @param value - The raw string to encode as a TOML basic string
 * @returns The encoded string including surrounding double quotes
 */
function tomlString(value) {
    const escaped = value
        .replaceAll("\\", "\\\\")
        .replaceAll('"', '\\"')
        .replaceAll("\n", "\\n")
        .replaceAll("\r", "\\r")
        .replaceAll("\t", "\\t");
    return `"${escaped}"`;
}
/**
 * Emit a TOML multi-line basic string, preserving newlines verbatim. The
 * leading newline after `"""` is part of TOML grammar — it is stripped by
 * the parser so authoring stays clean.
 *
 * Edge case: Markdown bodies sometimes contain literal `"""` (e.g., Python
 * docstring examples). We escape any closing triple-quote sequence by
 * inserting a backslash before the third quote.
 * @param value - The raw multi-line content to encode
 * @returns The encoded TOML multi-line string including surrounding triple-quotes
 */
function tomlMultilineString(value) {
    const escaped = value.replaceAll("\\", "\\\\").replaceAll('"""', '""\\"');
    return `"""\n${escaped}\n"""`;
}
//# sourceMappingURL=agent-transformer.js.map