#!/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 { 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); });