git-subtree-dir: vendor/ruvector git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
196 lines
5.8 KiB
JavaScript
Executable File
196 lines
5.8 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Visualization Script for Simulation Results
|
|
* Generates charts and graphs from simulation data
|
|
*/
|
|
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
const args = process.argv.slice(2);
|
|
const reportFile = args[0] || findLatestReport();
|
|
|
|
if (!reportFile) {
|
|
console.error('❌ No report file found. Run a simulation first.');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`📊 Visualizing report: ${reportFile}\n`);
|
|
|
|
const report = JSON.parse(fs.readFileSync(reportFile, 'utf-8'));
|
|
|
|
// Generate ASCII charts
|
|
generateNodeGrowthChart(report);
|
|
generateEconomicChart(report);
|
|
generatePhaseTimeline(report);
|
|
generateHealthDashboard(report);
|
|
|
|
function findLatestReport() {
|
|
const reportsDir = path.join(__dirname, '../reports');
|
|
if (!fs.existsSync(reportsDir)) return null;
|
|
|
|
const files = fs.readdirSync(reportsDir)
|
|
.filter(f => f.endsWith('.json'))
|
|
.map(f => ({
|
|
name: f,
|
|
path: path.join(reportsDir, f),
|
|
time: fs.statSync(path.join(reportsDir, f)).mtime.getTime()
|
|
}))
|
|
.sort((a, b) => b.time - a.time);
|
|
|
|
return files.length > 0 ? files[0].path : null;
|
|
}
|
|
|
|
function generateNodeGrowthChart(report) {
|
|
console.log('📈 NODE GROWTH OVER TIME');
|
|
console.log('─'.repeat(70));
|
|
|
|
const transitions = report.phases.transitions;
|
|
const maxNodes = report.summary.totalNodes;
|
|
|
|
transitions.forEach((t, i) => {
|
|
const barLength = Math.floor((t.nodeCount / maxNodes) * 50);
|
|
const bar = '█'.repeat(barLength) + '░'.repeat(50 - barLength);
|
|
|
|
console.log(`${t.to.padEnd(15)} │${bar}│ ${t.nodeCount.toLocaleString()} nodes`);
|
|
});
|
|
|
|
console.log('\n');
|
|
}
|
|
|
|
function generateEconomicChart(report) {
|
|
console.log('💰 ECONOMIC DISTRIBUTION');
|
|
console.log('─'.repeat(70));
|
|
|
|
const { supply } = report.economics;
|
|
const total = supply.total || 1;
|
|
|
|
const pools = [
|
|
{ name: 'Contributors', value: supply.contributors, symbol: '█' },
|
|
{ name: 'Treasury', value: supply.treasury, symbol: '▓' },
|
|
{ name: 'Protocol', value: supply.protocol, symbol: '▒' },
|
|
{ name: 'Founders', value: supply.founders, symbol: '░' },
|
|
];
|
|
|
|
pools.forEach(pool => {
|
|
const percentage = (pool.value / total) * 100;
|
|
const barLength = Math.floor(percentage / 2);
|
|
const bar = pool.symbol.repeat(barLength);
|
|
|
|
console.log(
|
|
`${pool.name.padEnd(14)} │${bar.padEnd(50)}│ ` +
|
|
`${pool.value.toLocaleString().padStart(10)} rUv (${percentage.toFixed(1)}%)`
|
|
);
|
|
});
|
|
|
|
console.log('\n');
|
|
}
|
|
|
|
function generatePhaseTimeline(report) {
|
|
console.log('🔄 PHASE TRANSITION TIMELINE');
|
|
console.log('─'.repeat(70));
|
|
|
|
const transitions = report.phases.transitions;
|
|
|
|
transitions.forEach((t, i) => {
|
|
const arrow = i === 0 ? '├─' : '├─';
|
|
console.log(`${arrow}> ${t.from.toUpperCase()} → ${t.to.toUpperCase()}`);
|
|
console.log(`│ Tick: ${t.tick.toLocaleString()}`);
|
|
console.log(`│ Nodes: ${t.nodeCount.toLocaleString()}`);
|
|
console.log(`│ Compute: ${Math.floor(t.totalCompute).toLocaleString()} hours`);
|
|
if (i < transitions.length - 1) {
|
|
console.log('│');
|
|
}
|
|
});
|
|
|
|
console.log('└─> CURRENT: ' + report.summary.finalPhase.toUpperCase());
|
|
console.log('\n');
|
|
}
|
|
|
|
function generateHealthDashboard(report) {
|
|
console.log('🏥 NETWORK HEALTH DASHBOARD');
|
|
console.log('─'.repeat(70));
|
|
|
|
const metrics = [
|
|
{
|
|
name: 'Network Health',
|
|
value: report.metrics.networkHealth,
|
|
threshold: 0.7,
|
|
unit: '%'
|
|
},
|
|
{
|
|
name: 'Success Rate',
|
|
value: report.metrics.averageSuccessRate,
|
|
threshold: 0.85,
|
|
unit: '%'
|
|
},
|
|
{
|
|
name: 'Economic Stability',
|
|
value: report.economics.health.stability,
|
|
threshold: 0.6,
|
|
unit: '%'
|
|
},
|
|
{
|
|
name: 'Economic Velocity',
|
|
value: report.economics.health.velocity,
|
|
threshold: 0.3,
|
|
unit: ''
|
|
},
|
|
];
|
|
|
|
metrics.forEach(metric => {
|
|
const percentage = metric.unit === '%' ? metric.value * 100 : metric.value * 100;
|
|
const barLength = Math.floor(percentage / 2);
|
|
const status = metric.value >= metric.threshold ? '✓' : '✗';
|
|
const color = metric.value >= metric.threshold ? '🟢' : '🔴';
|
|
|
|
console.log(
|
|
`${status} ${metric.name.padEnd(20)} ${color} ` +
|
|
`${'█'.repeat(Math.floor(barLength))}${'░'.repeat(50 - Math.floor(barLength))} ` +
|
|
`${(metric.value * 100).toFixed(1)}${metric.unit}`
|
|
);
|
|
});
|
|
|
|
console.log('\n');
|
|
}
|
|
|
|
function generateGenesisAnalysis(report) {
|
|
console.log('👑 GENESIS NODE ANALYSIS');
|
|
console.log('─'.repeat(70));
|
|
|
|
const genesisNodes = report.nodes.genesis;
|
|
const totalGenesisRuv = genesisNodes.reduce((sum, n) => sum + n.ruvEarned, 0);
|
|
const totalGenesisTasks = genesisNodes.reduce((sum, n) => sum + n.tasksCompleted, 0);
|
|
const avgGenesisCompute = genesisNodes.reduce((sum, n) => sum + n.totalComputeHours, 0) / genesisNodes.length;
|
|
|
|
console.log(`Total Genesis Nodes: ${genesisNodes.length}`);
|
|
console.log(`Active Genesis Nodes: ${genesisNodes.filter(n => n.active).length}`);
|
|
console.log(`Total rUv Earned: ${totalGenesisRuv.toLocaleString()}`);
|
|
console.log(`Total Tasks Completed: ${totalGenesisTasks.toLocaleString()}`);
|
|
console.log(`Avg Compute per Node: ${Math.floor(avgGenesisCompute).toLocaleString()} hours`);
|
|
|
|
console.log('\nTop Genesis Contributors:');
|
|
const topGenesis = [...genesisNodes]
|
|
.sort((a, b) => b.ruvEarned - a.ruvEarned)
|
|
.slice(0, 5);
|
|
|
|
topGenesis.forEach((node, i) => {
|
|
console.log(
|
|
` ${(i + 1)}. ${node.id.padEnd(12)} - ` +
|
|
`${node.ruvEarned.toLocaleString().padStart(8)} rUv, ` +
|
|
`${node.tasksCompleted.toLocaleString().padStart(6)} tasks`
|
|
);
|
|
});
|
|
|
|
console.log('\n');
|
|
}
|
|
|
|
generateGenesisAnalysis(report);
|
|
|
|
console.log('✅ Visualization complete!\n');
|