localgreenchain/deploy/NetworkDiscoveryAgent.ts
Claude 5e8ae1e259
Add NetworkDiscoveryAgent deployment script (Agent 8)
Create standalone deployment entry point for the Network Discovery Agent
that maps and analyzes geographic distribution of the plant network.
Includes status reporting, graceful shutdown, and configurable options.
2025-11-23 00:27:10 +00:00

263 lines
8.7 KiB
TypeScript

#!/usr/bin/env bun
/**
* NetworkDiscoveryAgent Deployment Script
* Agent 8 - Geographic Network Discovery and Analysis
*
* This script provides standalone deployment for the NetworkDiscoveryAgent,
* which maps and analyzes the geographic distribution of the plant network.
*
* Responsibilities:
* - Map plant distribution across regions
* - Identify network hotspots and clusters
* - Suggest grower/consumer connections
* - Track network growth patterns
* - Detect coverage gaps
*
* Usage:
* bun run deploy/NetworkDiscoveryAgent.ts
* bun run deploy:network-discovery
*
* Environment Variables:
* AGENT_INTERVAL_MS - Execution interval (default: 600000 = 10 min)
* AGENT_LOG_LEVEL - Log level: debug, info, warn, error (default: info)
* AGENT_AUTO_RESTART - Auto-restart on failure (default: true)
* AGENT_MAX_RETRIES - Max retry attempts (default: 3)
*/
import { getNetworkDiscoveryAgent, NetworkDiscoveryAgent } from '../lib/agents/NetworkDiscoveryAgent';
// Configuration from environment
const config = {
intervalMs: parseInt(process.env.AGENT_INTERVAL_MS || '600000'),
logLevel: process.env.AGENT_LOG_LEVEL || 'info',
autoRestart: process.env.AGENT_AUTO_RESTART !== 'false',
maxRetries: parseInt(process.env.AGENT_MAX_RETRIES || '3'),
};
// Logger utility
const log = {
debug: (...args: any[]) => config.logLevel === 'debug' && console.log('[DEBUG]', ...args),
info: (...args: any[]) => ['debug', 'info'].includes(config.logLevel) && console.log('[INFO]', ...args),
warn: (...args: any[]) => ['debug', 'info', 'warn'].includes(config.logLevel) && console.warn('[WARN]', ...args),
error: (...args: any[]) => console.error('[ERROR]', ...args),
};
/**
* Format uptime as human-readable string
*/
function formatUptime(ms: number): string {
const seconds = Math.floor(ms / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`;
if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
if (minutes > 0) return `${minutes}m ${seconds % 60}s`;
return `${seconds}s`;
}
/**
* Display agent status
*/
function displayStatus(agent: NetworkDiscoveryAgent): void {
const metrics = agent.getMetrics();
const analysis = agent.getNetworkAnalysis();
const clusters = agent.getClusters();
const gaps = agent.getCoverageGaps();
const suggestions = agent.getConnectionSuggestions();
const growth = agent.getGrowthHistory();
const regions = agent.getRegionalStats();
console.log('\n' + '='.repeat(60));
console.log(' NETWORK DISCOVERY AGENT - STATUS REPORT');
console.log('='.repeat(60));
// Agent Metrics
console.log('\n AGENT METRICS');
console.log(' ' + '-'.repeat(40));
console.log(` Status: ${agent.status}`);
console.log(` Uptime: ${formatUptime(metrics.uptime)}`);
console.log(` Tasks Completed: ${metrics.tasksCompleted}`);
console.log(` Tasks Failed: ${metrics.tasksFailed}`);
console.log(` Avg Execution: ${Math.round(metrics.averageExecutionMs)}ms`);
console.log(` Last Run: ${metrics.lastRunAt || 'Never'}`);
// Network Analysis
console.log('\n NETWORK ANALYSIS');
console.log(' ' + '-'.repeat(40));
console.log(` Total Nodes: ${analysis.totalNodes}`);
console.log(` Connections: ${analysis.totalConnections}`);
console.log(` Clusters: ${clusters.length}`);
console.log(` Hotspots: ${analysis.hotspots.length}`);
console.log(` Coverage Gaps: ${gaps.length}`);
console.log(` Suggestions: ${suggestions.length}`);
// Cluster Details
if (clusters.length > 0) {
console.log('\n TOP CLUSTERS');
console.log(' ' + '-'.repeat(40));
const topClusters = clusters.slice(0, 5);
for (const cluster of topClusters) {
console.log(` - ${cluster.activityLevel.toUpperCase()} activity cluster`);
console.log(` Nodes: ${cluster.nodes.length}, Radius: ${cluster.radius}km`);
if (cluster.dominantSpecies.length > 0) {
console.log(` Species: ${cluster.dominantSpecies.slice(0, 3).join(', ')}`);
}
}
}
// Coverage Gaps
if (gaps.length > 0) {
console.log('\n COVERAGE GAPS');
console.log(' ' + '-'.repeat(40));
for (const gap of gaps.slice(0, 3)) {
console.log(` - ${gap.populationDensity.toUpperCase()} area`);
console.log(` Distance to nearest: ${gap.distanceToNearest}km`);
console.log(` Potential demand: ${gap.potentialDemand}`);
}
}
// Top Suggestions
if (suggestions.length > 0) {
console.log('\n TOP CONNECTION SUGGESTIONS');
console.log(' ' + '-'.repeat(40));
for (const suggestion of suggestions.slice(0, 3)) {
console.log(` - Strength: ${suggestion.strength}%`);
console.log(` Distance: ${suggestion.distance}km`);
console.log(` Reason: ${suggestion.reason}`);
}
}
// Regional Stats
if (regions.length > 0) {
console.log('\n REGIONAL STATISTICS');
console.log(' ' + '-'.repeat(40));
for (const region of regions) {
if (region.nodeCount > 0) {
console.log(` ${region.region}:`);
console.log(` Nodes: ${region.nodeCount}, Plants: ${region.plantCount}`);
console.log(` Species: ${region.uniqueSpecies}, Activity: ${region.avgActivityScore}`);
}
}
}
// Growth Trend
if (growth.length > 0) {
const latest = growth[growth.length - 1];
console.log('\n NETWORK GROWTH');
console.log(' ' + '-'.repeat(40));
console.log(` Total Nodes: ${latest.totalNodes}`);
console.log(` Total Connections: ${latest.totalConnections}`);
console.log(` New Nodes/Week: ${latest.newNodesWeek}`);
console.log(` Geographic Span: ${latest.geographicExpansion}km`);
}
// Alerts
const alerts = agent.getAlerts();
const unacknowledged = alerts.filter(a => !a.acknowledged);
if (unacknowledged.length > 0) {
console.log('\n ACTIVE ALERTS');
console.log(' ' + '-'.repeat(40));
for (const alert of unacknowledged.slice(0, 5)) {
console.log(` [${alert.severity.toUpperCase()}] ${alert.title}`);
console.log(` ${alert.message}`);
}
}
console.log('\n' + '='.repeat(60));
}
/**
* Main deployment function
*/
async function deploy(): Promise<void> {
console.log('\n' + '='.repeat(60));
console.log(' DEPLOYING NETWORK DISCOVERY AGENT (Agent 8)');
console.log('='.repeat(60));
console.log(`\n Configuration:`);
console.log(` - Interval: ${config.intervalMs}ms (${config.intervalMs / 60000} min)`);
console.log(` - Log Level: ${config.logLevel}`);
console.log(` - Auto Restart: ${config.autoRestart}`);
console.log(` - Max Retries: ${config.maxRetries}`);
console.log('');
// Get agent instance
const agent = getNetworkDiscoveryAgent();
// Register event handlers
agent.on('task_completed', (data) => {
log.info(`Task completed: ${JSON.stringify(data.result)}`);
});
agent.on('task_failed', (data) => {
log.error(`Task failed: ${data.error}`);
});
agent.on('agent_started', () => {
log.info('Network Discovery Agent started');
});
agent.on('agent_stopped', () => {
log.info('Network Discovery Agent stopped');
});
// Start the agent
log.info('Starting Network Discovery Agent...');
try {
await agent.start();
log.info('Agent started successfully');
// Run initial discovery
log.info('Running initial network discovery...');
await agent.runOnce();
log.info('Initial discovery complete');
// Display initial status
displayStatus(agent);
// Set up periodic status display
const statusInterval = setInterval(() => {
displayStatus(agent);
}, config.intervalMs);
// Handle shutdown signals
const shutdown = async (signal: string) => {
log.info(`Received ${signal}, shutting down...`);
clearInterval(statusInterval);
try {
await agent.stop();
log.info('Agent stopped gracefully');
process.exit(0);
} catch (error) {
log.error('Error during shutdown:', error);
process.exit(1);
}
};
process.on('SIGINT', () => shutdown('SIGINT'));
process.on('SIGTERM', () => shutdown('SIGTERM'));
// Keep the process running
log.info(`Agent running. Press Ctrl+C to stop.`);
log.info(`Next discovery in ${config.intervalMs / 60000} minutes...`);
} catch (error) {
log.error('Failed to start agent:', error);
if (config.autoRestart) {
log.info('Auto-restart enabled, retrying in 10 seconds...');
setTimeout(() => deploy(), 10000);
} else {
process.exit(1);
}
}
}
// Run deployment
deploy().catch((error) => {
console.error('Deployment failed:', error);
process.exit(1);
});