Files
APAW/agent-evolution/scripts/build-standalone.cjs
¨NW¨ 15a7b4b7a4 feat: add Agent Evolution Dashboard
- Create agent-evolution/ directory with standalone dashboard
- Add interactive HTML dashboard with agent/model matrix
- Add heatmap view for agent-model compatibility scores
- Add recommendations tab with optimization suggestions
- Add Gitea integration preparation (history timeline)
- Add Docker configuration for deployment
- Add build scripts for standalone HTML generation
- Add sync scripts for agent data synchronization
- Add milestone and issues documentation
- Add skills and rules for evolution sync
- Update AGENTS.md with dashboard documentation
- Update package.json with evolution scripts

Features:
- 28 agents with model assignments and fit scores
- 8 models with benchmarks (SWE-bench, RULER, Terminal)
- 11 recommendations for model optimization
- History timeline with agent changes
- Interactive modal windows for model details
- Filter and search functionality
- Russian language interface
- Works offline (file://) with embedded data

Docker:
- Dockerfile for standalone deployment
- docker-compose.evolution.yml
- docker-run.sh/docker-run.bat scripts

NPM scripts:
- sync:evolution - sync and build dashboard
- evolution:open - open in browser
- evolution:dashboard - start dev server

Status: PAUSED - foundation complete, Gitea integration pending
2026-04-05 19:58:59 +01:00

117 lines
4.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Build standalone HTML with embedded data
* Run: node agent-evolution/scripts/build-standalone.cjs
*/
const fs = require('fs');
const path = require('path');
const DATA_FILE = path.join(__dirname, '../data/agent-versions.json');
const HTML_FILE = path.join(__dirname, '../index.html');
const OUTPUT_FILE = path.join(__dirname, '../index.standalone.html');
try {
// Read data
console.log('📖 Reading data from:', DATA_FILE);
const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf-8'));
console.log(' Found', Object.keys(data.agents).length, 'agents');
// Read HTML
console.log('📖 Reading HTML from:', HTML_FILE);
let html = fs.readFileSync(HTML_FILE, 'utf-8');
// Step 1: Replace EMBEDDED_DATA
const startMarker = '// Default embedded data (minimal - updated by sync script)';
const endPattern = /"sync_sources":\s*\[[^\]]*\]\s*\}\s*\};/;
const startIdx = html.indexOf(startMarker);
const endMatch = html.match(endPattern);
if (startIdx === -1) {
throw new Error('Start marker not found in HTML');
}
if (!endMatch) {
throw new Error('End pattern not found in HTML');
}
const endIdx = endMatch.index + endMatch[0].length + 1;
// Create embedded data
const embeddedData = `// Embedded data (generated ${new Date().toISOString()})
const EMBEDDED_DATA = ${JSON.stringify(data, null, 2)};`;
// Replace the section
html = html.substring(0, startIdx) + embeddedData + html.substring(endIdx);
// Step 2: Replace entire init function
// Find the init function start and end
const initStartPattern = /\/\/ Initialize\s*\n\s*async function init\(\) \{/;
const initStartMatch = html.match(initStartPattern);
if (initStartMatch) {
const initStartIdx = initStartMatch.index;
// Find matching closing brace (count opening and closing)
let braceCount = 0;
let inFunction = false;
let initEndIdx = initStartIdx;
for (let i = initStartIdx; i < html.length; i++) {
if (html[i] === '{') {
braceCount++;
inFunction = true;
} else if (html[i] === '}') {
braceCount--;
if (inFunction && braceCount === 0) {
initEndIdx = i + 1;
break;
}
}
}
// New init function
const newInit = `// Initialize
async function init() {
// Use embedded data directly (works with file://)
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 - run sync:evolution';
return;
}
renderOverview();
renderAllAgents();
renderTimeline();
renderRecommendations();
renderMatrix();
} catch (error) {
console.error('Failed to render dashboard:', error);
document.getElementById('lastSync').textContent = 'Error rendering data';
}
}`;
html = html.substring(0, initStartIdx) + newInit + html.substring(initEndIdx);
}
// Write output
fs.writeFileSync(OUTPUT_FILE, html);
console.log('\n✅ Built standalone dashboard');
console.log(' Output:', OUTPUT_FILE);
console.log(' Agents:', Object.keys(data.agents).length);
console.log(' Size:', (fs.statSync(OUTPUT_FILE).size / 1024).toFixed(1), 'KB');
console.log('\n📊 Open in browser:');
console.log(' Windows: start agent-evolution\\index.standalone.html');
console.log(' macOS: open agent-evolution/index.standalone.html');
console.log(' Linux: xdg-open agent-evolution/index.standalone.html');
} catch (error) {
console.error('❌ Error:', error.message);
process.exit(1);
}