Feat: Hermes-Update Gehirn-Check + Drawer breiter & farbige Update-Icons
- Post-Update-Gehirn-Check: hermes_update_job haengt deploy/hermes-postcheck.sh an (Mem0-Sidecar erreichbar? /api/memory? memory.provider=mc2-memory aktiv? Plugin laedt?). Bricht der Check, wird der Job rot -> kaputtes Gehirn faellt sofort auf. Standalone verifiziert. - SystemDrawer: Breite 500->640px (Log-Fenster endlich lesbar). - Update-Zeilen: farbige Icons (OS cyan, Engine violet, Hermes amber, Modell emerald) wie im Mockup, statt einheitlich grau. Aktiv-Zustand (amber) live verifiziert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -354,9 +354,12 @@ def hermes_update_job() -> dict:
|
|||||||
path = (git or {}).get("path") or os.path.expanduser("~/.hermes/hermes-agent")
|
path = (git or {}).get("path") or os.path.expanduser("~/.hermes/hermes-agent")
|
||||||
py = os.path.join(path, "venv", "bin", "python")
|
py = os.path.join(path, "venv", "bin", "python")
|
||||||
backup = os.path.join(_REPO_ROOT, "deploy", "backup.sh")
|
backup = os.path.join(_REPO_ROOT, "deploy", "backup.sh")
|
||||||
|
postcheck = os.path.join(_REPO_ROOT, "deploy", "hermes-postcheck.sh")
|
||||||
|
# Backup → update → Gateway-Neustart → Gehirn-Check (Job wird rot, wenn Mem0/Plugin kaputt).
|
||||||
cmd = (f"bash {backup} || true; "
|
cmd = (f"bash {backup} || true; "
|
||||||
f"cd {path} && {py} -m hermes_cli.main update --yes "
|
f"cd {path} && {py} -m hermes_cli.main update --yes "
|
||||||
f"&& systemctl --user restart hermes-gateway")
|
f"&& systemctl --user restart hermes-gateway "
|
||||||
|
f"&& sleep 4 && bash {postcheck}")
|
||||||
|
|
||||||
def on_done():
|
def on_done():
|
||||||
_comp_cache.update(ts=0.0, data=[]) # Update-Status neu berechnen lassen
|
_comp_cache.update(ts=0.0, data=[]) # Update-Status neu berechnen lassen
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Post-Update-Check nach einem Hermes-Agent-Update: läuft unser geteiltes „Gehirn"
|
||||||
|
# (Mem0 + die mc2-memory-Integration) noch? Exit 0 = alles ok, sonst 1 → der Job wird
|
||||||
|
# im UI rot, damit ein kaputtes Gehirn sofort auffällt.
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
MC_URL="${MC_URL:-http://127.0.0.1:9001}"
|
||||||
|
MEM0_URL="${MEM0_SERVICE_URL:-http://127.0.0.1:8765}"
|
||||||
|
HERMES="${HERMES_HOME:-$HOME/.hermes}"
|
||||||
|
fail=0
|
||||||
|
|
||||||
|
echo "=== Hermes Post-Update: Gehirn-Check ==="
|
||||||
|
|
||||||
|
if curl -sf -m 5 "$MEM0_URL/health" >/dev/null 2>&1; then
|
||||||
|
echo "PASS · Mem0-Sidecar erreichbar"
|
||||||
|
else
|
||||||
|
echo "FAIL · Mem0-Sidecar NICHT erreichbar"; fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if curl -sf -m 8 "$MC_URL/api/memory" >/dev/null 2>&1; then
|
||||||
|
echo "PASS · /api/memory antwortet"
|
||||||
|
else
|
||||||
|
echo "FAIL · /api/memory antwortet nicht"; fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -qE "^[[:space:]]*provider:[[:space:]]*'?mc2-memory'?" "$HERMES/config.yaml" 2>/dev/null \
|
||||||
|
&& grep -qE "memory_enabled:[[:space:]]*true" "$HERMES/config.yaml" 2>/dev/null; then
|
||||||
|
echo "PASS · memory.provider=mc2-memory aktiv"
|
||||||
|
else
|
||||||
|
echo "FAIL · memory.provider nicht mehr gesetzt (Config vom Update überschrieben?)"; fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ( cd "$HERMES/hermes-agent" && HERMES_HOME="$HERMES" ./venv/bin/python -c \
|
||||||
|
"import sys; sys.path.insert(0,'.'); from plugins.memory import load_memory_provider; p=load_memory_provider('mc2-memory'); assert p and p.name()=='mc2-memory'" \
|
||||||
|
>/dev/null 2>&1 ); then
|
||||||
|
echo "PASS · mc2-memory-Plugin lädt unter dem neuen Hermes"
|
||||||
|
else
|
||||||
|
echo "FAIL · mc2-memory-Plugin lädt nicht (MemoryProvider-ABC geändert?)"; fail=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$fail" -eq 0 ]; then
|
||||||
|
echo "=== GEHIRN OK ✓ ==="
|
||||||
|
else
|
||||||
|
echo "=== GEHIRN-CHECK FEHLGESCHLAGEN — bitte prüfen ==="
|
||||||
|
fi
|
||||||
|
exit "$fail"
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import{r as K,a as Hv,g as Hr,R as Um,c as q2,j as Ne,l as Z2,S as K2,b as Vx,T as $2}from"./index-cq5kdO0r.js";/**
|
import{r as K,a as Hv,g as Hr,R as Um,c as q2,j as Ne,l as Z2,S as K2,b as Vx,T as $2}from"./index-CazXw6yq.js";/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright 2010-2023 Three.js Authors
|
* Copyright 2010-2023 Three.js Authors
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
-1
File diff suppressed because one or more lines are too long
+2
-2
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -7,8 +7,8 @@
|
|||||||
<link rel="manifest" href="/manifest.webmanifest" />
|
<link rel="manifest" href="/manifest.webmanifest" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||||
<title>Mission Control 2.0</title>
|
<title>Mission Control 2.0</title>
|
||||||
<script type="module" crossorigin src="/assets/index-cq5kdO0r.js"></script>
|
<script type="module" crossorigin src="/assets/index-CazXw6yq.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-3d2FUwyu.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-SdhW3gX3.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -20,13 +20,13 @@ const SERVICES = [
|
|||||||
{ id: "llama-swap", label: "Llama Swap", type: "system", reach: "llama-swap" },
|
{ id: "llama-swap", label: "Llama Swap", type: "system", reach: "llama-swap" },
|
||||||
]
|
]
|
||||||
|
|
||||||
function UpdateRow({ icon: Icon, name, status, available, busy, actionLabel, onAction }: {
|
function UpdateRow({ icon: Icon, iconClass, name, status, available, busy, actionLabel, onAction }: {
|
||||||
icon: any; name: string; status: string; available: boolean; busy?: boolean; actionLabel: string; onAction: () => void
|
icon: any; iconClass: string; name: string; status: string; available: boolean; busy?: boolean; actionLabel: string; onAction: () => void
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className={cn("flex items-center gap-3 rounded-lg border px-3 py-2",
|
<div className={cn("flex items-center gap-3 rounded-lg border px-3 py-2",
|
||||||
available ? "border-amber-500/30 bg-amber-500/5" : "border-border/50 bg-background/20")}>
|
available ? "border-amber-500/30 bg-amber-500/5" : "border-border/50 bg-background/20")}>
|
||||||
<Icon className={cn("h-4 w-4 shrink-0", available ? "text-amber-400" : "text-muted-foreground")} />
|
<Icon className={cn("h-4 w-4 shrink-0", iconClass)} />
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
<div className="text-xs text-foreground truncate">{name}</div>
|
<div className="text-xs text-foreground truncate">{name}</div>
|
||||||
<div className={cn("text-[10px] truncate", available ? "text-amber-400/90" : "text-muted-foreground")}>{status}</div>
|
<div className={cn("text-[10px] truncate", available ? "text-amber-400/90" : "text-muted-foreground")}>{status}</div>
|
||||||
@@ -356,7 +356,7 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
|||||||
{/* Drawer */}
|
{/* Drawer */}
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"fixed inset-y-0 right-0 w-full sm:w-[500px] bg-card/85 backdrop-blur-xl border-l border-border/60 shadow-2xl z-50 flex flex-col transform transition-transform duration-300 ease-in-out font-sans text-foreground",
|
"fixed inset-y-0 right-0 w-full sm:w-[640px] bg-card/85 backdrop-blur-xl border-l border-border/60 shadow-2xl z-50 flex flex-col transform transition-transform duration-300 ease-in-out font-sans text-foreground",
|
||||||
open ? "translate-x-0" : "translate-x-full"
|
open ? "translate-x-0" : "translate-x-full"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -428,16 +428,16 @@ export function SystemDrawer({ open, onClose, defaultTab = "maintenance" }: Syst
|
|||||||
<div className="text-[9px] text-muted-foreground -mt-1">Zuletzt gesucht: {formatLastCheck(updates.last_check)}</div>
|
<div className="text-[9px] text-muted-foreground -mt-1">Zuletzt gesucht: {formatLastCheck(updates.last_check)}</div>
|
||||||
)}
|
)}
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<UpdateRow icon={Shield} name="OS-Pakete (apt)" available={!!updates?.os} status={updates?.os ? `${updates.os} verfügbar` : "aktuell"} actionLabel="Aktualisieren" onAction={triggerOsUpdate} />
|
<UpdateRow icon={Shield} iconClass="text-cyan-400" name="OS-Pakete (apt)" available={!!updates?.os} status={updates?.os ? `${updates.os} verfügbar` : "aktuell"} actionLabel="Aktualisieren" onAction={triggerOsUpdate} />
|
||||||
<UpdateRow icon={Server} name="Engine (llama.cpp)" available={!!updates?.engine} status={updates?.engine ? "Update verfügbar" : "aktuell"} actionLabel="Aktualisieren" onAction={triggerEngineUpdate} />
|
<UpdateRow icon={Server} iconClass="text-violet-400" name="Engine (llama.cpp)" available={!!updates?.engine} status={updates?.engine ? "Update verfügbar" : "aktuell"} actionLabel="Aktualisieren" onAction={triggerEngineUpdate} />
|
||||||
{(() => {
|
{(() => {
|
||||||
const h = updates?.components?.find((c) => c.key === "hermes_agent")
|
const h = updates?.components?.find((c) => c.key === "hermes_agent")
|
||||||
return (
|
return (
|
||||||
<UpdateRow icon={Bot} name="Hermes-Agent" available={h?.update === true} busy={hermesUpdating} status={h?.update === true ? `Update: ${h.latest}` : h?.reachable === false ? "offline" : "aktuell"} actionLabel="Aktualisieren" onAction={triggerHermesUpdate} />
|
<UpdateRow icon={Bot} iconClass="text-amber-400" name="Hermes-Agent" available={h?.update === true} busy={hermesUpdating} status={h?.update === true ? `Update: ${h.latest}` : h?.reachable === false ? "offline" : "aktuell"} actionLabel="Aktualisieren" onAction={triggerHermesUpdate} />
|
||||||
)
|
)
|
||||||
})()}
|
})()}
|
||||||
{updates?.model_list?.map((m) => (
|
{updates?.model_list?.map((m) => (
|
||||||
<UpdateRow key={m.role} icon={Box} name={`Modell · ${m.role}`} available={true} status={m.title} actionLabel="Upgrade" onAction={() => triggerModelUpgrade(m.repo, m.role)} />
|
<UpdateRow key={m.role} icon={Box} iconClass="text-emerald-400" name={`Modell · ${m.role}`} available={true} status={m.title} actionLabel="Upgrade" onAction={() => triggerModelUpgrade(m.repo, m.role)} />
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user