#!/usr/bin/env bun /** * Build APAW Agent Model Research Dashboard from live data. * * Reads model-benchmarks.json and injects into template HTML. * Creates standalone dashboard with embedded JSON data. * * Usage: * bun run agent-evolution/scripts/build-research-dashboard.ts # build once * bun run agent-evolution/scripts/build-research-dashboard.ts --watch # watch mode * bun run agent-evolution/scripts/build-research-dashboard.ts --template path/to/custom.html */ import { existsSync, readFileSync, writeFileSync, watch } from 'fs'; import { join, dirname, basename } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const DATA_FILE = join(__dirname, '../data/model-benchmarks.json'); const DEFAULT_TEMPLATE = join(__dirname, '../research-dashboard.template.html'); const OUTPUT_FILE = join(__dirname, '../research-dashboard.html'); const DIST_DIR = join(__dirname, '../dist'); interface BenchmarksData { version: string; generated: string; source: string; total_agents: number; total_models_tracked: number; providers: string[]; models: any[]; agent_model_scores: any[]; agent_current_config: any[]; groq_models: any[]; recommendations: any[]; impact_data: any[]; } function buildDashboard(templatePath: string = DEFAULT_TEMPLATE): boolean { console.log('š§ Building APAW Agent Model Research Dashboard'); // Validate inputs if (!existsSync(DATA_FILE)) { console.error(`ā Data file not found: ${DATA_FILE}`); console.error(' Please run research cycle first: bun run /research models'); return false; } if (!existsSync(templatePath)) { console.error(`ā Template file not found: ${templatePath}`); console.error(' Using default template:', DEFAULT_TEMPLATE); if (!existsSync(DEFAULT_TEMPLATE)) { console.error(' Default template also missing. Create template first.'); return false; } templatePath = DEFAULT_TEMPLATE; } // Read and validate JSON data let data: BenchmarksData; try { const rawData = readFileSync(DATA_FILE, 'utf-8'); data = JSON.parse(rawData); console.log(`š Read model-benchmarks.json (${rawData.length} bytes)`); } catch (error) { console.error(`ā Failed to parse JSON data: ${error}`); return false; } // Validate required fields if (!data.models || !Array.isArray(data.models)) { console.error('ā Missing or invalid "models" array in data'); return false; } if (!data.agent_model_scores || !Array.isArray(data.agent_model_scores)) { console.error('ā Missing or invalid "agent_model_scores" array in data'); return false; } console.log(` Models: ${data.models.length}`); console.log(` Agents: ${data.agent_model_scores.length}`); console.log(` Providers: ${data.providers?.join(', ') || 'unknown'}`); console.log(` Generated: ${data.generated}`); // Read HTML template let html: string; try { html = readFileSync(templatePath, 'utf-8'); console.log(`š Read template: ${templatePath} (${html.length} bytes)`); } catch (error) { console.error(`ā Failed to read template: ${error}`); return false; } // Find and replace placeholder ā must match exact text in template const placeholder = '// BENCHMARK_DATA_PLACEHOLDER - will be replaced by build script\nconst EMBEDDED_DATA = {};\n'; if (!html.includes(placeholder)) { // Try looser match with any line endings const loosePlaceholder = html.match(/\/\/\s*BENCHMARK_DATA_PLACEHOLDER[^\n]*\r?\n\s*const\s+EMBEDDED_DATA\s*=\s*\{\}\s*;\r?\n/); if (!loosePlaceholder) { console.error('ā Placeholder not found in template'); console.error(' Expected: "// BENCHMARK_DATA_PLACEHOLDER - will be replaced by build script\\nconst EMBEDDED_DATA = {};\\n"'); const match = html.match(/BENCHMARK_DATA_PLACEHOLDER/); if (match) { const start = Math.max(0, match.index - 20); const end = Math.min(html.length, match.index + 120); console.error(' Found near:', JSON.stringify(html.slice(start, end))); } return false; } html = html.replace(loosePlaceholder[0], `// BENCHMARK_DATA_PLACEHOLDER - REPLACED BY BUILD SCRIPT\n// Generated from ${basename(DATA_FILE)} on ${new Date().toISOString()}\nconst EMBEDDED_DATA = ${JSON.stringify(data, null, 2)};\n`); } else { html = html.replace(placeholder, `// BENCHMARK_DATA_PLACEHOLDER - REPLACED BY BUILD SCRIPT\n// Generated from ${basename(DATA_FILE)} on ${new Date().toISOString()}\nconst EMBEDDED_DATA = ${JSON.stringify(data, null, 2)};\n`); } // Update title with metadata if present (match any tag with APAW... in it) const titleRegex = /