diff --git a/public_html/admin/index.php b/public_html/admin/index.php index 7c2cbe6..5ce080c 100644 --- a/public_html/admin/index.php +++ b/public_html/admin/index.php @@ -589,6 +589,14 @@ if ($action) { } j(['lines'=>$out, 'next_line'=>$total]); + case 'arc_setup_log': + $logFile = '/var/log/jarvis/arc-setup.log'; + $since = max(0, (int)($_GET['since'] ?? 0)); + if (!file_exists($logFile)) { j(['lines'=>[],'next_line'=>0]); } + $allLines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $total = count($allLines); + if (!empty($_GET['snapshot'])) { j(['next_line'=>$total]); } + j(['lines'=>array_values(array_slice($allLines, $since)), 'next_line'=>$total]); case 'arc_status': $ch = curl_init('http://127.0.0.1:7474/status'); curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>5, CURLOPT_CONNECTTIMEOUT=>3]); @@ -2327,18 +2335,66 @@ async function runIntentGenerator() { } async function arcSetup() { - if (!confirm('Run Arc Reactor setup?\n\nThis will:\n• Copy reactor.py from deploy/\n• Install Python packages\n• Install/update systemd service\n• Restart jarvis-arc')) return; - const btn = event.currentTarget; - btn.disabled = true; btn.textContent = '⏳ SETTING UP...'; - try { - const d = await api('worker', {type:'daemon', id:'arc_reactor', action:'setup'}); - toast(d.msg || (d.ok ? 'Setup started' : 'Setup failed'), d.ok ? 'ok' : 'err'); - setTimeout(() => { loadWorkers(); btn.disabled=false; btn.innerHTML='⚙ SETUP'; }, 5000); - } catch(e) { - toast('Setup failed: ' + e.message, 'err'); - btn.disabled=false; btn.innerHTML='⚙ SETUP'; + const modalHtml = ` +
+
LAUNCHING...
+
Waiting for output...
+
`; + + openModal("⚙ ARC REACTOR SETUP", modalHtml, null, null); + document.getElementById("modalSave").textContent = "CLOSE"; + let _stop = false; + document.getElementById("modalSave").onclick = () => { _stop = true; closeModal(); loadWorkers(); }; + document.getElementById("modalClose").onclick = () => { _stop = true; closeModal(); loadWorkers(); }; + + const logEl = document.getElementById("as-log"); + const statEl = document.getElementById("as-status"); + + const snap = await api("arc_setup_log", {snapshot:1}); + let lastLine = snap?.next_line ?? 0; + + const kick = await api("worker", {type:"daemon", id:"arc_reactor", action:"setup"}); + if (!kick?.ok) { + statEl.style.color = "var(--red)"; + statEl.textContent = "LAUNCH FAILED: " + (kick?.msg || kick?.error || "unknown"); + return; } + statEl.textContent = "RUNNING — polling every 2s..."; + + async function pollLog() { + if (_stop) return; + try { + const res = await api("arc_setup_log", {since: lastLine}); + if (res?.lines?.length) { + lastLine = res.next_line; + if (logEl.textContent === "Waiting for output...") logEl.textContent = ""; + res.lines.forEach(line => { + const d = document.createElement("div"); + const l = line.toLowerCase(); + if (l.includes("error") || l.includes("fail")) d.style.color = "var(--red)"; + else if (l.includes("warn") || l.includes("skip")) d.style.color = "var(--yellow)"; + else if (l.includes("ok") || l.includes("done") || l.includes("active") || + l.includes("success") || l.includes("restart") || l.includes("enabled")) d.style.color = "var(--green)"; + else d.style.color = "var(--text-dim)"; + d.textContent = line; + logEl.appendChild(d); + }); + logEl.scrollTop = logEl.scrollHeight; + const joined = res.lines.join(" ").toLowerCase(); + if (joined.includes("systemctl restart") || joined.includes("active") || + joined.includes("done") || joined.includes("failed")) { + statEl.style.color = (joined.includes("error") || joined.includes("fail")) ? "var(--red)" : "var(--green)"; + statEl.textContent = (joined.includes("error") || joined.includes("fail")) ? "SETUP FAILED" : "SETUP COMPLETE"; + document.getElementById("modalSave").textContent = "CLOSE"; + loadWorkers(); return; + } + } + } catch(e) {} + setTimeout(pollLog, 2000); + } + setTimeout(pollLog, 1500); } + async function workerAction(type,id,action) { if (type === 'agent' && action === 'update') { await agentUpdateFlow(id);