feat: proactive alerts, Jellyfin control, agent sparklines, CCR roster fix

- Proactive alerts (#1): polls every 60s; baselines on load so old alerts are silent; speaks new critical/warning alerts aloud if voice active; adds chat bubble for all new alerts
- Jellyfin control (#2): pause/stop/next/previous via voice — auto-detects active session; 12 KB intents; jellyfin.php control action uses Jellyfin General Commands API
- Agent sparklines (#6): metrics.php returns 2h CPU+MEM history per agent; SVG polyline sparklines rendered in each agent card (cyan=CPU, green=MEM); non-blocking fetch so existing view shows instantly
- Agent health CCR (#7): updated hourly cloud routine to current 13-agent roster, removed ollama-ai and alien-pc, added all active agents with correct IPs/IDs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 02:30:13 +00:00
parent e381858299
commit c29d1bf4c7
5 changed files with 187 additions and 0 deletions
+28
View File
@@ -76,6 +76,34 @@ switch ($action) {
echo json_encode(['recent' => $out]);
break;
case 'control':
$jfSessionId = $_GET['session_id'] ?? '';
$jfCommand = $_GET['command'] ?? '';
// General commands supported by Jellyfin session control
$allowed = ['TogglePause', 'Stop', 'NextTrack', 'PreviousTrack', 'VolumeUp', 'VolumeDown'];
if (!$jfSessionId || !in_array($jfCommand, $allowed, true)) {
// No session_id: get the first active session automatically
if (!$jfSessionId && in_array($jfCommand, $allowed, true)) {
$sessions = jf_get('/Sessions');
foreach ($sessions as $s) {
if (isset($s['NowPlayingItem'])) { $jfSessionId = $s['Id']; break; }
}
}
if (!$jfSessionId) { echo json_encode(['error' => 'No active session or invalid command']); break; }
}
$url = JELLYFIN_URL . '/Sessions/' . rawurlencode($jfSessionId) . '/Command/' . $jfCommand
. '?api_key=' . JELLYFIN_API_KEY;
$ctx = stream_context_create(['http' => [
'method' => 'POST',
'timeout' => 5,
'header' => 'Content-Type: application/json',
'content' => '{}',
'ignore_errors' => true,
]]);
@file_get_contents($url, false, $ctx);
echo json_encode(['success' => true, 'command' => $jfCommand, 'session_id' => $jfSessionId]);
break;
default:
echo json_encode(['error' => 'Unknown action']);
}