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);