Skill: rhanxerox/rhandus-alerting-system (version 1.0.0)

--- name: alerting-system description: "Centralized alerting and notification system for OpenClaw. Multi-channel alerts, intelligent rules, escalation, and audit." license: MIT metadata: author: Rhandus Malpica company: Tiklick website: https://tiklick.com version: "1.0.0" openclaw: emoji: "🚨" ui: color: "#FF4444" icon: "bell" --- # Alerting & Notification System Sistema centralizado de alertas y notificaciones para OpenClaw. Alertas multi-canal, reglas inteligentes, escalación y auditoría. ## 🎯 Objetivo Permitir que OpenClaw sea **proactivo** en lugar de reactivo, detectando problemas y notificando automáticamente antes de que impacten operaciones. ## 📋 Características ### Nivel 1 (Semana 1 - Base): - ✅ **Multi-canal:** Telegram, Email (Gmail), Log - ✅ **Reglas básicas:** Umbrales, patrones, horarios - ✅ **Prioridades:** Info, Warning, Critical, Emergency - ✅ **Agrupación:** Alertas relacionadas agrupadas - ✅ **Historial:** Auditoría completa de alertas ### Nivel 2 (Semana 2 - Avanzado): - 🔄 **Escalación automática:** Si no hay respuesta - 📊 **Dashboard web:** Visualización en tiempo real - 🤖 **Auto-resolución:** Alertas que se resuelven solas - 📈 **Análisis:** Patrones y tendencias de alertas - 🔗 **Integraciones:** Webhooks, Slack, etc. ### Nivel 3 (Semana 3 - Inteligente): - 🧠 **Aprendizaje:** Reduce falsos positivos - ⏰ **Horarios inteligentes:** Respeta horas no laborales - 👥 **Routing:** Enruta a persona correcta - 📱 **Mobile:** Notificaciones push - 🔄 **Feedback loop:** Mejora continua ## 🚀 Uso ### Comandos Principales: #### `alert monitor` Monitorea un endpoint o recurso. ```bash # Monitorear API Tiklick alert monitor https://api.tiklick.com/health --interval 60 --channel telegram # Monitorear archivo de log alert monitor /var/log/tiklick_app.log --pattern "ERROR\|CRITICAL" --channel email # Monitorear métrica del sistema alert monitor system.cpu --threshold 80 --duration 300 --channel both ``` #### `alert threshold` Configura alertas basadas en umbrales. ```bash # Ventas mínimas diarias alert threshold /workspace/ventas.csv --column "total" --min 1000000 --channel email # Uso máximo de disco alert threshold system.disk --path /workspace --max 90 --channel telegram # Tiempo respuesta API alert threshold api.response_time --url https://api.tiklick.com --max 2000 --channel both ``` #### `alert pattern` Busca patrones en logs o datos. ```bash # Errores críticos en logs alert pattern /var/log/app.log --pattern "FATAL\|SEGFAULT\|OutOfMemory" --channel telegram # Intentos fallidos de login alert pattern /var/log/auth.log --pattern "Failed password" --count 5 --window 300 --channel email # Patrones de seguridad alert pattern security --type "brute_force\|sql_injection\|xss" --channel both ``` #### `alert status` Muestra estado de alertas. ```bash # Alertas activas alert status --active # Historial de alertas alert status --history --days 7 # Resumen estadístico alert status --stats ``` #### `alert resolve` Marca alertas como resueltas. ```bash # Resolver alerta específica alert resolve ALERT-1234 # Resolver todas de un servicio alert resolve --service api-tiklick # Auto-resolver después de verificación alert resolve --auto --check "curl -s https://api.tiklick.com/health" ``` ## ⚙️ Configuración ### Canales Disponibles: 1. **telegram** - Notificación inmediata a Telegram 2. **email** - Email a lista configurada 3. **log** - Registro en archivo de log 4. **dashboard** - Visualización en dashboard web 5. **all** - Todos los canales ### Prioridades: - **emergency** (🔴) - Requiere acción inmediata - **critical** (🟠) - Acción requerida pronto - **warning** (🟡) - Atención recomendada - **info** (🔵) - Informativo solamente ### Variables de Entorno: ```bash ALERTING_TELEGRAM_CHAT_ID="${TELEGRAM_CHAT_ID}" # Variable de entorno ALERTING_EMAIL_RECIPIENTS="[REDACTED_SECRET],[REDACTED_SECRET]" ALERTING_SMTP_SERVER="smtp.gmail.com" ALERTING_DASHBOARD_URL="http://localhost:3000/alerts" ALERTING_RETENTION_DAYS="30" ``` ## 📊 Integración con Skills Existentes ### Con API Testing: ```bash # Si API falla, generar alerta api test https://api.tiklick.com/health --on-failure "alert trigger api.down --priority critical" ``` ### Con Security Tools: ```bash # Alertar hallazgos críticos de seguridad security scan --on-finding-critical "alert trigger security.critical --details {finding}" ``` ### Con Docker Management: ```bash # Alertar si contenedor cae docker monitor tiklick-app --on-crash "alert trigger docker.crash --container {name}" ``` ### Con Calendar Integration: ```bash # Recordatorios de eventos importantes calendar monitor --before 30 --action "alert trigger calendar.reminder --event {title}" ``` ## 🎯 Ejemplos para Tiklick ### Caso 1: Monitoreo API Producción ```bash # Configurar monitoreo 24/7 alert monitor https://api.tiklick.com/health \ --interval 30 \ --timeout 10 \ --expected-status 200 \ --on-failure "alert trigger api.production.down --priority emergency" \ --on-recovery "alert resolve api.production.down" \ --channel all ``` ### Caso 2: Ventas por Debajo de Umbral ```bash # Verificar ventas cada hora alert threshold /workspace/ventas/ultima_hora.csv \ --column "total_ventas" \ --min 500000 \ --check-every 3600 \ --on-below "alert trigger sales.low --priority warning --details 'Ventas bajas: {value}'" \ --channel telegram,email ``` ### Caso 3: Backup Fallido ```bash # Verificar backup diario alert monitor /workspace/backups/latest.tar.gz \ --max-age 86400 \ --min-size 1000000 \ --on-failure "alert trigger backup.failed --priority critical" \ --channel email ``` ### Caso 4: Horario No Laboral (Silenciar) ```bash # Solo alertas críticas fuera de horario alert rule working-hours \ --days mon-fri \ --time 08:00-18:00 \ --action "allow-all" \ --else "allow-only critical,emergency" ``` ## 🔧 Arquitectura ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Detección │───▶│ Procesamiento │───▶│ Notificación │ │ (Monitores) │ │ (Reglas) │ │ (Canales) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ ▼ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ APIs Tiklick │ │ Agrupación │ │ Telegram │ │ Sistema │ │ Escalación │ │ Email │ │ Logs │ │ Deduplicación │ │ Dashboard │ │ Métricas │ │ Priorización │ │ Log │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ## 📈 Métricas y Monitoreo ### Métricas a Seguir: - **Tiempo medio de detección:** < 60 segundos - **Tiempo medio de resolución:** < 15 minutos - **Falsos positivos:** < 5% - **Cobertura:** > 95% de sistemas críticos - **Satisfacción:** > 4.5/5 en encuestas ### Dashboard de Alertas: - **Alertas activas** por prioridad - **Tendencia histórica** - **Top servicios con problemas** - **Tiempos de respuesta** - **Estadísticas de resolución** ## 🛡️ Seguridad - **Autenticación:** Verificación de origen de alertas - **Autorización:** Quién puede configurar/ver alertas - **Auditoría:** Log completo de todas las acciones - **Rate limiting:** Prevenir spam de alertas - **Cifrado:** Datos sensibles cifrados ## 🔄 Mantenimiento ### Diario: - Revisar alertas activas - Verificar canales de notificación - Limpiar alertas resueltas antiguas ### Semanal: - Revisar reglas y ajustar umbrales - Analizar falsos positivos - Actualizar contactos de escalación ### Mensual: - Auditoría completa del sistema - Revisión de métricas y KPIs - Plan de mejora continua ## 🚨 Plan de Implementación ### Semana 1: Base (Actual) - Estructura del skill - Canal Telegram - Reglas básicas - Testing inicial ### Semana 2: Avanzado - Canal Email - Dashboard web - Reglas avanzadas - Integración skills ### Semana 3: Inteligente - Escalación automática - Aprendizaje automático - Mobile notifications - Optimización --- **Estado:** 🟡 EN DESARROLLO (Semana 1) **Próximo hito:** Canal Telegram funcional **Responsable:** TK Claw **Fecha objetivo:** 2026-02-26

path: alert_integration.sh
content: #!/bin/bash
# 🚨 Script de Integración del Sistema de Alertas
# Para uso inmediato con OpenClaw

set -e

ALERT_SYSTEM_DIR="/workspace/skills/alerting-system"
ALERT_DB="/workspace/.openclaw_alerts.json"
LOG_DIR="/var/log/openclaw_alerts"

# Colores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Funciones de utilidad
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}

log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# Verificar dependencias
check_dependencies() {
    log_info "Verificando dependencias..."
    
    # Node.js
    if ! command -v node &> /dev/null; then
        log_error "Node.js no encontrado. Instalar con: sudo apt install nodejs"
        exit 1
    fi
    
    # curl
    if ! command -v curl &> /dev/null; then
        log_warning "curl no encontrado. Instalar con: sudo apt install curl"
    fi
    
    # Directorio de logs
    if [ ! -d "$LOG_DIR" ]; then
        log_info "Creando directorio de logs: $LOG_DIR"
        sudo mkdir -p "$LOG_DIR"
        sudo chown rhandus:rhandus "$LOG_DIR"
    fi
    
    log_success "Dependencias verificadas"
}

# Inicializar sistema
initialize_system() {
    log_info "Inicializando sistema de alertas..."
    
    if [ ! -f "$ALERT_DB" ]; then
        log_info "Creando base de datos de alertas..."
        echo '{"alerts": [], "rules": [], "history": []}' > "$ALERT_DB"
        log_success "Base de datos creada: $ALERT_DB"
    fi
    
    # Probar sistema básico
    cd "$ALERT_SYSTEM_DIR"
    if node src/index.js stats &> /dev/null; then
        log_success "Sistema de alertas inicializado correctamente"
    else
        log_error "Error inicializando sistema de alertas"
        exit 1
    fi
}

# Crear alerta de ejemplo
create_example_alert() {
    log_info "Creando alerta de ejemplo..."
    
    cd "$ALERT_SYSTEM_DIR"
    node src/index.js create "Sistema de Alertas Iniciado" "El sistema de alertas ha sido inicializado correctamente" "alerting-system" "info"
    
    log_success "Alerta de ejemplo creada"
}

# Monitorear API de ejemplo
monitor_example_api() {
    local url="${1:-https://httpbin.org/status/200}"
    
    log_info "Monitoreando API de ejemplo: $url"
    
    cd "$ALERT_SYSTEM_DIR"
    node src/index.js monitor "$url" 200
    
    log_success "Monitoreo completado"
}

# Mostrar estado actual
show_status() {
    log_info "Estado actual del sistema de alertas:"
    
    cd "$ALERT_SYSTEM_DIR"
    node src/index.js stats
    
    echo ""
    log_info "Alertas activas:"
    node src/index.js list active
}

# Integrar con skill API Testing
integrate_with_api_testing() {
    log_info "Integrando con skill API Testing..."
    
    local api_testing_dir="/workspace/skills/api-testing"
    
    if [ ! -d "$api_testing_dir" ]; then
        log_warning "Skill API Testing no encontrado"
        return 1
    fi
    
    # Crear script de integración
    cat > "$api_testing_dir/alert_integration.js" << 'EOF'
/**
 * Integración entre API Testing y Alerting System
 */

import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

export async function alertOnAPIFailure(url, error) {
    const command = `cd /workspace/skills/alerting-system && \
                    node src/index.js create \
                    "API Testing Failure: ${url}" \
                    "Error al probar API: ${error}" \
                    "api-testing" \
                    "critical"`;
    
    try {
        await execAsync(command, { shell: true });
        console.log(`🚨 Alerta creada para fallo de API: ${url}`);
    } catch (err) {
        console.error(`Error creando alerta: ${err.message}`);
    }
}

export async function monitorAPIContinuously(url, interval = 300) {
    console.log(`📡 Monitoreando API continuamente: ${url} (cada ${interval}s)`);
    
    setInterval(async () => {
        try {
            const response = await fetch(url, { timeout: 10000 });
            
            if (!response.ok) {
                await alertOnAPIFailure(url, `HTTP ${response.status}`);
            }
        } catch (error) {
            await alertOnAPIFailure(url, error.message);
        }
    }, interval * 1000);
}
EOF
    
    log_success "Integración con API Testing creada"
    log_info "Archivo: $api_testing_dir/alert_integration.js"
}

# Integrar con skill Security Tools
integrate_with_security_tools() {
    log_info "Integrando con skill Security Tools..."
    
    local security_dir="/workspace/skills/security-tools"
    
    if [ ! -d "$security_dir" ]; then
        log_warning "Skill Security Tools no encontrado"
        return 1
    fi
    
    # Crear script de integración
    cat > "$security_dir/alert_integration.js" << 'EOF'
/**
 * Integración entre Security Tools y Alerting System
 */

import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

export async function alertOnSecurityFinding(finding) {
    const { severity, title, description, file } = finding;
    
    let priority = 'info';
    if (severity === 'high') priority = 'critical';
    if (severity === 'medium') priority = 'warning';
    
    const command = `cd /workspace/skills/alerting-system && \
                    node src/index.js create \
                    "Security Finding: ${title}" \
                    "${description}\\n\\nArchivo: ${file}" \
                    "security-tools" \
                    "${priority}"`;
    
    try {
        await execAsync(command, { shell: true });
        console.log(`🔐 Alerta de seguridad creada: ${title}`);
    } catch (err) {
        console.error(`Error creando alerta de seguridad: ${err.message}`);
    }
}

export async function alertOnCriticalPermission(file, permission) {
    const command = `cd /workspace/skills/alerting-system && \
                    node src/index.js create \
                    "Permiso Peligroso Detectado" \
                    "Archivo: ${file}\\nPermiso: ${permission}\\n\\nEste permiso podría ser un riesgo de seguridad." \
                    "security-tools" \
                    "critical"`;
    
    try {
        await execAsync(command, { shell: true });
        console.log(`🔐 Alerta de permiso peligroso creada: ${file}`);
    } catch (err) {
        console.error(`Error creando alerta: ${err.message}`);
    }
}
EOF
    
    log_success "Integración con Security Tools creada"
    log_info "Archivo: $security_dir/alert_integration.js"
}

# Crear cron job para monitoreo automático
setup_cron_job() {
    log_info "Configurando cron job para monitoreo automático..."
    
    local cron_file="/etc/cron.d/openclaw-alerting"
    local script_path="/workspace/skills/alerting-system/cron_monitor.sh"
    
    # Crear script de monitoreo
    cat > "$script_path" << 'EOF'
#!/bin/bash
# Cron job para monitoreo automático de APIs críticas

ALERT_DIR="/workspace/skills/alerting-system"
LOG_FILE="/var/log/openclaw_alerts/cron.log"

echo "[$(date)] Iniciando monitoreo automático..." >> "$LOG_FILE"

# Monitorear APIs Tiklick (ejemplos - ajustar URLs reales)
APIS=(
    "https://api.tiklick.com/health"
    "https://admin.tiklick.com"
    "https://app.tiklick.com"
)

for api in "${APIS[@]}"; do
    echo "Monitoreando: $api" >> "$LOG_FILE"
    cd "$ALERT_DIR" && node src/index.js monitor "$api" 200 >> "$LOG_FILE" 2>&1
    sleep 2
done

# Verificar sistema de alertas
cd "$ALERT_DIR" && node src/index.js stats >> "$LOG_FILE" 2>&1

echo "[$(date)] Monitoreo completado" >> "$LOG_FILE"
EOF
    
    chmod +x "$script_path"
    
    # Configurar cron job (cada 15 minutos)
    echo "*/15 * * * * rhandus $script_path" | sudo tee "$cron_file" > /dev/null
    
    log_success "Cron job configurado: cada 15 minutos"
    log_info "Script: $script_path"
    log_info "Log: /var/log/openclaw_alerts/cron.log"
}

# Mostrar ayuda
show_help() {
    echo -e "${BLUE}🚨 Sistema de Alertas OpenClaw - Script de Integración${NC}"
    echo ""
    echo "Uso: $0 [comando]"
    echo ""
    echo "Comandos disponibles:"
    echo "  init           - Inicializar sistema completo"
    echo "  status         - Mostrar estado actual"
    echo "  example        - Crear alerta de ejemplo"
    echo "  monitor <url>  - Monitorear API específica"
    echo "  integrate      - Integrar con skills existentes"
    echo "  cron           - Configurar cron job automático"
    echo "  help           - Mostrar esta ayuda"
    echo ""
    echo "Ejemplos:"
    echo "  $0 init"
    echo "  $0 monitor https://api.tiklick.com/health"
    echo "  $0 integrate"
    echo ""
}

# Main
case "$1" in
    "init")
        check_dependencies
        initialize_system
        create_example_alert
        show_status
        ;;
        
    "status")
        show_status
        ;;
        
    "example")
        create_example_alert
        ;;
        
    "monitor")
        if [ -z "$2" ]; then
            log_error "Se requiere URL para monitorear"
            echo "Uso: $0 monitor <url>"
            exit 1
        fi
        monitor_example_api "$2"
        ;;
        
    "integrate")
        integrate_with_api_testing
        integrate_with_security_tools
        log_success "Integración completada"
        ;;
        
    "cron")
        setup_cron_job
        ;;
        
    "help"|"")
        show_help
        ;;
        
    *)
        log_error "Comando no reconocido: $1"
        show_help
        exit 1
        ;;
esac

path: examples/api_monitoring.js
content: /**
 * 📡 Ejemplo: Monitoreo de APIs Tiklick con Sistema de Alertas
 * Integración con skill api-testing existente
 */

import { AlertManager } from '../src/alert_manager.js';

// APIs críticas de Tiklick para monitorear
const TIKLICK_APIS = [
  {
    name: 'API Principal Tiklick',
    url: 'https://api.tiklick.com/health',
    expectedStatus: 200,
    checkInterval: 60, // segundos
    priority: 'critical'
  },
  {
    name: 'API Pagos',
    url: 'https://pagos.tiklick.com/status',
    expectedStatus: 200,
    checkInterval: 120,
    priority: 'critical'
  },
  {
    name: 'API Autenticación',
    url: 'https://auth.tiklick.com/health',
    expectedStatus: 200,
    checkInterval: 90,
    priority: 'critical'
  },
  {
    name: 'Dashboard Admin',
    url: 'https://admin.tiklick.com',
    expectedStatus: 200,
    checkInterval: 180,
    priority: 'warning'
  }
];

// APIs de terceros importantes
const THIRD_PARTY_APIS = [
  {
    name: 'Google Calendar API',
    url: 'https://www.googleapis.com/calendar/v3/users/me/calendarList',
    expectedStatus: 200,
    checkInterval: 300,
    priority: 'warning'
  },
  {
    name: 'Google Drive API',
    url: 'https://www.googleapis.com/drive/v3/about',
    expectedStatus: 200,
    checkInterval: 300,
    priority: 'warning'
  },
  {
    name: 'MercadoPago API (ejemplo)',
    url: 'https://api.mercadopago.com/health',
    expectedStatus: 200,
    checkInterval: 300,
    priority: 'warning'
  }
];

class APIMonitoringService {
  constructor() {
    this.alertManager = new AlertManager();
    this.monitoringJobs = new Map();
    this.activeAlerts = new Map();
  }
  
  /**
   * Iniciar monitoreo de todas las APIs
   */
  async startMonitoring() {
    console.log('🚀 Iniciando monitoreo de APIs...');
    
    // Monitorear APIs Tiklick
    TIKLICK_APIS.forEach(api => {
      this.scheduleAPIMonitoring(api);
    });
    
    // Monitorear APIs de terceros
    THIRD_PARTY_APIS.forEach(api => {
      this.scheduleAPIMonitoring(api);
    });
    
    console.log(`✅ Monitoreando ${TIKLICK_APIS.length + THIRD_PARTY_APIS.length} APIs`);
  }
  
  /**
   * Programar monitoreo periódico de una API
   */
  scheduleAPIMonitoring(apiConfig) {
    const { name, url, expectedStatus, checkInterval, priority } = apiConfig;
    
    console.log(`📡 Programando monitoreo: ${name} (cada ${checkInterval}s)`);
    
    // Ejecutar inmediatamente
    this.checkAPI(apiConfig);
    
    // Programar chequeos periódicos
    const intervalId = setInterval(() => {
      this.checkAPI(apiConfig);
    }, checkInterval * 1000);
    
    this.monitoringJobs.set(name, intervalId);
  }
  
  /**
   * Verificar estado de una API
   */
  async checkAPI(apiConfig) {
    const { name, url, expectedStatus, priority } = apiConfig;
    const alertId = `api-${name.toLowerCase().replace(/\s+/g, '-')}`;
    
    try {
      console.log(`🔍 Verificando: ${name} (${url})`);
      
      const result = await this.alertManager.monitorHTTP(url, {
        expectedStatus,
        alertOnFailure: false, // Manejar alertas manualmente
        serviceName: 'api-monitoring'
      });
      
      if (result.success) {
        console.log(`✅ ${name} responde correctamente`);
        
        // Si había una alerta activa, resolverla
        if (this.activeAlerts.has(alertId)) {
          const alert = this.activeAlerts.get(alertId);
          this.alertManager.resolveAlert(alert.id, 'API recuperada');
          this.activeAlerts.delete(alertId);
          console.log(`✅ Alerta resuelta para ${name}`);
        }
        
      } else {
        console.log(`❌ ${name} no responde correctamente: ${result.status || result.error}`);
        
        // Crear alerta si no existe una activa
        if (!this.activeAlerts.has(alertId)) {
          const alert = await this.alertManager.createAlert({
            title: `API Down: ${name}`,
            message: `La API ${name} (${url}) no responde correctamente. Status: ${result.status || 'Error'}`,
            service: 'api-monitoring',
            priority,
            channels: ['telegram', 'log'],
            metadata: {
              api_name: name,
              url,
              expected_status: expectedStatus,
              actual_status: result.status,
              error: result.error,
              timestamp: new Date().toISOString()
            }
          });
          
          this.activeAlerts.set(alertId, alert);
          console.log(`🚨 Alerta creada para ${name}: ${alert.id}`);
        } else {
          console.log(`⚠️  Alerta ya activa para ${name}`);
        }
      }
      
    } catch (error) {
      console.error(`💥 Error verificando ${name}:`, error.message);
    }
  }
  
  /**
   * Detener monitoreo
   */
  stopMonitoring() {
    console.log('🛑 Deteniendo monitoreo de APIs...');
    
    this.monitoringJobs.forEach((intervalId, name) => {
      clearInterval(intervalId);
      console.log(`✅ Detenido: ${name}`);
    });
    
    this.monitoringJobs.clear();
    console.log('✅ Monitoreo detenido completamente');
  }
  
  /**
   * Mostrar estado actual
   */
  getStatus() {
    const status = {
      totalAPIs: TIKLICK_APIS.length + THIRD_PARTY_APIS.length,
      activeJobs: this.monitoringJobs.size,
      activeAlerts: this.activeAlerts.size,
      tiklickAPIs: TIKLICK_APIS.length,
      thirdPartyAPIs: THIRD_PARTY_APIS.length,
      timestamp: new Date().toISOString()
    };
    
    return status;
  }
}

// CLI para pruebas
if (process.argv[2] === 'start') {
  const monitor = new APIMonitoringService();
  
  console.log('🚀 Sistema de Monitoreo de APIs Tiklick');
  console.log('========================================');
  
  monitor.startMonitoring();
  
  // Mantener proceso activo
  process.on('SIGINT', () => {
    console.log('\n🛑 Recibido SIGINT, deteniendo...');
    monitor.stopMonitoring();
    process.exit(0);
  });
  
  // Mostrar estado cada 5 minutos
  setInterval(() => {
    const status = monitor.getStatus();
    console.log('\n📊 Estado del monitoreo:', JSON.stringify(status, null, 2));
  }, 5 * 60 * 1000);
  
} else if (process.argv[2] === 'test') {
  // Prueba con una API de ejemplo
  const monitor = new APIMonitoringService();
  
  console.log('🧪 Probando monitoreo con API de ejemplo...');
  
  const testAPI = {
    name: 'API de Prueba (httpbin)',
    url: 'https://httpbin.org/status/200',
    expectedStatus: 200,
    checkInterval: 10,
    priority: 'info'
  };
  
  monitor.checkAPI(testAPI)
    .then(() => {
      console.log('✅ Prueba completada');
      process.exit(0);
    })
    .catch(error => {
      console.error('❌ Error en prueba:', error);
      process.exit(1);
    });
    
} else if (process.argv[2] === 'status') {
  const monitor = new APIMonitoringService();
  const status = monitor.getStatus();
  
  console.log('📊 Estado del Sistema de Monitoreo:');
  console.log(JSON.stringify(status, null, 2));
  
} else {
  console.log('📡 Sistema de Monitoreo de APIs');
  console.log('===============================');
  console.log('');
  console.log('Uso:');
  console.log('  node api_monitoring.js start    - Iniciar monitoreo continuo');
  console.log('  node api_monitoring.js test     - Ejecutar prueba con API de ejemplo');
  console.log('  node api_monitoring.js status   - Mostrar estado');
  console.log('');
  console.log('APIs Tiklick configuradas:', TIKLICK_APIS.length);
  console.log('APIs de terceros configuradas:', THIRD_PARTY_APIS.length);
  console.log('');
}

path: package.json
content: {
  "name": "alerting-system-skill",
  "version": "1.0.0",
  "description": "Centralized alerting and notification system for OpenClaw",
  "type": "module",
  "main": "src/alert_manager.js",
  "scripts": {
    "test": "node src/alert_manager.js test",
    "monitor": "node src/alert_manager.js monitor https://httpbin.org/status/200",
    "stats": "node src/alert_manager.js stats",
    "start": "node src/index.js"
  },
  "keywords": ["alerting", "notifications", "monitoring", "telegram", "email", "openclaw"],
  "author": "TK Claw",
  "license": "MIT"
}

path: src/alert_manager.js
content: /**
 * 🚨 Alert Manager - Sistema Centralizado de Alertas
 * Nivel 1: Sistema base con Telegram y reglas básicas
 */

import fs from 'fs';
import path from 'path';
import { exec } from 'child_process';
import { promisify } from 'util';

const execAsync = promisify(exec);

// Configuración
const ALERTS_DB = '/workspace/.openclaw_alerts.json';
const LOG_FILE = '/var/log/openclaw_alerts/alerts.log';
const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID || 'CHANGE_ME';
const DEFAULT_PRIORITIES = ['info', 'warning', 'critical', 'emergency'];

/**
 * Clase principal del sistema de alertas
 */
export class AlertManager {
  constructor() {
    this.alerts = this.loadAlerts();
    this.rules = [];
    this.stats = {
      totalAlerts: 0,
      activeAlerts: 0,
      resolvedAlerts: 0,
      byPriority: {},
      byService: {}
    };
    
    this.initializeStats();
  }
  
  /**
   * Cargar alertas desde base de datos
   */
  loadAlerts() {
    try {
      if (fs.existsSync(ALERTS_DB)) {
        const data = fs.readFileSync(ALERTS_DB, 'utf8');
        return JSON.parse(data);
      }
    } catch (error) {
      this.log(`Error cargando alertas: ${error.message}`, 'error');
    }
    
    return {
      alerts: [],
      rules: [],
      history: []
    };
  }
  
  /**
   * Guardar alertas a base de datos
   */
  saveAlerts() {
    try {
      const data = JSON.stringify(this.alerts, null, 2);
      fs.writeFileSync(ALERTS_DB, data);
      this.log('Alertas guardadas en base de datos', 'info');
    } catch (error) {
      this.log(`Error guardando alertas: ${error.message}`, 'error');
    }
  }
  
  /**
   * Inicializar estadísticas
   */
  initializeStats() {
    DEFAULT_PRIORITIES.forEach(priority => {
      this.stats.byPriority[priority] = 0;
    });
    
    // Contar alertas existentes
    this.alerts.alerts.forEach(alert => {
      this.stats.totalAlerts++;
      if (alert.status === 'active') {
        this.stats.activeAlerts++;
      } else if (alert.status === 'resolved') {
        this.stats.resolvedAlerts++;
      }
      
      this.stats.byPriority[alert.priority] = (this.stats.byPriority[alert.priority] || 0) + 1;
      this.stats.byService[alert.service] = (this.stats.byService[alert.service] || 0) + 1;
    });
  }
  
  /**
   * Registrar en log
   */
  log(message, level = 'info') {
    const timestamp = new Date().toISOString();
    const logEntry = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
    
    try {
      fs.appendFileSync(LOG_FILE, logEntry);
    } catch (error) {
      console.error(`Error escribiendo log: ${error.message}`);
    }
    
    // También log a consola en desarrollo
    if (level === 'error') {
      console.error(`🚨 ${message}`);
    } else if (level === 'warning') {
      console.warn(`⚠️  ${message}`);
    } else {
      console.log(`📝 ${message}`);
    }
  }
  
  /**
   * Crear nueva alerta
   */
  async createAlert(options) {
    const {
      title,
      message,
      service = 'unknown',
      priority = 'warning',
      channels = ['telegram'],
      metadata = {},
      deduplicate = true
    } = options;
    
    // Generar ID único
    const alertId = `ALERT-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    
    // Verificar duplicados si está habilitado
    if (deduplicate) {
      const duplicate = this.findDuplicateAlert(title, service);
      if (duplicate) {
        this.log(`Alerta duplicada encontrada: ${duplicate.id}`, 'info');
        
        // Actualizar alerta existente
        duplicate.lastOccurrence = new Date().toISOString();
        duplicate.occurrenceCount = (duplicate.occurrenceCount || 1) + 1;
        duplicate.metadata = { ...duplicate.metadata, ...metadata };
        
        this.saveAlerts();
        return duplicate;
      }
    }
    
    const alert = {
      id: alertId,
      title,
      message,
      service,
      priority,
      status: 'active',
      channels,
      createdAt: new Date().toISOString(),
      lastOccurrence: new Date().toISOString(),
      occurrenceCount: 1,
      metadata,
      history: []
    };
    
    // Agregar a base de datos
    this.alerts.alerts.push(alert);
    
    // Actualizar estadísticas
    this.stats.totalAlerts++;
    this.stats.activeAlerts++;
    this.stats.byPriority[priority] = (this.stats.byPriority[priority] || 0) + 1;
    this.stats.byService[service] = (this.stats.byService[service] || 0) + 1;
    
    // Enviar notificaciones
    await this.sendNotifications(alert);
    
    // Guardar
    this.saveAlerts();
    
    this.log(`Nueva alerta creada: ${alertId} (${priority}) - ${title}`, 'info');
    
    return alert;
  }
  
  /**
   * Buscar alerta duplicada
   */
  findDuplicateAlert(title, service) {
    return this.alerts.alerts.find(alert => 
      alert.title === title && 
      alert.service === service && 
      alert.status === 'active'
    );
  }
  
  /**
   * Enviar notificaciones por canales configurados
   */
  async sendNotifications(alert) {
    const promises = [];
    
    alert.channels.forEach(channel => {
      switch (channel) {
        case 'telegram':
          promises.push(this.sendTelegramAlert(alert));
          break;
        case 'email':
          promises.push(this.sendEmailAlert(alert));
          break;
        case 'log':
          promises.push(this.logAlert(alert));
          break;
        default:
          this.log(`Canal no soportado: ${channel}`, 'warning');
      }
    });
    
    try {
      await Promise.allSettled(promises);
      this.log(`Notificaciones enviadas para alerta ${alert.id}`, 'info');
    } catch (error) {
      this.log(`Error enviando notificaciones: ${error.message}`, 'error');
    }
  }
  
  /**
   * Enviar alerta por Telegram
   */
  async sendTelegramAlert(alert) {
    try {
      const emoji = this.getPriorityEmoji(alert.priority);
      const message = `${emoji} *${alert.title}*\n\n${alert.message}\n\n` +
                     `*Servicio:* ${alert.service}\n` +
                     `*Prioridad:* ${alert.priority}\n` +
                     `*ID:* ${alert.id}\n` +
                     `*Hora:* ${new Date(alert.createdAt).toLocaleTimeString()}`;
      
      // Usar message tool de OpenClaw para enviar a Telegram
      // Nota: En entorno de OpenClaw, el routing es automático al canal actual
      // Para pruebas, usar console.log. En producción, OpenClaw manejará el routing.
      console.log(`📱 [TELEGRAM ALERT] ${message}`);
      // En entorno real de OpenClaw, el mensaje se enviará automáticamente
      return Promise.resolve();
      
      await execAsync(command, { shell: true });
      this.log(`Alerta enviada por Telegram: ${alert.id}`, 'info');
      
    } catch (error) {
      this.log(`Error enviando alerta por Telegram: ${error.message}`, 'error');
    }
  }
  
  /**
   * Enviar alerta por Email (usando gog)
   */
  async sendEmailAlert(alert) {
    try {
      const subject = `[${alert.priority.toUpperCase()}] ${alert.title}`;
      const body = `
ALERTA: ${alert.title}

Mensaje: ${alert.message}

Detalles:
- Servicio: ${alert.service}
- Prioridad: ${alert.priority}
- ID: ${alert.id}
- Hora: ${new Date(alert.createdAt).toLocaleString()}
- Status: ${alert.status}

${JSON.stringify(alert.metadata, null, 2)}

---
Sistema de Alertas OpenClaw
      `.trim();
      
      const account = process.env.GOOGLE_ACCOUNT || 'TU_EMAIL_GOOGLE';
      const adminEmail = process.env.ADMIN_EMAIL || '[REDACTED_SECRET]';
      const command = `gog gmail send --account ${account} --to ${adminEmail} --subject "${subject}" --body "${body.replace(/"/g, '\\"')}"`;
      
      await execAsync(command, { shell: true });
      this.log(`Alerta enviada por Email: ${alert.id}`, 'info');
      
    } catch (error) {
      this.log(`Error enviando alerta por Email: ${error.message}`, 'error');
    }
  }
  
  /**
   * Registrar alerta en log
   */
  async logAlert(alert) {
    const logEntry = `[ALERT] ${alert.id} | ${alert.priority} | ${alert.service} | ${alert.title} | ${alert.message}`;
    this.log(logEntry, 'info');
    return Promise.resolve();
  }
  
  /**
   * Obtener emoji para prioridad
   */
  getPriorityEmoji(priority) {
    const emojis = {
      emergency: '🔴',
      critical: '🟠',
      warning: '🟡',
      info: '🔵'
    };
    
    return emojis[priority] || '⚪';
  }
  
  /**
   * Resolver alerta
   */
  resolveAlert(alertId, resolutionNotes = '') {
    const alert = this.alerts.alerts.find(a => a.id === alertId);
    
    if (!alert) {
      this.log(`Alerta no encontrada: ${alertId}`, 'warning');
      return null;
    }
    
    alert.status = 'resolved';
    alert.resolvedAt = new Date().toISOString();
    alert.resolutionNotes = resolutionNotes;
    
    // Agregar al historial
    alert.history.push({
      action: 'resolved',
      timestamp: new Date().toISOString(),
      notes: resolutionNotes
    });
    
    // Actualizar estadísticas
    this.stats.activeAlerts--;
    this.stats.resolvedAlerts++;
    
    this.saveAlerts();
    
    this.log(`Alerta resuelta: ${alertId}`, 'info');
    
    // Notificar resolución
    this.notifyResolution(alert);
    
    return alert;
  }
  
  /**
   * Notificar resolución de alerta
   */
  async notifyResolution(alert) {
    try {
      const message = `✅ *ALERTA RESUELTA*\n\n` +
                     `*${alert.title}*\n\n` +
                     `La alerta ha sido marcada como resuelta.\n\n` +
                     `*ID:* ${alert.id}\n` +
                     `*Resuelta a las:* ${new Date().toLocaleTimeString()}\n` +
                     `*Notas:* ${alert.resolutionNotes || 'Sin notas'}`;
      
      // En entorno real de OpenClaw, el mensaje se enviará automáticamente
      console.log(`📱 [TELEGRAM RESOLUTION] ${message}`);
      this.log(`Notificación de resolución preparada: ${alert.id}`, 'info');
      
      return Promise.resolve();
      
    } catch (error) {
      this.log(`Error preparando notificación de resolución: ${error.message}`, 'error');
    }
  }
  
  /**
   * Listar alertas activas
   */
  listActiveAlerts() {
    return this.alerts.alerts.filter(alert => alert.status === 'active');
  }
  
  /**
   * Obtener estadísticas
   */
  getStats() {
    return {
      ...this.stats,
      timestamp: new Date().toISOString(),
      uptime: this.getUptime()
    };
  }
  
  /**
   * Obtener tiempo de actividad
   */
  getUptime() {
    // Para simplificar, retornar tiempo desde primera alerta
    if (this.alerts.alerts.length === 0) {
      return '0s';
    }
    
    const firstAlert = this.alerts.alerts.reduce((oldest, alert) => {
      return new Date(alert.createdAt) < new Date(oldest.createdAt) ? alert : oldest;
    });
    
    const uptimeMs = Date.now() - new Date(firstAlert.createdAt).getTime();
    const hours = Math.floor(uptimeMs / (1000 * 60 * 60));
    const minutes = Math.floor((uptimeMs % (1000 * 60 * 60)) / (1000 * 60));
    
    return `${hours}h ${minutes}m`;
  }
  
  /**
   * Monitorear endpoint HTTP
   */
  async monitorHTTP(url, options = {}) {
    const {
      interval = 60,
      timeout = 10,
      expectedStatus = 200,
      alertOnFailure = true,
      alertPriority = 'critical',
      serviceName = 'http-monitor'
    } = options;
    
    this.log(`Iniciando monitoreo HTTP: ${url} (cada ${interval}s)`, 'info');
    
    try {
      const command = `curl -s -o /dev/null -w "%{http_code}" --max-time ${timeout} "${url}"`;
      const { stdout } = await execAsync(command, { shell: true });
      
      const statusCode = parseInt(stdout.trim());
      
      if (statusCode === expectedStatus) {
        this.log(`✅ ${url} responde correctamente (${statusCode})`, 'info');
        return { success: true, status: statusCode };
      } else {
        this.log(`❌ ${url} responde con código ${statusCode} (esperado ${expectedStatus})`, 'warning');
        
        if (alertOnFailure) {
          await this.createAlert({
            title: `HTTP Monitor Failure: ${url}`,
            message: `El endpoint ${url} respondió con código ${statusCode} (esperado ${expectedStatus})`,
            service: serviceName,
            priority: alertPriority,
            channels: ['telegram', 'log'],
            metadata: { url, statusCode, expectedStatus, timeout }
          });
        }
        
        return { success: false, status: statusCode };
      }
      
    } catch (error) {
      this.log(`❌ Error monitoreando ${url}: ${error.message}`, 'error');
      
      if (alertOnFailure) {
        await this.createAlert({
          title: `HTTP Monitor Error: ${url}`,
          message: `Error al monitorear endpoint ${url}: ${error.message}`,
          service: serviceName,
          priority: alertPriority,
          channels: ['telegram', 'log'],
          metadata: { url, error: error.message, timeout }
        });
      }
      
      return { success: false, error: error.message };
    }
  }
}

// CLI para pruebas
if (process.argv[2] === 'test') {
  const manager = new AlertManager();
  
  // Crear alerta de prueba
  manager.createAlert({
    title: 'Prueba del Sistema de Alertas',
    message: 'Esta es una alerta de prueba del nuevo sistema de alertas OpenClaw.',
    service: 'alerting-system',
    priority: 'info',
    channels: ['telegram', 'log'],
    metadata: { test: true, version: '1.0.0' }
  })
  .then(alert => {
    console.log('✅ Alerta de prueba creada:');
    console.log(JSON.stringify(alert, null, 2));
    
    // Mostrar estadísticas
    console.log('\n📊 Estadísticas:');
    console.log(JSON.stringify(manager.getStats(), null, 2));
    
    // Listar alertas activas
    console.log('\n🚨 Alertas activas:');
    console.log(manager.listActiveAlerts().map(a => `${a.id}: ${a.title}`).join('\n'));
  })
  .catch(console.error);
}

if (process.argv[2] === 'monitor') {
  const manager = new AlertManager();
  const url = process.argv[3] || 'https://httpbin.org/status/200';
  
  manager.monitorHTTP(url, {
    interval: 30,
    timeout: 5,
    expectedStatus: 200,
    alertOnFailure: true,
    alertPriority: 'critical',
    serviceName: 'http-test'
  })
  .then(result => {
    console.log('📡 Resultado monitoreo HTTP:');
    console.log(JSON.stringify(result, null, 2));
  })
  .catch(console.error);
}

if (process.argv[2] === 'stats') {
  const manager = new AlertManager();
  console.log('📊 Estadísticas del Sistema de Alertas:');
  console.log(JSON.stringify(manager.getStats(), null, 2));
}

path: src/index.js
content: /**
 * 🚨 Alerting System - Punto de Entrada Principal
 * Sistema centralizado de alertas y notificaciones
 */

import { AlertManager } from './alert_manager.js';

/**
 * CLI Handler principal
 */
async function main() {
  const manager = new AlertManager();
  
  const command = process.argv[2];
  const args = process.argv.slice(3);
  
  switch (command) {
    case 'create':
      await handleCreateAlert(manager, args);
      break;
      
    case 'resolve':
      await handleResolveAlert(manager, args);
      break;
      
    case 'list':
      await handleListAlerts(manager, args);
      break;
      
    case 'stats':
      await handleStats(manager, args);
      break;
      
    case 'monitor':
      await handleMonitor(manager, args);
      break;
      
    case 'test':
      await handleTest(manager, args);
      break;
      
    case 'help':
    default:
      showHelp();
      break;
  }
}

/**
 * Crear nueva alerta
 */
async function handleCreateAlert(manager, args) {
  const title = args[0] || 'Alerta sin título';
  const message = args[1] || 'Sin mensaje proporcionado';
  const service = args[2] || 'general';
  const priority = args[3] || 'warning';
  
  const alert = await manager.createAlert({
    title,
    message,
    service,
    priority,
    channels: ['telegram', 'log'],
    metadata: { source: 'cli', args }
  });
  
  console.log('✅ Alerta creada:');
  console.log(JSON.stringify(alert, null, 2));
}

/**
 * Resolver alerta
 */
async function handleResolveAlert(manager, args) {
  const alertId = args[0];
  const notes = args.slice(1).join(' ') || 'Resuelta manualmente';
  
  if (!alertId) {
    console.error('❌ Se requiere ID de alerta');
    console.log('Uso: alert resolve <alert_id> [notes]');
    return;
  }
  
  const alert = manager.resolveAlert(alertId, notes);
  
  if (alert) {
    console.log('✅ Alerta resuelta:');
    console.log(JSON.stringify(alert, null, 2));
  } else {
    console.error(`❌ No se pudo resolver alerta: ${alertId}`);
  }
}

/**
 * Listar alertas
 */
async function handleListAlerts(manager, args) {
  const filter = args[0] || 'active';
  
  let alerts;
  
  switch (filter) {
    case 'active':
      alerts = manager.listActiveAlerts();
      console.log('🚨 Alertas Activas:');
      break;
      
    case 'all':
      alerts = manager.alerts.alerts;
      console.log('📋 Todas las Alertas:');
      break;
      
    case 'resolved':
      alerts = manager.alerts.alerts.filter(a => a.status === 'resolved');
      console.log('✅ Alertas Resueltas:');
      break;
      
    default:
      console.error(`❌ Filtro no válido: ${filter}`);
      console.log('Filtros válidos: active, all, resolved');
      return;
  }
  
  if (alerts.length === 0) {
    console.log('No hay alertas.');
    return;
  }
  
  alerts.forEach(alert => {
    const emoji = manager.getPriorityEmoji(alert.priority);
    const time = new Date(alert.createdAt).toLocaleTimeString();
    console.log(`${emoji} ${alert.id} - ${alert.title} (${alert.service}) - ${time}`);
  });
  
  console.log(`\n📊 Total: ${alerts.length} alerta(s)`);
}

/**
 * Mostrar estadísticas
 */
async function handleStats(manager) {
  const stats = manager.getStats();
  
  console.log('📊 Estadísticas del Sistema de Alertas:');
  console.log('========================================');
  console.log(`Total alertas: ${stats.totalAlerts}`);
  console.log(`Activas: ${stats.activeAlerts}`);
  console.log(`Resueltas: ${stats.resolvedAlerts}`);
  console.log(`Tiempo actividad: ${stats.uptime}`);
  console.log('');
  
  console.log('📈 Por prioridad:');
  Object.entries(stats.byPriority).forEach(([priority, count]) => {
    if (count > 0) {
      const emoji = manager.getPriorityEmoji(priority);
      console.log(`  ${emoji} ${priority}: ${count}`);
    }
  });
  
  console.log('');
  console.log('🏷️  Por servicio (top 5):');
  Object.entries(stats.byService)
    .sort((a, b) => b[1] - a[1])
    .slice(0, 5)
    .forEach(([service, count]) => {
      console.log(`  ${service}: ${count}`);
    });
}

/**
 * Monitorear endpoint
 */
async function handleMonitor(manager, args) {
  const url = args[0];
  
  if (!url) {
    console.error('❌ Se requiere URL para monitorear');
    console.log('Uso: alert monitor <url> [expected_status]');
    return;
  }
  
  const expectedStatus = parseInt(args[1]) || 200;
  
  console.log(`📡 Monitoreando: ${url} (esperado: ${expectedStatus})`);
  
  const result = await manager.monitorHTTP(url, {
    expectedStatus,
    alertOnFailure: true,
    alertPriority: 'critical',
    serviceName: 'http-monitor'
  });
  
  console.log('✅ Resultado:');
  console.log(JSON.stringify(result, null, 2));
}

/**
 * Ejecutar pruebas
 */
async function handleTest(manager) {
  console.log('🧪 Ejecutando pruebas del sistema de alertas...');
  
  // Prueba 1: Crear alerta de prueba
  console.log('\n1. Creando alerta de prueba...');
  const testAlert = await manager.createAlert({
    title: 'Prueba del Sistema de Alertas',
    message: 'Esta es una alerta de prueba del sistema.',
    service: 'testing',
    priority: 'info',
    channels: ['log'],
    metadata: { test: true }
  });
  
  console.log(`✅ Alerta creada: ${testAlert.id}`);
  
  // Prueba 2: Listar alertas activas
  console.log('\n2. Listando alertas activas...');
  const activeAlerts = manager.listActiveAlerts();
  console.log(`✅ Alertas activas: ${activeAlerts.length}`);
  
  // Prueba 3: Estadísticas
  console.log('\n3. Obteniendo estadísticas...');
  const stats = manager.getStats();
  console.log(`✅ Estadísticas obtenidas: ${stats.totalAlerts} alertas totales`);
  
  // Prueba 4: Resolver alerta
  console.log('\n4. Resolviendo alerta de prueba...');
  const resolved = manager.resolveAlert(testAlert.id, 'Prueba completada');
  console.log(`✅ Alerta resuelta: ${resolved ? 'Sí' : 'No'}`);
  
  // Prueba 5: Estadísticas finales
  console.log('\n5. Estadísticas finales:');
  const finalStats = manager.getStats();
  console.log(`   Total: ${finalStats.totalAlerts}`);
  console.log(`   Activas: ${finalStats.activeAlerts}`);
  console.log(`   Resueltas: ${finalStats.resolvedAlerts}`);
  
  console.log('\n🎉 Todas las pruebas completadas exitosamente!');
}

/**
 * Mostrar ayuda
 */
function showHelp() {
  console.log('🚨 Sistema de Alertas OpenClaw');
  console.log('===============================');
  console.log('');
  console.log('Comandos disponibles:');
  console.log('');
  console.log('  alert create <title> <message> [service] [priority]');
  console.log('    Crear nueva alerta');
  console.log('');
  console.log('  alert resolve <alert_id> [notes]');
  console.log('    Marcar alerta como resuelta');
  console.log('');
  console.log('  alert list [active|all|resolved]');
  console.log('    Listar alertas');
  console.log('');
  console.log('  alert stats');
  console.log('    Mostrar estadísticas');
  console.log('');
  console.log('  alert monitor <url> [expected_status]');
  console.log('    Monitorear endpoint HTTP');
  console.log('');
  console.log('  alert test');
  console.log('    Ejecutar pruebas del sistema');
  console.log('');
  console.log('  alert help');
  console.log('    Mostrar esta ayuda');
  console.log('');
  console.log('Prioridades: info, warning, critical, emergency');
  console.log('');
}

// Ejecutar CLI
if (process.argv.length > 2) {
  main().catch(console.error);
} else {
  showHelp();
}

Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)