Skip to content

Commit 3a751ba

Browse files
feat(dashboard): add diagnostics debug log snapshot for AI analysis
- New endpoint GET /api/diagnostics/snapshot?minutes=N returns plain-text system state dump (agent, orchestrator, goals, tasks, workers, economy, turns, events, diagnostic flags) - Debug Log panel in Diagnostics section with 2m/5m/10m buttons + copy - Moved Diagnostics to separate bottom sidebar segment - Added nav-separator + debug-log-viewer CSS
1 parent 4dd8d3a commit 3a751ba

5 files changed

Lines changed: 371 additions & 3 deletions

File tree

apps/dashboard/public/app.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,29 @@
567567
html += `<div class="empty" style="margin-top:24px;color:var(--green)">✓ All systems nominal. No stalls, zombies, or dispatch failures detected.</div>`;
568568
}
569569

570+
// ── Debug Log — system snapshot for AI analysis ──
571+
html += `<div class="nav-separator" style="margin:32px 0 16px"></div>`;
572+
html += `<div class="section-header"><span class="section-title">📋 Debug Log — System Snapshot</span></div>`;
573+
html += `<div class="card-sub" style="margin-bottom:12px">
574+
Generate a plain-text snapshot of the entire system state. Copy and paste into an AI tool for error analysis.
575+
</div>`;
576+
html += `<div class="debug-log-toolbar">
577+
<div style="display:flex;gap:6px">
578+
<button class="btn ${window.__debugMinutes === 2 ? 'active' : ''}" onclick="window.__loadDebugLog(2)">Last 2 min</button>
579+
<button class="btn ${window.__debugMinutes === 5 || !window.__debugMinutes ? 'active' : ''}" onclick="window.__loadDebugLog(5)">Last 5 min</button>
580+
<button class="btn ${window.__debugMinutes === 10 ? 'active' : ''}" onclick="window.__loadDebugLog(10)">Last 10 min</button>
581+
</div>
582+
<button class="btn" onclick="window.__copyDebugLog()" id="copyDebugBtn" style="display:${window.__debugLogText ? 'inline-flex' : 'none'}">📋 Copy to Clipboard</button>
583+
</div>`;
584+
585+
if (window.__debugLogText) {
586+
html += `<pre class="debug-log-viewer" id="debugLogContent">${esc(window.__debugLogText)}</pre>`;
587+
} else if (window.__debugLoading) {
588+
html += `<div class="debug-log-viewer" style="text-align:center;padding:40px;color:var(--text-muted)">Loading snapshot…</div>`;
589+
} else {
590+
html += `<div class="debug-log-viewer" style="text-align:center;padding:40px;color:var(--text-muted)">Click a time window button above to generate a snapshot</div>`;
591+
}
592+
570593
return html;
571594
},
572595

@@ -846,6 +869,50 @@
846869
window.__dbSetOffset = (o) => { window.__dbOffset = o; navigate(); };
847870
window.__switchDbTable = (t) => { window.__dbTable = t; window.__dbOffset = 0; navigate(); };
848871

872+
// ─── Debug Log State ────────────────────────────────
873+
window.__debugLogText = "";
874+
window.__debugMinutes = 0;
875+
window.__debugLoading = false;
876+
877+
window.__loadDebugLog = async (minutes) => {
878+
window.__debugMinutes = minutes;
879+
window.__debugLoading = true;
880+
window.__debugLogText = "";
881+
navigate(); // re-render to show loading state
882+
try {
883+
const resp = await fetch(`/api/diagnostics/snapshot?minutes=${minutes}`);
884+
window.__debugLogText = await resp.text();
885+
} catch (err) {
886+
window.__debugLogText = `Error loading snapshot: ${err.message}`;
887+
}
888+
window.__debugLoading = false;
889+
navigate(); // re-render with content
890+
};
891+
892+
window.__copyDebugLog = async () => {
893+
try {
894+
await navigator.clipboard.writeText(window.__debugLogText);
895+
const btn = document.getElementById("copyDebugBtn");
896+
if (btn) {
897+
btn.textContent = "✓ Copied!";
898+
setTimeout(() => { btn.textContent = "📋 Copy to Clipboard"; }, 2000);
899+
}
900+
} catch {
901+
// Fallback for older browsers
902+
const ta = document.createElement("textarea");
903+
ta.value = window.__debugLogText;
904+
document.body.appendChild(ta);
905+
ta.select();
906+
document.execCommand("copy");
907+
document.body.removeChild(ta);
908+
const btn = document.getElementById("copyDebugBtn");
909+
if (btn) {
910+
btn.textContent = "✓ Copied!";
911+
setTimeout(() => { btn.textContent = "📋 Copy to Clipboard"; }, 2000);
912+
}
913+
}
914+
};
915+
849916
// ─── Router ─────────────────────────────────────────
850917

851918
function getRoute() {

apps/dashboard/public/index.html

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,6 @@ <h1>Automaton</h1>
3535
<li><a href="#activity" class="nav-link" data-section="activity">
3636
<span class="nav-icon">📊</span> Activity
3737
</a></li>
38-
<li><a href="#diagnostics" class="nav-link" data-section="diagnostics">
39-
<span class="nav-icon">🚨</span> Diagnostics
40-
</a></li>
4138
<li><a href="#db_inspector" class="nav-link" data-section="db_inspector">
4239
<span class="nav-icon">🗄️</span> DB Inspector
4340
</a></li>
@@ -51,6 +48,12 @@ <h1>Automaton</h1>
5148
<span class="nav-icon">⚙️</span> Config
5249
</a></li>
5350
</ul>
51+
<div class="nav-separator"></div>
52+
<ul class="nav-list">
53+
<li><a href="#diagnostics" class="nav-link" data-section="diagnostics">
54+
<span class="nav-icon">🚨</span> Diagnostics
55+
</a></li>
56+
</ul>
5457
<div class="sidebar-footer">
5558
<div class="connection-badge" id="connBadge">
5659
<span class="dot"></span> <span id="connText">Checking…</span>

apps/dashboard/public/style.css

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ body {
8888
.nav-list {
8989
list-style: none;
9090
padding: 12px 8px;
91+
}
92+
93+
.sidebar>.nav-list:first-of-type {
9194
flex: 1;
95+
overflow-y: auto;
9296
}
9397

9498
.nav-link {
@@ -618,4 +622,45 @@ tr:hover td {
618622
.timeline-ts {
619623
font-size: 11px;
620624
color: var(--text-muted);
625+
}
626+
627+
/* ─── Nav Separator ────────────────────────────────────────── */
628+
629+
.nav-separator {
630+
height: 1px;
631+
background: var(--border);
632+
margin: 4px 16px;
633+
}
634+
635+
/* ─── Debug Log Viewer ─────────────────────────────────────── */
636+
637+
.debug-log-toolbar {
638+
display: flex;
639+
align-items: center;
640+
justify-content: space-between;
641+
gap: 12px;
642+
margin-bottom: 12px;
643+
flex-wrap: wrap;
644+
}
645+
646+
.debug-log-toolbar .btn.active {
647+
background: var(--accent-glow);
648+
color: var(--accent);
649+
border-color: rgba(59, 130, 246, 0.3);
650+
}
651+
652+
.debug-log-viewer {
653+
background: var(--bg-input);
654+
border: 1px solid var(--border);
655+
border-radius: var(--radius);
656+
padding: 20px;
657+
font-family: var(--mono);
658+
font-size: 11px;
659+
line-height: 1.6;
660+
color: var(--text-secondary);
661+
max-height: 600px;
662+
overflow-y: auto;
663+
white-space: pre-wrap;
664+
word-break: break-word;
665+
margin-bottom: 24px;
621666
}

0 commit comments

Comments
 (0)