diff --git a/dist/mua-2026.08.18.r004-x86_64-1.txz b/dist/mua-2026.08.18.r004-x86_64-1.txz new file mode 100644 index 0000000..5962e9c Binary files /dev/null and b/dist/mua-2026.08.18.r004-x86_64-1.txz differ diff --git a/mcp/helpers.php b/mcp/helpers.php index d5518b6..381903b 100644 --- a/mcp/helpers.php +++ b/mcp/helpers.php @@ -10,7 +10,7 @@ error_reporting(E_ALL); ini_set('display_errors', 0); // Fehler werden als JSON-RPC-Error zurückgegeben, nicht als HTML -const MUA_VERSION = '2026.08.18.r003'; +const MUA_VERSION = '2026.08.18.r004'; const MUA_SERVER_NAME = 'mua'; /** diff --git a/mcp/server.php b/mcp/server.php index d2b8f62..8f5f731 100644 --- a/mcp/server.php +++ b/mcp/server.php @@ -21,7 +21,7 @@ const MUA_PORT = 3002; const MUA_BIND = '0.0.0.0'; const MUA_SESSION_TTL = 3600; // Sekunden const MUA_SERVER_NAME = 'mua'; -const MUA_VERSION = '2026.08.18.r003'; +const MUA_VERSION = '2026.08.18.r004'; // ── Session-Management (in-memory) ─────────────────────────────────────── $sessions = []; // session_id => ['created' => time, 'initialized' => bool] diff --git a/package.json b/package.json index 710a776..ef4ed2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mua", - "version": "2026.08.18.r003", + "version": "2026.08.18.r004", "description": "Mikes Unraid Agent - MCP over HTTP (Streamable HTTP) for Unraid", "type": "module", "main": "src/index.ts", diff --git a/plugin/mua.plg b/plugin/mua.plg index 6695fe7..c5627cf 100644 --- a/plugin/mua.plg +++ b/plugin/mua.plg @@ -2,13 +2,13 @@ - + - - + + ]> -### 2026.08.18.r003 +### 2026.08.18.r004 +- Auto-Restart: Binary erkennt Update auf Platte (mtime/size) und startet den Service automatisch neu. +- WebGUI: „MUA neu starten"-Button (manueller Restart über Config-Server). +- POST-INSTALL/UPDATE: Service wird nach Installation/Update automatisch neu gestartet. +- WebGUI: Version wird dynamisch aus /health gelesen (kein hartkodiertes rNNN). +### 2026.08.18.r002 - API-Key-Authentifizierung (Bearer-Token) für den MCP-HTTP-Endpunkt (Port 3002). /health bleibt offen. - Einstellungs-Maske im WebGUI-Tab: API-Key generieren + Tools per Checkbox aktivieren/deaktivieren. - Config-Server auf 127.0.0.1:3013 (nur localhost) für WebGUI-Integration. @@ -70,23 +75,31 @@ Das .txz enthält: install/doinst.sh (läuft nach Installation) =========================================== --> - + &txzURL; &txzSHA256; set +e +echo "" +echo " Starte MUA-Service neu..." +/etc/rc.d/rc.mua restart 2>/dev/null || true + echo "" echo " Führe Health-Check aus..." -sleep 2 +sleep 3 if curl -sf "http://127.0.0.1:3002/health" > /dev/null 2>&1; then echo "" echo " Health-Check: OK" diff --git a/plugin/plugin.json b/plugin/plugin.json index 3408582..6507a4d 100644 --- a/plugin/plugin.json +++ b/plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "mua", "author": "Michael", - "version": "2026.08.18.r003", + "version": "2026.08.18.r004", "minver": "7.0.0", "pluginDirectory": "/usr/local/emhttp/plugins/mua", "configDirectory": "/boot/config/plugins/mua", diff --git a/scripts/mua.page b/scripts/mua.page index 7985cab..2772d68 100644 --- a/scripts/mua.page +++ b/scripts/mua.page @@ -49,6 +49,13 @@ $health_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); $health_ok = ($health_code === 200); +// Version aus /health lesen (dynamisch, kein hartkodiertes rNNN) +$running_version = ''; +if ($health_ok && $health !== false) { + $h = json_decode($health, true); + $running_version = $h['version'] ?? ''; +} + // ── Config vom Config-Server laden (Port 3003) ────────────────────────── $config = null; $ch = curl_init('http://127.0.0.1:' . $config_port . '/config'); @@ -91,6 +98,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $payload['enabledTools'] = $selected; } + // C) Service neu starten + if (isset($_POST['action']) && $_POST['action'] === 'restart') { + $ch = curl_init('http://127.0.0.1:' . $config_port . '/restart'); + curl_setopt_array($ch, [ + CURLOPT_RETURNTRANSFER => true, + CURLOPT_TIMEOUT => 5, + CURLOPT_CONNECTTIMEOUT => 3, + CURLOPT_POST => true, + ]); + $resp_raw = curl_exec($ch); + $resp_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($resp_code === 200) { + $flash_msg = 'MUA wird neu gestartet (Service restart).'; + $flash_type = 'ok'; + } else { + $flash_msg = 'Fehler beim Neustart (HTTP ' . $resp_code . ')'; + $flash_type = 'err'; + } + } + if (!empty($payload)) { $ch = curl_init('http://127.0.0.1:' . $config_port . '/config'); curl_setopt_array($ch, [ @@ -248,7 +276,7 @@ $tool_groups = [

Details

- + @@ -268,3 +296,10 @@ $tool_groups = [
PluginMUA (Mikes Unraid Agent)
Version2026.08.18.r003
Version
RuntimeTypeScript (Bun Runtime, kompiliertes Binary)
Binary
Port (MCP)
Status/etc/rc.d/rc.mua status
Logstail -f /var/log/plugins/mua.log
+ +

Service neu starten

+

Startet den MCP-Service neu (z. B. nach einem Plugin-Update, wenn sich das Binary geändert hat).

+
+ + +
diff --git a/src/helpers.ts b/src/helpers.ts index 5fe7f21..be4392d 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -13,7 +13,7 @@ import { createConnection, type Socket } from "net"; // ── Konstanten ────────────────────────────────────────────────────────── export const MUA_SERVER_NAME = "mua"; -export const MUA_VERSION = "2026.08.18.r003"; +export const MUA_VERSION = "2026.08.18.r004"; export const MUA_PROTOCOL_VERSION = "2025-03-26"; export const PHP_HELPER = "/usr/local/bin/unraid-docker-mcp-helper.php"; diff --git a/src/index.ts b/src/index.ts index 9b4aa01..04654c6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -21,6 +21,8 @@ import { import { TOOLS, toolByName } from "./tools"; import { checkAuth, isToolEnabled, getApiKey, getEnabledTools, setApiKey, setEnabledTools } from "./auth"; import { randomBytes } from "node:crypto"; +import { spawn } from "node:child_process"; +import { statSync } from "node:fs"; const PORT = Number(process.env["MUA_PORT"] ?? 3002); const HOST = process.env["MUA_HOST"] ?? "0.0.0.0"; @@ -312,10 +314,25 @@ try { const path = url.pathname; const method = req.method; - if (path !== "/config") { + if (path !== "/config" && path !== "/restart") { return Response.json({ error: "Not found" }, { status: 404 }); } + // POST /restart: Service neu starten (für WebGUI-Button) + if (path === "/restart" && method === "POST") { + const rcScript = process.env["MUA_RC_SCRIPT"] ?? "/etc/rc.d/rc.mua"; + try { + const child = spawn(rcScript, ["restart"], { + detached: true, + stdio: "ignore", + }); + child.unref(); + return Response.json({ ok: true, message: "Restart initiated" }); + } catch (e) { + return Response.json({ error: String(e) }, { status: 500 }); + } + } + // GET: Config lesen if (method === "GET") { return Response.json({ @@ -368,6 +385,49 @@ console.log( (configServer ? ` + 127.0.0.1:${CONFIG_PORT} (config)` : " (config: NICHT VERFÜGBAR)"), ); +// ── Auto-Restart bei Binary-Update ────────────────────────────────────── +// Beim Plugin-Update wird das Binary auf Platte ersetzt, aber der laufende +// Prozess hält das alte Binary im Speicher (Linux-Verhalten). Wir erkennen +// den Change (mtime + size) und starten den Service automatisch neu. +const BINARY_PATH = process.env["MUA_BINARY"] ?? "/usr/local/bin/mua"; +const RC_SCRIPT = process.env["MUA_RC_SCRIPT"] ?? "/etc/rc.d/rc.mua"; +let binarySnapshot: { mtimeMs: number; size: number } | null = null; +try { + const st = statSync(BINARY_PATH); + binarySnapshot = { mtimeMs: st.mtimeMs, size: st.size }; +} catch { + // Binary-Pfad nicht lesbar (z.B. lokaler Test) — Auto-Restart deaktiviert +} + +function checkBinaryUpdate() { + if (!binarySnapshot) return; + try { + const st = statSync(BINARY_PATH); + if (st.mtimeMs !== binarySnapshot.mtimeMs || st.size !== binarySnapshot.size) { + console.log( + `[MUA] Binary-Update erkannt (${BINARY_PATH} geändert). ` + + `Starte Service neu: ${RC_SCRIPT} restart`, + ); + // rc.mua restart detached ausführen, dann sauber beenden + const child = spawn(RC_SCRIPT, ["restart"], { + detached: true, + stdio: "ignore", + }); + child.unref(); + // Kurze Pause, damit der Log-Flush durchkommt + setTimeout(() => process.exit(0), 500); + } + } catch { + // Binary temporär nicht lesbar — ignorieren + } +} + +const updateCheckInterval = setInterval( + checkBinaryUpdate, + Number(process.env["MUA_UPDATE_CHECK_INTERVAL"] ?? 30_000), +); +updateCheckInterval.unref(); + // Graceful shutdown process.on("SIGTERM", () => { console.log("[MUA] SIGTERM received, shutting down");