true, CURLOPT_TIMEOUT => ARC_TIMEOUT, CURLOPT_CONNECTTIMEOUT => 3, CURLOPT_HTTPHEADER => ['Content-Type: application/json'], ]); if ($method === 'POST') { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); } elseif ($method === 'DELETE') { curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE'); } $raw = curl_exec($ch); $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $err = curl_error($ch); curl_close($ch); if ($err || $raw === false) { return ['error' => 'Arc Reactor unreachable: ' . $err, 'online' => false]; } $decoded = json_decode($raw, true); return $decoded ?? ['error' => 'Invalid response from Arc Reactor', 'raw' => substr($raw, 0, 200)]; } // ── ROUTING ─────────────────────────────────────────────────────────────────── // arc action comes from query string or POST body (not the URL path segment) global $data; $action = $_GET['action'] ?? $data['action'] ?? ''; switch ($action) { // GET /api/arc?action=status case 'status': $result = arc_request('GET', '/status'); if (!isset($result['online'])) $result['online'] = false; echo json_encode($result); break; // POST /api/arc — create a job case 'job_create': $type = $data['type'] ?? ''; $payload = $data['payload'] ?? []; $priority = (int)($data['priority'] ?? 5); if (!$type) { http_response_code(400); echo json_encode(['error' => 'Missing job type']); break; } $result = arc_request('POST', '/job', [ 'type' => $type, 'payload' => $payload, 'priority' => $priority, 'created_by' => 'jarvis_ui', ]); echo json_encode($result); break; // GET /api/arc?action=job_get&id=123 case 'job_get': $id = (int)($data['id'] ?? $_GET['id'] ?? 0); if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing job id']); break; } echo json_encode(arc_request('GET', "/job/{$id}")); break; // GET /api/arc?action=jobs&status=done&limit=20 case 'jobs': $status = $_GET['status'] ?? $data['status'] ?? ''; $limit = (int)($_GET['limit'] ?? $data['limit'] ?? 50); $qs = http_build_query(array_filter(['status' => $status, 'limit' => $limit])); echo json_encode(arc_request('GET', '/jobs' . ($qs ? "?{$qs}" : ''))); break; // DELETE /api/arc?action=job_cancel&id=123 case 'job_cancel': $id = (int)($data['id'] ?? $_GET['id'] ?? 0); if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing job id']); break; } echo json_encode(arc_request('DELETE', "/job/{$id}")); break; // DELETE /api/arc?action=purge case 'purge': echo json_encode(arc_request('DELETE', '/jobs/purge')); break; // Quick ping test case 'ping': $result = arc_request('POST', '/job', [ 'type' => 'ping', 'payload' => [], 'priority' => 9, 'created_by' => 'jarvis_ping', ]); echo json_encode($result); break; // GET /api/arc?action=triage&limit=50&filter=priority // Returns email_triage rows for the COMMS tab case 'triage': $limit = min((int)($_GET['limit'] ?? 50), 100); $filter = $_GET['filter'] ?? 'priority'; if ($filter === 'urgent') { $sql = "SELECT id, account, from_name, from_email, subject, date_received, category, priority, summary, draft_reply, action_taken, created_at FROM email_triage WHERE action_taken != 'dismissed' AND category = 'urgent' ORDER BY priority DESC, created_at DESC LIMIT ?"; } elseif ($filter === 'action') { $sql = "SELECT id, account, from_name, from_email, subject, date_received, category, priority, summary, draft_reply, action_taken, created_at FROM email_triage WHERE action_taken != 'dismissed' AND category IN ('urgent','action','reply','meeting') ORDER BY priority DESC, created_at DESC LIMIT ?"; } elseif ($filter === 'priority') { $sql = "SELECT id, account, from_name, from_email, subject, date_received, category, priority, summary, draft_reply, action_taken, created_at FROM email_triage WHERE action_taken != 'dismissed' AND category IN ('urgent','action','reply','meeting') AND priority >= 5 ORDER BY priority DESC, created_at DESC LIMIT ?"; } else { $sql = "SELECT id, account, from_name, from_email, subject, date_received, category, priority, summary, draft_reply, action_taken, created_at FROM email_triage WHERE action_taken != 'dismissed' ORDER BY priority DESC, created_at DESC LIMIT ?"; } $rows = JarvisDB::query($sql, [$limit]); echo json_encode($rows ?: []); break; // POST /api/arc?action=triage_action&id=123 body: { action: "dismissed"|"replied"|"done" } case 'triage_action': $id = (int)($_GET['id'] ?? $data['id'] ?? 0); $actionTaken = $data['action'] ?? 'dismissed'; $allowed = ['dismissed', 'replied', 'done', 'snoozed']; if (!$id || !in_array($actionTaken, $allowed)) { http_response_code(400); echo json_encode(['error' => 'Invalid id or action']); break; } JarvisDB::execute( "UPDATE email_triage SET action_taken = ? WHERE id = ?", [$actionTaken, $id] ); echo json_encode(['ok' => true, 'id' => $id, 'action_taken' => $actionTaken]); break; // GET /api/arc?action=screenshots&limit=20&agent=hostname case 'screenshots': $limit = min((int)($_GET['limit'] ?? 20), 100); $agent = $_GET['agent'] ?? ''; $url = 'http://127.0.0.1:7474/screenshots?' . http_build_query(array_filter(['limit' => $limit, 'agent' => $agent])); $ch = curl_init($url); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5]); $raw = curl_exec($ch); curl_close($ch); echo $raw ?: '[]'; break; // GET /api/arc?action=screenshot_get&id=123 case 'screenshot_get': $id = (int)($_GET['id'] ?? 0); if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; } echo json_encode(arc_request('GET', "/screenshots/{$id}")); break; // DELETE /api/arc?action=screenshot_delete&id=123 case 'screenshot_delete': $id = (int)($_GET['id'] ?? 0); if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; } echo json_encode(arc_request('DELETE', "/screenshots/{$id}")); break; // ── GUARDIAN MODE ───────────────────────────────────────────────────────── case 'guardian_status': echo json_encode(arc_request('GET', '/guardian/status')); break; case 'guardian_events': $limit = (int)($_GET['limit'] ?? 30); $unread = !empty($_GET['unread']) ? 'true' : ''; $severity = $_GET['severity'] ?? ''; $since = $_GET['since'] ?? ''; $qs = http_build_query(array_filter([ 'limit' => $limit, 'unread' => $unread, 'severity' => $severity, 'since' => $since, ])); echo json_encode(arc_request('GET', '/guardian/events' . ($qs ? "?{$qs}" : ''))); break; case 'guardian_ack': $id = (int)($_GET['id'] ?? $data['id'] ?? 0); if ($id) { echo json_encode(arc_request('POST', "/guardian/events/{$id}/ack")); } else { echo json_encode(arc_request('POST', '/guardian/events/ack_all')); } break; case 'guardian_chat': $since = $_GET['since'] ?? ''; $qs = $since ? '?since=' . urlencode($since) : ''; echo json_encode(arc_request('GET', '/guardian/chat' . $qs)); break; // ── COMMS v2 ────────────────────────────────────────────────────────────── // GET /api/arc?action=comms_sent&limit=50&status=sent case 'comms_sent': $limit = min((int)($_GET['limit'] ?? 50), 200); $status = $_GET['status'] ?? ''; $qs = http_build_query(array_filter(['limit' => $limit, 'status' => $status])); echo json_encode(arc_request('GET', '/comms/sent' . ($qs ? "?{$qs}" : ''))); break; // GET /api/arc?action=comms_sent_get&id=123 case 'comms_sent_get': $id = (int)($_GET['id'] ?? 0); if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; } echo json_encode(arc_request('GET', "/comms/sent/{$id}")); break; // DELETE /api/arc?action=comms_sent_delete&id=123 case 'comms_sent_delete': $id = (int)($_GET['id'] ?? 0); if (!$id) { http_response_code(400); echo json_encode(['error' => 'Missing id']); break; } echo json_encode(arc_request('DELETE', "/comms/sent/{$id}")); break; default: http_response_code(404); echo json_encode(['error' => "Unknown arc action: {$action}"]); }