feat(diagnostic): Satelliten-Tab — verbundene Satelliten + erkannte Geraete

Das Diagnostic haengt selbst am RVS-Raum und kennt die sat_*-Broadcasts jetzt:
- server.js: Satelliten-Registry (sat_hello), leitet sat_devices an den Browser,
  gibt die Liste beim init mit; Browser-Aktionen sat_list + sat_discover.
- index.html: neuer Haupt-Tab "Satelliten" — Karten pro Satellit (online/offline,
  Standort, Capabilities, read-only/steuerbar) mit "Geraete scannen" → Live-Liste
  der erkannten Geraete (Typ/IP/Modell/DIAL/MAC).

Kein Brain/Bridge-Rebuild fuer diesen Teil noetig (nur diagnostic). node -c OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-20 19:11:14 +02:00
co-authored by Claude Opus 4.8
parent 071e38f464
commit 1dc8c0936f
3 changed files with 140 additions and 0 deletions
+41
View File
@@ -475,6 +475,21 @@ function broadcastState() {
broadcast({ type: "state", state });
}
// ── Satelliten-Registry (Aussenposten in fremden Netzen) ──────────
const satellites = new Map(); // id → {id, location, caps, control, last_seen}
function satelliteList() {
const now = Date.now();
return Array.from(satellites.values()).map(s => ({
id: s.id, location: s.location, caps: s.caps, control: s.control,
online: (now - (s.last_seen || 0)) < 300000,
}));
}
function broadcastSatellites() {
broadcast({ type: "sat_update", satellites: satelliteList() });
}
// ── OpenClaw Gateway Verbindung ─────────────────────────
async function connectGateway() {
@@ -903,6 +918,22 @@ function connectRVS(forcePlain) {
// Browser-Tabs weiterreichen, damit die Projektliste live neu laedt
// (bisher wurde das NICHT geforwardet → Diagnostic aktualisierte nie).
broadcast({ type: "project_changed", payload: msg.payload || {} });
} else if (msg.type === "sat_hello") {
// Ein Satellit (Aussenposten in einem fremden Netz) meldet sich.
const p = msg.payload || {};
if (p.id) {
satellites.set(p.id, {
id: p.id, location: p.location || p.id,
caps: p.caps || [], control: !!p.control, last_seen: Date.now(),
});
broadcastSatellites();
}
} else if (msg.type === "sat_devices") {
// Antwort eines Satelliten auf sat_discover → Geraeteliste an Browser.
const p = msg.payload || {};
if (p.satellite && satellites.has(p.satellite)) satellites.get(p.satellite).last_seen = Date.now();
broadcast({ type: "sat_devices", satellite: p.satellite || "",
location: p.location || "", devices: p.devices || [] });
} else if (msg.type === "agent_activity") {
// Bridge meldet "ARIA denkt/schreibt/tool" oder "idle" — an Browser
// weiterreichen, damit der Thinking-Indikator im Chat erscheint.
@@ -2407,6 +2438,8 @@ wss.on("connection", (ws) => {
ws.send(JSON.stringify({ type: "init", state, logs: logs.slice(-100) }));
// Letzten Disk-Status mitgeben damit der Client sofort weiss wie's um Platz steht
if (currentDiskStatus) ws.send(JSON.stringify(currentDiskStatus));
// Aktuell bekannte Satelliten mitgeben (RVS replayt sat_hello nicht).
ws.send(JSON.stringify({ type: "sat_update", satellites: satelliteList() }));
ws.on("message", (raw) => {
try {
@@ -2425,6 +2458,14 @@ wss.on("connection", (ws) => {
connectGateway();
} else if (msg.action === "reconnect_rvs") {
connectRVS();
} else if (msg.action === "sat_list") {
// Browser will die aktuelle Satelliten-Liste.
ws.send(JSON.stringify({ type: "sat_update", satellites: satelliteList() }));
} else if (msg.action === "sat_discover") {
// Browser triggert einen Geraete-Scan auf einem Satelliten.
sendToRVS_raw({ type: "sat_discover",
payload: { satellite: msg.satellite || "", force: true },
timestamp: Date.now() });
} else if (msg.action === "test_proxy") {
testProxy(msg.text);
} else if (msg.action === "check_proxy_auth") {