// tools/output-formatter.ts — SPEC-455: Smart output compression for tool responses
// Replaces raw JSON.stringify dumps with concise, LLM-friendly markdown output.
// Goal: reduce token consumption by 60%+ in tool responses.
const MAX_TABLE_ROWS = 30;
const MAX_LIST_ITEMS = 20;
function formatUnknown(value) {
    if (value === null || value === undefined) {
        return String(value);
    }
    if (typeof value === 'string') {
        return value;
    }
    if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
        return String(value);
    }
    if (typeof value === 'symbol') {
        return value.description ?? value.toString();
    }
    if (typeof value === 'function') {
        return '[function]';
    }
    return JSON.stringify(value);
}
/** Format a key-value object as concise markdown (no JSON dump) */
export function formatKeyValue(data, title) {
    const lines = [];
    if (title) {
        lines.push(`## ${title}`, '');
    }
    for (const [key, value] of Object.entries(data)) {
        if (value === undefined || value === null) {
            continue;
        }
        if (Array.isArray(value)) {
            lines.push(`**${key}**: ${value.length} items`);
        }
        else if (typeof value === 'object') {
            lines.push(`**${key}**: [object]`);
        }
        else if (typeof value === 'string') {
            lines.push(`**${key}**: ${value}`);
        }
        else {
            lines.push(`**${key}**: ${formatUnknown(value)}`);
        }
    }
    return lines.join('\n');
}
/** Format an array of objects as a markdown table */
export function formatTable(rows, columns, title) {
    if (rows.length === 0) {
        return title ? `## ${title}\n\nNo items.` : 'No items.';
    }
    const truncated = rows.length > MAX_TABLE_ROWS;
    const displayRows = truncated ? rows.slice(0, MAX_TABLE_ROWS) : rows;
    const lines = [];
    if (title) {
        lines.push(`## ${title}`, '');
    }
    // Header
    lines.push(`| ${columns.join(' | ')} |`);
    lines.push(`| ${columns.map(() => '---').join(' | ')} |`);
    // Rows
    for (const row of displayRows) {
        const cells = columns.map((col) => {
            const val = row[col];
            if (val === undefined || val === null) {
                return '-';
            }
            if (Array.isArray(val)) {
                return `${val.length}`;
            }
            const str = formatUnknown(val);
            return str.length > 60 ? `${str.slice(0, 57)}...` : str;
        });
        lines.push(`| ${cells.join(' | ')} |`);
    }
    if (truncated) {
        lines.push(`\n_...and ${rows.length - MAX_TABLE_ROWS} more_`);
    }
    return lines.join('\n');
}
/** Format a list of items as bullet points */
export function formatList(items, title) {
    const lines = [];
    if (title) {
        lines.push(`## ${title}`, '');
    }
    const truncated = items.length > MAX_LIST_ITEMS;
    const display = truncated ? items.slice(0, MAX_LIST_ITEMS) : items;
    for (const item of display) {
        lines.push(`- ${item}`);
    }
    if (truncated) {
        lines.push(`- _...and ${items.length - MAX_LIST_ITEMS} more_`);
    }
    return lines.join('\n');
}
/** Format a confirmation (write/update/delete operations) — ultra concise */
export function formatConfirmation(action, details) {
    const line = `Done: ${action}`;
    return details ? `${line}\n${details}` : line;
}
/** Format a score/health result */
export function formatScore(label, score, maxScore, issues) {
    const pct = Math.round((score / maxScore) * 100);
    const bar = pct >= 80 ? 'healthy' : pct >= 50 ? 'warning' : 'critical';
    const lines = [`**${label}**: ${score}/${maxScore} (${pct}%) — ${bar}`];
    if (issues && issues.length > 0) {
        for (const issue of issues.slice(0, 10)) {
            lines.push(`  - ${issue}`);
        }
        if (issues.length > 10) {
            lines.push(`  - _...and ${issues.length - 10} more_`);
        }
    }
    return lines.join('\n');
}
/** Format a config object showing only non-default values */
export function formatConfig(config, defaults, title) {
    const lines = [];
    if (title) {
        lines.push(`## ${title}`, '');
    }
    for (const [key, value] of Object.entries(config)) {
        if (value === undefined || value === null) {
            continue;
        }
        const isDefault = defaults?.[key] !== undefined && defaults[key] === value;
        const marker = isDefault ? '' : ' (custom)';
        const display = formatUnknown(value);
        lines.push(`- **${key}**: ${display}${marker}`);
    }
    return lines.join('\n');
}
/** Wrap formatted text into a ToolResult */
export function compactResult(text) {
    return { content: [{ type: 'text', text }] };
}
/** Wrap formatted text into an error ToolResult */
export function compactError(text) {
    return { content: [{ type: 'text', text }], isError: true };
}
/**
 * Smart fallback: if a tool hasn't been migrated yet, truncate JSON output
 * to avoid massive token consumption. Keeps first 30 lines + summary.
 */
export function compactJson(data, maxLines = 300) {
    const full = JSON.stringify(data, null, 2);
    const lines = full.split('\n');
    if (lines.length <= maxLines) {
        return full;
    }
    return [...lines.slice(0, maxLines), `\n... (${lines.length - maxLines} lines truncated)`].join('\n');
}
/**
 * Format a spec summary for list_specs output — most impactful optimization.
 * Replaces full spec JSON dumps with a concise table.
 */
export function formatSpecList(specs) {
    if (specs.length === 0) {
        return 'No specs found.';
    }
    return formatTable(specs.map((s) => ({
        ID: s.id ?? '-',
        Title: s.title ?? '-',
        Status: s.status ?? '-',
        Type: s.type ?? '-',
    })), ['ID', 'Title', 'Status', 'Type'], `Specs (${specs.length})`);
}
//# sourceMappingURL=output-formatter.js.map