// src/formatters/html-report-formatter.ts // Generates a comprehensive Bootstrap-based HTML report showing multi-round discussions import fs from 'fs'; import { AgentResult } from '../agents/agent.interface'; /** * Generate comprehensive HTML report with Bootstrap showing full multi-round discussion */ export function generateHtmlReport( results: AgentResult[], outputPath: string, metadata?: { commitHash?: string; timestamp?: string } ) { // All results are discussion agents now (no separate metrics agent) const discussionAgents = results; // Detect agent names from content patterns const detectAgentName = (result: AgentResult, idx: number): string => { const summary = result.summary?.toLowerCase() || ''; const details = result.details?.toLowerCase() || ''; const combined = summary + ' ' + details; // Business Analyst patterns if ( combined.includes('business analyst') || combined.includes('functional impact') || combined.includes('business value') || combined.includes('ideal time') ) { return 'Business Analyst'; } // QA Engineer patterns if ( combined.includes('qa engineer') || combined.includes('test coverage') || combined.includes('quality assurance') || combined.includes('testing') ) { return 'QA Engineer'; } // Developer (Author) patterns if ( combined.includes('developer (author)') || combined.includes('actual time') || combined.includes('implementation approach') || combined.includes('spent about') ) { return 'Developer (Author)'; } // Senior Architect patterns if ( combined.includes('senior architect') || combined.includes('architect') || combined.includes('code complexity') || combined.includes('technical debt') || combined.includes('architectural') ) { return 'Senior Architect'; } // Developer Reviewer patterns if ( combined.includes('developer reviewer') || combined.includes('code reviewer') || combined.includes('code quality') || combined.includes('refactoring') || combined.includes('looking at the code') ) { return 'Developer Reviewer'; } return `Agent ${idx + 1}`; }; // Generate agent discussion cards const agentCardsHtml = discussionAgents .map((agent, idx) => { const agentName = detectAgentName(agent, idx); const iconMap: Record = { 'Business Analyst': '๐Ÿ‘”', 'QA Engineer': '๐Ÿงช', 'Developer (Author)': '', 'Senior Architect': '๐Ÿ›๏ธ', 'Developer Reviewer': '๐Ÿ‘จโ€๐Ÿ’ป', }; const icon = iconMap[agentName] || '๐Ÿค–'; const colorMap: Record = { 'Business Analyst': 'info', 'QA Engineer': 'warning', 'Developer (Author)': 'success', 'Senior Architect': 'primary', 'Developer Reviewer': 'secondary', }; const color = colorMap[agentName] || 'secondary'; const summary = agent.summary || 'No summary provided'; const details = agent.details || 'No details provided'; // Format details with proper line breaks and markdown-like formatting const formattedDetails = details .replace(/\*\*(.*?)\*\*/g, '$1') // Bold .replace(/\*(.*?)\*/g, '$1') // Italic .replace(/\n/g, '
') // Line breaks .replace(/^(\d+\.\s)/gm, '
$1'); // Numbered lists return `
${icon} ${agentName}
๐Ÿ“‹ Summary

${summary}

๐Ÿ“ Detailed Analysis
${formattedDetails}
`; }) .join('\n'); // Aggregate all metrics from all agents const allMetrics: Record = {}; discussionAgents.forEach((agent) => { if (agent.metrics) { Object.assign(allMetrics, agent.metrics); } }); // Generate metrics summary table let metricsHtml = ''; if (Object.keys(allMetrics).length > 0) { const metricsRows = Object.entries(allMetrics) .map(([key, value]) => { const label = key .replace(/([A-Z])/g, ' $1') .replace(/^./, (str) => str.toUpperCase()) .trim(); // Color code metrics based on value let badge = 'secondary'; if (typeof value === 'number') { // Standard scales (higher is better) if ( key.toLowerCase().includes('quality') || key.toLowerCase().includes('coverage') || key.toLowerCase().includes('impact') || key.toLowerCase().includes('commitscore') ) { badge = value >= 7 ? 'success' : value >= 4 ? 'warning' : 'danger'; } // Inverted scale (lower is better) - Code Complexity else if (key.toLowerCase().includes('complexity')) { badge = value <= 3 ? 'success' : value <= 6 ? 'warning' : 'danger'; } // Technical debt (negative is good, positive is bad) else if (key.toLowerCase().includes('debt')) { badge = value <= 0 ? 'success' : value <= 4 ? 'warning' : 'danger'; } } return ` ${label} ${value} `; }) .join(''); metricsHtml = `
๐Ÿ“Š Evaluation Metrics (7 Pillars)
${metricsRows}
Metric Score
`; } const html = ` Commit Evaluation Report

๐Ÿ” Commit Evaluation Report

AI-Powered Multi-Agent Code Review

${metadata?.commitHash ? `
Commit: ${metadata.commitHash}
` : ''} Generated on ${metadata?.timestamp || new Date().toLocaleString()}

๐Ÿ’ฌ Agent Discussions

${agentCardsHtml} ${metricsHtml}
Generated by Commit Evaluator using LangGraph workflows
`; fs.writeFileSync(outputPath, html, 'utf-8'); }