Panou web pe 127.0.0.1:18790, unit systemd separat de al puntii. Server stdlib
(fara dependinte noi), tokenii de design si tiparul de endpoint-uri preluate din
/home/moltbot/echo-core/dashboard (handlers/eco.py) de pe LXC 110.
Arata: starea unitatii (uptime, PID, memoria cgroup, restarturi), firele din
state.json cu tur in zbor si cost, costul zilei fata de plafon, confirmarile
PreToolUse in asteptare (aprobabile direct din pagina), bot.log / infra.log si
opt verificari de diagnostic.
Face: start / stop / restart pe punte, cautarea si curatarea orfanilor prin
cleanup.py, repornirea propriului serviciu.
Garantii, cu teste:
- unitatea controlata e fixa in cod; un {"unit": "ssh.service"} in cerere nu
schimba nimic, altfel panoul ar fi systemctl remote fara parola;
- stop/restart intorc 409 cu lista firelor active si cer force explicit, fiindca
KillMode=control-group taie tururile in desfasurare;
- state.json se citeste fara lock: panoul nu are voie sa blocheze botul;
- diagnosticul pica daca reapare Bash(ssh:*) in deny (regresia de azi).
Uptime-ul se calculeaza din time.monotonic(), nu din /proc/uptime: in LXC acela
e virtualizat de lxcfs si da diferenta negativa fata de monotonic-ul systemd.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B29CApsP1JkSdjYaGaHpE7
44 lines
1.4 KiB
HTML
44 lines
1.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ro" data-theme="dark">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Autentificare — Punte Discord</title>
|
|
<link rel="stylesheet" href="/static/tokens.css">
|
|
<link rel="stylesheet" href="/static/app.css">
|
|
</head>
|
|
<body>
|
|
<div class="login">
|
|
<form id="f" autocomplete="off">
|
|
<h1>Punte Discord → Claude Code</h1>
|
|
<p>Token din <span class="mono">~/.claude-discord/env</span> (<span class="mono">DASHBOARD_TOKEN</span>).</p>
|
|
<input type="password" id="token" placeholder="token" autofocus required>
|
|
<div class="error-msg" id="err"></div>
|
|
<button class="primary" type="submit">Intră</button>
|
|
</form>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
var saved = localStorage.getItem('theme');
|
|
if (saved) document.documentElement.setAttribute('data-theme', saved);
|
|
})();
|
|
document.getElementById('f').addEventListener('submit', async function (e) {
|
|
e.preventDefault();
|
|
var err = document.getElementById('err');
|
|
err.textContent = '';
|
|
try {
|
|
var r = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ token: document.getElementById('token').value })
|
|
});
|
|
if (r.ok) { location.href = '/'; return; }
|
|
err.textContent = 'Token invalid.';
|
|
} catch (ex) {
|
|
err.textContent = 'Serverul nu răspunde.';
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|