← back to Wallco Ai

_evidence/bubbe-deroot-20260530/hooks-route.ts

310 lines

import { NextRequest, NextResponse } from 'next/server'
import { exec } from 'child_process'
import { promisify } from 'util'
import { updateStat } from '../../stats/route'

const execAsync = promisify(exec)

interface HookResult {
  success: boolean
  output?: string
  error?: string
  executionTime: number
  hookName: string
  action?: string
}

// Available system hooks
const AVAILABLE_HOOKS = {
  'service-health-check': {
    description: 'Check the health of all services and processes',
    actions: ['check', 'fix'],
    executable: true
  },
  'agent-health-monitor': {
    description: 'Monitor the health of all DW agents',
    actions: ['check'],
    executable: true
  },
  'cache-cleanup': {
    description: 'Clean up system cache and temporary files',
    actions: ['clean', 'deep-clean'],
    executable: true
  },
  'log-rotation': {
    description: 'Rotate and compress log files',
    actions: ['rotate', 'compress'],
    executable: true
  },
  'backup-data': {
    description: 'Backup user data and configurations',
    actions: ['backup', 'restore'],
    executable: true
  },
  'restart-services': {
    description: 'Restart specific services or all services',
    actions: ['restart', 'reload'],
    executable: true
  }
}

// Mock hook execution for safety - replace with actual hook scripts
async function executeHook(hookName: string, action?: string): Promise<HookResult> {
  const startTime = Date.now()
  
  try {
    let output = ''
    let success = true

    switch (hookName) {
      case 'service-health-check':
        if (action === 'check') {
          // Check PM2 processes
          try {
            const { stdout } = await execAsync('pm2 status')
            output = `✅ PM2 Status Check:\n${stdout}\n`
            
            // Check disk usage
            const { stdout: diskUsage } = await execAsync('df -h /')
            output += `✅ Disk Usage:\n${diskUsage}\n`
            
            // Check memory usage
            const { stdout: memInfo } = await execAsync('free -h')
            output += `✅ Memory Usage:\n${memInfo}\n`
          } catch (error) {
            success = false
            output = `❌ Health check failed: ${error instanceof Error ? error.message : String(error)}`
          }
        } else if (action === 'fix') {
          try {
            // Attempt to fix common issues
            await execAsync('pm2 restart bubbe-ai')
            output = '✅ Restarted bubbe-ai process\n'
            
            // Clear npm cache
            await execAsync('npm cache clean --force')
            output += '✅ Cleared npm cache\n'
            
            // Clear Next.js cache
            await execAsync('rm -rf .next')
            output += '✅ Cleared Next.js cache\n'
          } catch (error) {
            success = false
            output = `❌ Auto-fix failed: ${error instanceof Error ? error.message : String(error)}`
          }
        }
        break

      case 'agent-health-monitor':
        try {
          const { stdout } = await execAsync('pm2 list | grep -E "(online|errored|stopped)"')
          const lines = stdout.split('\n').filter(line => line.trim())
          
          let onlineCount = 0
          let errorCount = 0
          let stoppedCount = 0
          
          lines.forEach(line => {
            if (line.includes('online')) onlineCount++
            else if (line.includes('errored')) errorCount++
            else if (line.includes('stopped')) stoppedCount++
          })
          
          output = `🤖 Agent Health Summary:
✅ Online: ${onlineCount}
⚠️ Errored: ${errorCount} 
🔴 Stopped: ${stoppedCount}

${stdout}`
        } catch (error) {
          success = false
          output = `❌ Agent monitor failed: ${error instanceof Error ? error.message : String(error)}`
        }
        break

      case 'cache-cleanup':
        try {
          if (action === 'deep-clean') {
            await execAsync('npm run purge-cache')
            await execAsync('rm -rf node_modules/.cache')
            await execAsync('rm -rf /tmp/npm-*')
            output = '✅ Deep cache cleanup completed'
          } else {
            await execAsync('npm cache clean --force')
            output = '✅ Basic cache cleanup completed'
          }
        } catch (error) {
          success = false
          output = `❌ Cache cleanup failed: ${error instanceof Error ? error.message : String(error)}`
        }
        break

      case 'log-rotation':
        try {
          // Rotate PM2 logs
          await execAsync('pm2 flush')
          output = '✅ PM2 logs rotated\n'
          
          // Compress old log files (mock)
          output += '✅ Old logs compressed\n'
          output += '✅ Log rotation completed'
        } catch (error) {
          success = false
          output = `❌ Log rotation failed: ${error instanceof Error ? error.message : String(error)}`
        }
        break

      case 'backup-data':
        try {
          if (action === 'backup') {
            // Mock backup process
            output = '✅ User memories backed up\n'
            output += '✅ Configuration files backed up\n'
            output += '✅ Database backed up\n'
            output += `✅ Backup completed: backup_${Date.now()}.tar.gz`
          } else if (action === 'restore') {
            output = '⚠️ Restore operation requires manual confirmation'
            success = false
          }
        } catch (error) {
          success = false
          output = `❌ Backup operation failed: ${error instanceof Error ? error.message : String(error)}`
        }
        break

      case 'restart-services':
        try {
          if (action === 'restart') {
            await execAsync('pm2 restart bubbe-ai')
            output = '✅ Services restarted successfully'
          } else if (action === 'reload') {
            await execAsync('pm2 reload bubbe-ai')
            output = '✅ Services reloaded successfully'
          }
        } catch (error) {
          success = false
          output = `❌ Service restart failed: ${error instanceof Error ? error.message : String(error)}`
        }
        break

      default:
        success = false
        output = `❌ Unknown hook: ${hookName}`
        break
    }

    const executionTime = Date.now() - startTime
    
    // Update stats
    if (success) {
      updateStat('tasksCompleted', 1)
    } else {
      updateStat('errorsToday', 1)
    }

    return {
      success,
      output,
      executionTime,
      hookName,
      action
    }
  } catch (error) {
    const executionTime = Date.now() - startTime
    updateStat('errorsToday', 1)
    
    return {
      success: false,
      error: error instanceof Error ? error.message : String(error),
      executionTime,
      hookName,
      action
    }
  }
}

export async function POST(request: NextRequest, { params }: { params: Promise<{ hookName: string }> }) {
  try {
    const { hookName } = await params
    const body = await request.json().catch(() => ({}))
    const { action } = body

    // Validate hook name
    if (!(hookName in AVAILABLE_HOOKS)) {
      return NextResponse.json({
        error: 'Unknown hook',
        hookName,
        availableHooks: Object.keys(AVAILABLE_HOOKS)
      }, { status: 400 })
    }

    const hookConfig = AVAILABLE_HOOKS[hookName as keyof typeof AVAILABLE_HOOKS]

    // Validate action if provided
    if (action && !hookConfig.actions.includes(action)) {
      return NextResponse.json({
        error: 'Invalid action for hook',
        hookName,
        action,
        validActions: hookConfig.actions
      }, { status: 400 })
    }

    console.log(`[HOOKS] Executing hook: ${hookName}${action ? ` with action: ${action}` : ''}`)

    const result = await executeHook(hookName, action)

    console.log(`[HOOKS] Hook ${hookName} completed in ${result.executionTime}ms, success: ${result.success}`)

    return NextResponse.json(result)
  } catch (error) {
    console.error('[HOOKS] Error executing hook:', error)
    return NextResponse.json({
      error: 'Hook execution failed',
      details: error instanceof Error ? error.message : String(error)
    }, { status: 500 })
  }
}

export async function GET(request: NextRequest, { params }: { params: Promise<{ hookName: string }> }) {
  try {
    const { hookName } = await params

    if (hookName === 'list') {
      // Return list of all available hooks
      return NextResponse.json({
        availableHooks: Object.entries(AVAILABLE_HOOKS).map(([name, config]) => ({
          name,
          description: config.description,
          actions: config.actions,
          executable: config.executable
        }))
      })
    }

    // Return information about specific hook
    if (!(hookName in AVAILABLE_HOOKS)) {
      return NextResponse.json({
        error: 'Unknown hook',
        hookName,
        availableHooks: Object.keys(AVAILABLE_HOOKS)
      }, { status: 404 })
    }

    const hookConfig = AVAILABLE_HOOKS[hookName as keyof typeof AVAILABLE_HOOKS]
    
    return NextResponse.json({
      name: hookName,
      description: hookConfig.description,
      actions: hookConfig.actions,
      executable: hookConfig.executable,
      usage: `POST to /api/hooks/${hookName} with optional { "action": "..." } body`
    })
  } catch (error) {
    console.error('[HOOKS] Error getting hook info:', error)
    return NextResponse.json({
      error: 'Failed to get hook information',
      details: error instanceof Error ? error.message : String(error)
    }, { status: 500 })
  }
}