"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
    for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DEFAULT_OUTPUT_FORMAT = exports.TERMINAL_PROVENANCE_LABELS = exports.OUTPUT_FORMATS = void 0;
exports.resolveOutputFormat = resolveOutputFormat;
exports.detectRequestedOutputFormat = detectRequestedOutputFormat;
exports.detectInvalidGlobalOutputFormat = detectInvalidGlobalOutputFormat;
exports.formatTerminalLongValue = formatTerminalLongValue;
exports.renderTerminalLabeledField = renderTerminalLabeledField;
exports.renderTerminalSummary = renderTerminalSummary;
exports.renderTerminalHeading = renderTerminalHeading;
exports.renderTerminalSection = renderTerminalSection;
exports.renderTerminalPathBlock = renderTerminalPathBlock;
exports.renderTerminalCompactList = renderTerminalCompactList;
exports.renderTerminalEmptyState = renderTerminalEmptyState;
exports.renderTerminalNextAction = renderTerminalNextAction;
exports.renderTerminalBoundary = renderTerminalBoundary;
exports.renderTerminalNoWriteEvidence = renderTerminalNoWriteEvidence;
exports.renderTerminalProvenanceField = renderTerminalProvenanceField;
exports.renderTerminalProvenance = renderTerminalProvenance;
exports.renderTerminalSafeValueMarker = renderTerminalSafeValueMarker;
exports.emitSuccess = emitSuccess;
exports.emitError = emitError;
exports.normalizeEmittedFailureContract = normalizeEmittedFailureContract;
exports.shouldEmitSupplementalHumanReadableText = shouldEmitSupplementalHumanReadableText;
exports.emitSupplementalHumanReadableText = emitSupplementalHumanReadableText;
const node_fs_1 = __importDefault(require("node:fs"));
const automation_protocol_1 = require("../automation-protocol");
const validation_1 = require("../automation-protocol/validation");
const output_safety_1 = require("./output-safety");
exports.OUTPUT_FORMATS = ["text", "json"];
__exportStar(require("./validation"), exports);
__exportStar(require("./command-capabilities"), exports);
__exportStar(require("./command-availability"), exports);
__exportStar(require("./command-descriptors"), exports);
__exportStar(require("./command-inventory"), exports);
__exportStar(require("./command-discovery"), exports);
__exportStar(require("./command-descriptor-projections"), exports);
__exportStar(require("./tool-manifest"), exports);
__exportStar(require("./structured-command-input"), exports);
__exportStar(require("./command-drift"), exports);
__exportStar(require("./projection"), exports);
__exportStar(require("./pagination"), exports);
__exportStar(require("./collection-pagination"), exports);
__exportStar(require("./budget"), exports);
__exportStar(require("./output-safety"), exports);
const projection_1 = require("./projection");
const pagination_1 = require("./pagination");
const collection_pagination_1 = require("./collection-pagination");
const budget_1 = require("./budget");
exports.TERMINAL_PROVENANCE_LABELS = {
    source: "Source",
    sourceLayer: "Source layer",
    configuredBy: "Configured by",
    default: "Default",
    commandInput: "Command input",
    environment: "Environment",
    runtimeDerived: "Runtime derived",
    scaffoldedVia: "Scaffolded via",
    generatedFrom: "Generated from"
};
exports.DEFAULT_OUTPUT_FORMAT = "text";
const defaultStdoutWrite = process.stdout.write;
const defaultStderrWrite = process.stderr.write;
const TERMINAL_CHILD_INDENT = "  ";
const TERMINAL_SAFE_VALUE_LABELS = {
    "local-state": "local state",
    "host-state": "host state",
    "environment-only": "environment-only",
    "command-input-only": "command input only",
    "future-candidate": "future candidate"
};
function resolveOutputFormat(value) {
    if (value === undefined || value === null || value === "") {
        return exports.DEFAULT_OUTPUT_FORMAT;
    }
    if (value === "text" || value === "json") {
        return value;
    }
    return null;
}
function detectRequestedOutputFormat(argv) {
    for (let index = 0; index < argv.length; index += 1) {
        const token = argv[index];
        if (token === "--format") {
            return resolveOutputFormat(argv[index + 1]) ?? exports.DEFAULT_OUTPUT_FORMAT;
        }
        if (token.startsWith("--format=")) {
            return resolveOutputFormat(token.slice("--format=".length)) ?? exports.DEFAULT_OUTPUT_FORMAT;
        }
    }
    return exports.DEFAULT_OUTPUT_FORMAT;
}
function detectInvalidGlobalOutputFormat(argv) {
    for (let index = 2; index < argv.length; index += 1) {
        const token = argv[index];
        if (token === "--") {
            return null;
        }
        if (token === "--format") {
            const value = argv[index + 1];
            if (value === undefined || value.startsWith("-")) {
                return null;
            }
            return resolveOutputFormat(value) === null ? value : null;
        }
        if (token.startsWith("--format=")) {
            const value = token.slice("--format=".length);
            return resolveOutputFormat(value) === null ? value : null;
        }
        if (!token.startsWith("-")) {
            return null;
        }
    }
    return null;
}
function formatTerminalLongValue(value) {
    if (value === null || value === undefined) {
        return "";
    }
    return String(value).replace(/\r\n?/g, "\n");
}
function renderTerminalLabeledField(field, indent = "") {
    const value = formatTerminalLongValue(field.value);
    if (value.includes("\n")) {
        return [
            `${indent}${field.label}:`,
            ...value.split("\n").map((line) => `${indent}${TERMINAL_CHILD_INDENT}${line}`)
        ].join("\n");
    }
    return `${indent}${field.label}: ${value}`;
}
function renderTerminalSummary(fields) {
    return fields.map((field) => renderTerminalLabeledField(field)).join("\n");
}
function renderTerminalHeading(heading, style = "plain") {
    if (style === "title") {
        const decorator = renderTerminalHeadingDecorator("=", heading);
        return [
            decorator,
            heading,
            decorator,
            ""
        ].join("\n");
    }
    if (style === "section") {
        const decorator = renderTerminalHeadingDecorator("*", heading);
        return [
            decorator,
            heading,
            decorator,
            ""
        ].join("\n");
    }
    return heading;
}
function renderTerminalHeadingDecorator(character, heading) {
    return character.repeat(Math.max(formatTerminalLongValue(heading).length, 1));
}
function renderTerminalSection(section) {
    return [
        renderTerminalHeading(section.heading, section.headingStyle),
        ...renderTerminalFieldsAndLines(section.fields ?? [], section.lines ?? [])
    ].join("\n");
}
function renderTerminalPathBlock(options) {
    const label = options.label ?? "Path";
    const lines = options.paths.length === 0
        ? [options.emptyMessage ?? "No paths found."]
        : options.paths.map((pathValue) => renderTerminalLabeledField({ label, value: pathValue }, TERMINAL_CHILD_INDENT));
    return joinOptionalHeading(options.heading, lines, options.headingStyle);
}
function renderTerminalCompactList(options) {
    const entrySeparator = options.entrySpacing === "loose" ? [""] : [];
    const lines = options.entries.length === 0
        ? [options.emptyMessage ?? "No entries found."]
        : options.entries.flatMap((entry, index) => [
            ...(index === 0 ? [] : entrySeparator),
            `${TERMINAL_CHILD_INDENT}- ${entry.label}`,
            ...renderTerminalFieldsAndLines(entry.fields ?? [], entry.lines ?? [], `${TERMINAL_CHILD_INDENT}${TERMINAL_CHILD_INDENT}`)
        ]);
    return joinOptionalHeading(options.heading, lines, options.headingStyle);
}
function renderTerminalEmptyState(options) {
    const lines = [
        renderTerminalLabeledField({ label: "Inspected", value: options.inspected }),
        renderTerminalLabeledField({ label: "Result", value: options.result })
    ];
    if (options.boundary) {
        lines.push(options.boundary);
    }
    if (options.nextAction) {
        lines.push(renderTerminalNextAction({ command: options.nextAction }));
    }
    return lines.join("\n");
}
function renderTerminalNextAction(action) {
    return renderTerminalLabeledField({ label: action.label ?? "Next Action", value: action.command });
}
function renderTerminalBoundary(options) {
    if (options.kind === "read-only") {
        if (options.evidence !== undefined) {
            return renderTerminalNoWriteEvidence(options.evidence);
        }
        return "Read-only: no files were changed.";
    }
    if (options.kind === "no-write-failure") {
        return `No write applied: ${formatTerminalSentence(options.reason)}`;
    }
    if (options.kind === "dry-run") {
        return "Dry run: planned changes only; no files were changed.";
    }
    if (options.kind === "force-gated-write") {
        return `Write requires --force: ${formatTerminalSentence(options.reason)}`;
    }
    const lines = [
        `Write applied: ${options.kind === "write-applied" ? "yes" : "no"}`
    ];
    if (options.target !== undefined) {
        lines.push(renderTerminalLabeledField({
            label: options.targetLabel ?? "Write target",
            value: options.target
        }));
    }
    if (options.stateSurface !== undefined) {
        lines.push(renderTerminalLabeledField({
            label: "State surface",
            value: options.stateSurface
        }));
    }
    if (options.kind === "mutating-no-op") {
        lines.push(renderTerminalLabeledField({
            label: "Reason",
            value: options.reason ?? "Target already matched the intended state."
        }));
    }
    return lines.join("\n");
}
function renderTerminalNoWriteEvidence(evidence) {
    const lines = [
        "Read-only: no files were changed.",
        renderTerminalLabeledField({ label: "Command posture", value: `${evidence.capability} / ${evidence.mutationPosture}` }),
        renderTerminalLabeledField({ label: "No-write reason", value: evidence.noWriteReason }),
        renderTerminalLabeledField({ label: "No-write boundary", value: evidence.noWriteBoundary }),
        renderTerminalLabeledField({ label: "Evidence only", value: evidence.evidenceOnly ? "yes" : "no" }),
        renderTerminalLabeledField({ label: "Finding severity lane", value: evidence.severity })
    ];
    if (evidence.recommendation !== undefined) {
        lines.push(renderTerminalLabeledField({
            label: evidence.recommendation.label,
            value: evidence.recommendation.command
        }), ...(evidence.recommendation.capability === undefined
            ? []
            : [
                renderTerminalLabeledField({
                    label: "Recommended command posture",
                    value: `${evidence.recommendation.capability} / ${evidence.recommendation.mutationPosture}`
                })
            ]), renderTerminalLabeledField({
            label: "Recommendation boundary",
            value: evidence.recommendation.boundary
        }));
    }
    return lines.join("\n");
}
function renderTerminalProvenanceField(field) {
    return renderTerminalLabeledField({
        label: exports.TERMINAL_PROVENANCE_LABELS[field.kind],
        value: field.value
    });
}
function renderTerminalProvenance(fields) {
    return fields.map((field) => renderTerminalProvenanceField(field)).join("\n");
}
function renderTerminalSafeValueMarker(options) {
    if (options.treatment === "redacted") {
        return `<redacted>:${formatTerminalLongValue(options.reasonOrFamily)}`;
    }
    if (options.treatment === "omitted") {
        return `omitted(${formatTerminalLongValue(options.reason)})`;
    }
    if (options.treatment === "summary") {
        return `summary(${formatTerminalLongValue(options.facts)})`;
    }
    return TERMINAL_SAFE_VALUE_LABELS[options.treatment];
}
function emitSuccess(options) {
    const safety = { repositoryRoot: process.cwd(), environment: process.env };
    const findings = (0, output_safety_1.sanitizeOutputValue)(options.findings ?? [], safety);
    if (options.format === "json") {
        const outputOptions = resolveProcessOutputProjectionOptions(options.command);
        const projected = (0, projection_1.projectOutput)((0, output_safety_1.sanitizeOutputValue)(options.data, safety), findings, bindPaginationToCommand(options.command, outputOptions, true));
        const envelope = {
            protocolVersion: (0, automation_protocol_1.getSelectedAutomationProtocolVersion)(),
            status: "ok",
            command: options.command,
            data: projected.data,
            output: projected.output,
            findings: projected.findings
        };
        writeJsonEnvelope((0, validation_1.validateAutomationEnvelope)(envelope), options.command, outputOptions);
        return;
    }
    if (typeof options.text === "function") {
        const outputOptions = resolveProcessOutputProjectionOptions(options.command);
        const boundOptions = bindPaginationToCommand(options.command, outputOptions, false);
        const projected = boundOptions.pagination === undefined
            ? undefined
            : (0, projection_1.projectOutput)((0, output_safety_1.sanitizeOutputValue)(options.data, safety), findings, boundOptions);
        const page = projected?.output.page;
        const continuationCommand = page?.nextCursor === null || page?.nextCursor === undefined
            ? undefined
            : (0, collection_pagination_1.createPageContinuationCommand)(process.argv, page.nextCursor);
        const text = options.text({
            data: (projected?.data ?? (0, output_safety_1.sanitizeOutputValue)(options.data, safety)),
            ...(page === undefined ? {} : { page }),
            ...(continuationCommand === undefined ? {} : { continuationCommand })
        });
        const withContinuation = continuationCommand === undefined
            ? text
            : `${text}\n\n${(0, collection_pagination_1.renderPageContinuation)(continuationCommand)}`;
        writeText((0, output_safety_1.sanitizeOutputText)(withContinuation, safety));
        return;
    }
    writeText((0, output_safety_1.sanitizeOutputText)(options.text, safety));
}
function emitError(options) {
    const safety = { repositoryRoot: process.cwd(), environment: process.env };
    const details = (0, output_safety_1.sanitizeOutputValue)(options.details ?? [], safety);
    const findings = (0, output_safety_1.sanitizeOutputValue)(options.findings ?? [], safety);
    if (options.format === "json") {
        const failure = normalizeEmittedFailureContract(options);
        const outputOptions = withoutPagination(resolveProcessOutputProjectionOptions(options.command));
        const projected = (0, projection_1.projectOutput)(options.data, findings, outputOptions);
        const envelope = {
            protocolVersion: (0, automation_protocol_1.getSelectedAutomationProtocolVersion)(),
            status: "error",
            command: options.command,
            output: projected.output,
            error: {
                code: options.code,
                message: (0, output_safety_1.sanitizeOutputText)(options.message, safety),
                ...failure,
                details,
                findings: projected.findings
            },
            ...(options.data === undefined ? {} : { data: projected.data })
        };
        writeJsonEnvelope((0, validation_1.validateAutomationEnvelope)(envelope), options.command, outputOptions, process.stderr);
        return;
    }
    const lines = [(0, output_safety_1.sanitizeOutputText)(options.message, safety), ...details];
    writeText(lines.join("\n"), process.stderr);
}
function normalizeEmittedFailureContract(options) {
    const usageFailure = options.code === "USAGE_ERROR" || options.code === "INVALID_CONFIG";
    const failure = {
        category: options.category ?? (usageFailure ? "invalid-input" : "unexpected-internal-failure"),
        exitClassification: options.exitClassification ?? (options.code === "INVALID_CONFIG" ? "invalid-config" : usageFailure ? "usage" : "error"),
        exitCode: options.exitCode ?? (options.code === "INVALID_CONFIG" ? 5 : usageFailure ? 3 : 2),
        retryable: options.retryable ?? usageFailure,
        writeOutcome: options.writeOutcome ?? "no-writes",
        recoveryActions: [...(options.recoveryActions ?? [])]
    };
    const expectedByExitCode = {
        2: ["unexpected-internal-failure", "error", false],
        3: ["invalid-input", "usage", true],
        4: ["unexpected-internal-failure", "unexpected", false],
        5: ["invalid-input", "invalid-config", true],
        6: ["stale-evidence", "stale-evidence", true],
        7: ["concurrency-conflict", "concurrency-conflict", true],
        8: ["unavailable-dependency", "unavailable-dependency", true],
        9: ["permission-failure", "permission-failure", false],
        10: ["partial-mutation", "partial-mutation", false],
        11: ["unsupported-capability", "unsupported-capability", false]
    };
    const expected = expectedByExitCode[failure.exitCode];
    if (expected === undefined || failure.category !== expected[0] || failure.exitClassification !== expected[1] || failure.retryable !== expected[2]) {
        throw new TypeError("Terminal failure category, exit classification/code, and retryability are contradictory.");
    }
    if (failure.writeOutcome === "complete") {
        throw new TypeError("A terminal failure cannot claim a completed write outcome.");
    }
    if ((failure.exitCode === 10) !== (failure.writeOutcome === "partial")) {
        throw new TypeError("Only partial-mutation failures may report a partial write outcome.");
    }
    if (failure.writeOutcome === "partial" && failure.recoveryActions.length === 0) {
        throw new TypeError("Partial-mutation failures require explicit recovery actions.");
    }
    if (failure.recoveryActions.length > 8) {
        throw new TypeError("Terminal failure recovery actions must contain at most 8 entries.");
    }
    return failure;
}
function shouldEmitSupplementalHumanReadableText(options) {
    return options.format !== "json" || options.humanReadableStreamEnabled === true;
}
function emitSupplementalHumanReadableText(options) {
    if (!shouldEmitSupplementalHumanReadableText(options)) {
        return false;
    }
    const stream = options.stream ?? (options.format === "json" ? process.stderr : process.stdout);
    writeText(options.text, stream);
    return true;
}
function writeText(text, stream = process.stdout) {
    writeToStream(stream, text.endsWith("\n") ? text : `${text}\n`);
}
function writeJsonEnvelope(value, command, options, stream = process.stdout) {
    const spacing = options.jsonSpacing
        ?? (options.detail === "compact" ? "compact" : "pretty");
    const byteBudget = options.outputBudget
        ?? (options.detail === "compact" && (0, budget_1.isApprovedBoundedReadCommand)(command)
            ? budget_1.DEFAULT_COMPACT_OUTPUT_BUDGET_BYTES
            : undefined);
    if (byteBudget === undefined) {
        writeToStream(stream, `${JSON.stringify(value, null, spacing === "pretty" ? 2 : undefined)}\n`);
        return;
    }
    const result = (0, budget_1.serializeBudgetedEnvelope)(value, { byteBudget, spacing });
    writeToStream(stream, result.text);
}
function resolveProcessOutputProjectionOptions(command) {
    try {
        const options = (0, projection_1.detectOutputProjectionOptions)(process.argv);
        const detailWasExplicit = process.argv.some((token) => token === "--detail" || token.startsWith("--detail="));
        return !detailWasExplicit
            && (0, automation_protocol_1.getSelectedAutomationProtocolVersion)() === 2
            && (0, budget_1.isApprovedBoundedReadCommand)(command)
            ? { ...options, detail: "compact" }
            : options;
    }
    catch {
        return { detail: "full" };
    }
}
function bindPaginationToCommand(command, options, allowAutomaticCompactCollection) {
    const profile = (0, collection_pagination_1.getCompactCollectionProfile)(command);
    const useAutomaticProfile = allowAutomaticCompactCollection
        && options.pageLane === undefined
        && options.detail === "compact"
        && (0, automation_protocol_1.getSelectedAutomationProtocolVersion)() === 2
        && profile !== undefined
        && (options.fields?.length === 0 || options.fields?.includes(profile.lane))
        && options.limits?.[profile.lane] === undefined;
    const lane = useAutomaticProfile ? profile.lane : options.pageLane;
    const pageSize = useAutomaticProfile ? profile.pageSize : options.pageSize;
    if (lane === undefined || pageSize === undefined)
        return options;
    const useCompactProfile = options.detail === "compact"
        && profile !== undefined
        && lane === profile.lane;
    const scope = (0, pagination_1.hashPaginationValue)({
        detail: options.detail ?? "full",
        findingCodes: options.findingCodes ?? [],
        severities: options.severities ?? [],
        fields: options.fields ?? [],
        limits: options.limits ?? {}
    });
    return {
        ...options,
        pagination: {
            command,
            scope,
            lane,
            pageSize,
            ...(options.pageCursor === undefined ? {} : { cursor: options.pageCursor })
        },
        ...(useCompactProfile ? { compactCollectionProfile: profile } : {})
    };
}
function withoutPagination(options) {
    const { pageLane: _pageLane, pageSize: _pageSize, pageCursor: _pageCursor, pagination: _pagination, ...rest } = options;
    return rest;
}
function renderTerminalFieldsAndLines(fields, lines, indent = TERMINAL_CHILD_INDENT) {
    return [
        ...fields.map((field) => renderTerminalLabeledField(field, indent)),
        ...lines.flatMap((line) => formatTerminalLongValue(line)
            .split("\n")
            .map((linePart) => `${indent}${linePart}`))
    ];
}
function joinOptionalHeading(heading, lines, style = "plain") {
    if (heading) {
        return [renderTerminalHeading(heading, style), ...lines].join("\n");
    }
    return lines.join("\n");
}
function formatTerminalSentence(value) {
    const text = formatTerminalLongValue(value).trim();
    if (/[.!?]$/u.test(text)) {
        return text;
    }
    return `${text}.`;
}
function writeToStream(stream, text) {
    if (canUseSynchronousFdWrite(stream)) {
        node_fs_1.default.writeSync(stream.fd, text, undefined, "utf8");
        return;
    }
    stream.write(text);
}
function canUseSynchronousFdWrite(stream) {
    if (typeof stream.fd !== "number") {
        return false;
    }
    if (stream === process.stdout) {
        return process.stdout.write === defaultStdoutWrite;
    }
    if (stream === process.stderr) {
        return process.stderr.write === defaultStderrWrite;
    }
    return true;
}
