#!/usr/bin/env node /** * Build unified dashboard data by calling export script: * 1. parse files → export to JSON * 2. embed in HTML * * Run: node agent-evolution/scripts/build-standalone-fixed.cjs */ const fs = require('fs'); const path = require('path'); const HTML_FILE = path.join(__dirname, '../index.html'); const OUTPUT_FILE = path.join(__dirname, '../index.standalone.html'); try { // Step 1: Export data to JSON console.log('Exporting data to JSON...'); const jsonData = require('./export-data-direct.cjs'); // ---------- Read HTML ---------- let html = fs.readFileSync(HTML_FILE, 'utf-8'); // ---------- Remove old hardcoded constants ---------- // Remove INLINE_RECOMMENDATIONS (lines ~1004-1016) const inlineRecPattern = /const INLINE_RECOMMENDATIONS = \[[\s\S]*?\];/; html = html.replace(inlineRecPattern, 'const INLINE_RECOMMENDATIONS = []; // REMOVED — data now comes from agentData, not hardcoded'); // Remove MODEL_BENCHMARKS line ~1021 (will be embedded in JSON) const bmPattern = /const MODEL_BENCHMARKS = \{[\s\S]*?\n\};/; html = html.replace(bmPattern, '/* MODEL_BENCHMARKS removed — data now in EMBEDDED_DATA.model_benchmarks */'); // ---------- Replace EMBEDDED_DATA section ---------- const startMarker = '// Default embedded data (minimal - updated by sync script)'; const endMarker = '};'; const startIdx = html.indexOf(startMarker); if (startIdx === -1) throw new Error('Start marker not found'); // Find the start of the EMBEDDED_DATA object const dataStartIdx = html.indexOf('const EMBEDDED_DATA = {', startIdx); if (dataStartIdx === -1) throw new Error('EMBEDDED_DATA start not found'); // Find the end of the EMBEDDED_DATA object (the closing brace followed by semicolon) const dataEndIdx = html.indexOf(endMarker, dataStartIdx) + endMarker.length; if (dataEndIdx === -1) throw new Error('EMBEDDED_DATA end not found'); // Create properly formatted JSON without HTML escaping const jsonStr = JSON.stringify(jsonData, null, 2); // Ensure HTML characters are not escaped in string literals // This is a workaround for JSON.stringify escaping < and > in some environments const safeJsonStr = jsonStr .replace(/\\u003c/g, '<') .replace(/\\u003e/g, '>'); const embeddedData = `// Unified data from REAL sources (${new Date().toISOString()}) // Sources: .kilo/agents/*.md + kilo-meta.json + model-benchmarks-verified.json const EMBEDDED_DATA = ${safeJsonStr};`; html = html.substring(0, dataStartIdx) + embeddedData + html.substring(dataEndIdx); // ---------- Replace init function ---------- const initStartPattern = /\/\/ Initialize\s*\n\s*async function init\(\)\s*\{/; const initStart = html.match(initStartPattern); if (initStart) { let brace = 0, inFn = false, endIdx = initStart.index; for (let i = initStart.index; i < html.length; i++) { if (html[i] === '{') { brace++; inFn = true; } else if (html[i] === '}') { brace--; if (inFn && brace === 0) { endIdx = i + 1; break; } } } const newInit = `// Initialize async function init() { agentData = EMBEDDED_DATA; try { document.getElementById('lastSync').textContent = formatDate(agentData.lastUpdated); document.getElementById('agentCount').textContent = agentData.evolution_metrics.total_agents + ' agents'; document.getElementById('historyCount').textContent = agentData.evolution_metrics.agents_with_history + ' with history'; if (agentData.evolution_metrics.total_agents === 0) { document.getElementById('lastSync').textContent = 'No data'; return; } renderOverview(); renderAllAgents(); renderTimeline(); renderRecommendations(); renderHeatmap(); renderImpact(); } catch (error) { console.error('Render error:', error); } }`; html = html.substring(0, initStart.index) + newInit + html.substring(endIdx); } // ---------- Heatmap: original renderHeatmap() in index.html is correct ---------- // ---------- Replace renderRecommendations function ---------- const recStartPattern = /function renderRecommendations\(\)\s*\{/; const recStart = html.match(recStartPattern); if (recStart) { let brace = 0, inFn = false, endIdx = recStart.index; for (let i = recStart.index; i < html.length; i++) { if (html[i] === '{') { brace++; inFn = true; } else if (html[i] === '}') { brace--; if (inFn && brace === 0) { endIdx = i + 1; break; } } } const newRec = `// Render Recommendations (only use agentData.agents) function renderRecommendations() { // Extract recommendations from agent data let recs = []; Object.entries(agentData.agents).forEach(([name, agent]) => { if (agent.current.recommendations && agent.current.recommendations.length > 0) { agent.current.recommendations.forEach(rec => { recs.push({ agent: name, current_model: agent.current.model, recommended_model: rec.target, impact: rec.priority || 'medium', score_before: rec.score_before || 0, score_after: rec.score_after || 0, score_delta: rec.score_delta || 0, rationale: rec.reason || '' }); }); } }); if (recs.length === 0) { document.getElementById('allRecommendations').innerHTML = '
No recommendations available
'; return; } document.getElementById('allRecommendations').innerHTML = recs.map((r, idx) => renderRecCard(r, idx)).join(''); }`; html = html.substring(0, recStart.index) + newRec + html.substring(endIdx); } // ---------- Write ---------- fs.writeFileSync(OUTPUT_FILE, html); fs.writeFileSync(path.join(__dirname, '../data/index.html'), html); console.log('\nBuilt standalone dashboard'); console.log(' Output:', OUTPUT_FILE); console.log(' Size:', (fs.statSync(OUTPUT_FILE).size / 1024).toFixed(1), 'KB'); } catch (error) { console.error('Error:', error.message); console.error(error.stack); process.exit(1); }