← back to Norma

agents/discord-agent/skills/report.js

137 lines

/**
 * Discord Report Skill
 *
 * Gathers agent stats and recent actions, then pushes to Pulse.
 */

const { logAction, getActionSummary } = require('../../shared/audit-logger');
const { reportAgentStatus } = require('../../shared/pulse-reporter');
const { hasCredentials, getStatus } = require('../lib/discord');
const { query: dbQuery } = require('../../shared/db');

const AGENT = 'discord-agent';
const PLATFORM = 'discord';

/**
 * @param {Object} body - Request body
 * @param {number} [body.hours_back=24] - How many hours back to report
 * @returns {Promise<Object>}
 */
module.exports = async function report(body) {
  const hoursBack = body.hours_back || 24;

  // Get action summary
  const actionSummary = await getActionSummary(AGENT, hoursBack);

  // Get bot status
  const botStatus = getStatus();

  // Get monitor stats
  let monitorStats = { total: 0, active: 0, totalItemsFound: 0 };
  try {
    const { rows } = await dbQuery(
      `SELECT
        COUNT(*)::int as total,
        COUNT(*) FILTER (WHERE is_active = true)::int as active,
        COALESCE(SUM(items_found), 0)::int as total_items_found
       FROM sdcc_agent_monitors
       WHERE agent = $1 AND platform = $2`,
      [AGENT, PLATFORM]
    );
    if (rows[0]) {
      monitorStats = {
        total: rows[0].total,
        active: rows[0].active,
        totalItemsFound: rows[0].total_items_found,
      };
    }
  } catch (err) {
    console.error(`[${AGENT}] Failed to get monitor stats:`, err.message);
  }

  // Get campaign stats
  let campaignStats = { total: 0, active: 0, totalPosts: 0, totalReplies: 0 };
  try {
    const { rows } = await dbQuery(
      `SELECT
        COUNT(*)::int as total,
        COUNT(*) FILTER (WHERE status = 'active')::int as active,
        COALESCE(SUM(total_posts), 0)::int as total_posts,
        COALESCE(SUM(total_replies), 0)::int as total_replies
       FROM sdcc_petition_campaigns
       WHERE 'discord' = ANY(target_platforms)`
    );
    if (rows[0]) {
      campaignStats = {
        total: rows[0].total,
        active: rows[0].active,
        totalPosts: rows[0].total_posts,
        totalReplies: rows[0].total_replies,
      };
    }
  } catch (err) {
    console.error(`[${AGENT}] Failed to get campaign stats:`, err.message);
  }

  // Get recent actions
  let recentActions = [];
  try {
    const { rows } = await dbQuery(
      `SELECT target_id, target_url, content, action_type,
              channel, response_data, created_at
       FROM sdcc_agent_actions
       WHERE agent = $1 AND platform = $2
         AND action_type IN ('post', 'reply')
         AND status = 'success'
       ORDER BY created_at DESC
       LIMIT 10`,
      [AGENT, PLATFORM]
    );
    recentActions = rows;
  } catch (err) {
    console.error(`[${AGENT}] Failed to get recent actions:`, err.message);
  }

  const reportData = {
    agent: AGENT,
    platform: PLATFORM,
    credentials_configured: hasCredentials(),
    bot_status: botStatus,
    period_hours: hoursBack,
    actions: actionSummary,
    monitors: monitorStats,
    campaigns: campaignStats,
    recent_actions: recentActions,
    uptime: process.uptime(),
    reported_at: new Date().toISOString(),
  };

  // Push to Pulse
  const pulseResult = await reportAgentStatus(AGENT, {
    state: botStatus.connected ? 'running' : hasCredentials() ? 'idle' : 'idle',
    uptime: process.uptime(),
    lastAction: actionSummary.length > 0 ? actionSummary[0] : null,
    stats: {
      bot: botStatus,
      monitors: monitorStats,
      campaigns: campaignStats,
      credentialsConfigured: hasCredentials(),
      actionsInPeriod: actionSummary.reduce((sum, a) => sum + a.count, 0),
    },
  });

  // Log the report action
  await logAction({
    agent: AGENT,
    actionType: 'report',
    platform: PLATFORM,
    responseData: reportData,
    status: 'success',
  });

  return {
    ...reportData,
    pulse_response: pulseResult,
  };
};