/** * ReportGenerator * Generates a visual HTML dashboard based on the ContextComposition. * Apple-inspired design: clean whitespace, SF Pro typography, single blue accent. */ import type { ContextComposition } from "./analyzer"; import type { Insight } from "./insights"; export class ReportGenerator { public static generateHTML( composition: ContextComposition, insights: Insight[], contextWindow: number = 128_000, actualTokens?: number | null, ): string { // Use Pi's actual token count when available const total = actualTokens != null && actualTokens > 0 ? actualTokens : composition.total.tokens; const usagePercent = total > 0 ? Math.round((total / contextWindow) * 100) : 0; const fileCards = composition.files_detail .map( (file) => `
${ReportGenerator.escapeHtml(file.path)} ${file.weight.toLocaleString()}
${ReportGenerator.getOpIcon(file.lastOp.type)} · Turn ${file.lastOp.turn} ${file.status}
`, ) .join(""); const insightCards = insights .map( (insight, i) => `

${ReportGenerator.escapeHtml(insight.message)}

${insight.command ? `
${insight.command}
` : ""}
`, ) .join(""); return ` Context Profiler
Live

Context Profiler

Session context window breakdown with actionable recommendations

${total.toLocaleString()} Total Tokens
${composition.files_detail.length} Files
${insights.filter((i) => i.severity === "warning" || i.severity === "critical").length} Alerts
${(contextWindow / 1000).toFixed(0)}k Context Window
60 ? " warning" : ""}">
${usagePercent}% of ${(contextWindow / 1000).toFixed(0)}k window ${usagePercent > 80 ? "Compaction recommended" : usagePercent > 60 ? "Monitor usage" : "Healthy"}

Context Composition

${ReportGenerator.seg("seg-system", composition.system.percent)} ${ReportGenerator.seg("seg-tools", composition.tools.percent)} ${ReportGenerator.seg("seg-history", composition.history.percent)} ${ReportGenerator.seg("seg-files", composition.files.percent)} ${ReportGenerator.seg("seg-summaries", composition.summaries.percent)}
System — ${composition.system.tokens.toLocaleString()} (${composition.system.percent}%)
Tools — ${composition.tools.tokens.toLocaleString()} (${composition.tools.percent}%)
History — ${composition.history.tokens.toLocaleString()} (${composition.history.percent}%)
Files — ${composition.files.tokens.toLocaleString()} (${composition.files.percent}%)
Summaries — ${composition.summaries.tokens.toLocaleString()} (${composition.summaries.percent}%)

Insights

${insightCards || `

No insights available yet — the context composition is balanced.

`}

Files (${composition.files_detail.length})

${fileCards || '
No files tracked in the current session context.
'}
`; } private static seg(cls: string, pct: number): string { return pct > 0 ? `
` : ""; } private static getOpIcon(type: string): string { switch (type) { case "read": return "Read"; case "write": return "Write"; case "edit": return "Edit"; case "delete": return "Delete"; default: return "Access"; } } private static escapeHtml(text: string): string { return text .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """) .replace(/'/g, "'"); } /** Escape text for use in HTML attributes */ private static escapeAttr(text: string): string { return text .replace(/&/g, "&") .replace(/"/g, """) .replace(/'/g, "'") .replace(//g, ">"); } }