orquesta-agent 0.2.64 → 0.2.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ui/public/app.js +83 -2
- package/dist/ui/public/index.html +13 -0
- package/dist/ui/public/style.css +60 -0
- package/package.json +1 -1
package/dist/ui/public/app.js
CHANGED
|
@@ -32,6 +32,7 @@ function switchTab(tab) {
|
|
|
32
32
|
document.getElementById('tab-' + tab)?.classList.add('active')
|
|
33
33
|
document.querySelector(`[data-tab="${tab}"]`)?.classList.add('active')
|
|
34
34
|
if (tab === 'health') loadHealth()
|
|
35
|
+
if (tab === 'logs') loadAllLogs()
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
// ── System Info ────────────────────────────────────────────────────
|
|
@@ -242,7 +243,7 @@ function connectLogStream(id) {
|
|
|
242
243
|
const { logs } = JSON.parse(e.data)
|
|
243
244
|
const el = document.getElementById('logs-' + id)
|
|
244
245
|
if (el) {
|
|
245
|
-
el.
|
|
246
|
+
el.innerHTML = colorizeLogs(logs)
|
|
246
247
|
el.scrollTop = el.scrollHeight
|
|
247
248
|
}
|
|
248
249
|
} catch {}
|
|
@@ -318,6 +319,86 @@ async function saveAgent(e) {
|
|
|
318
319
|
} catch (e2) { alert(e2.message) }
|
|
319
320
|
}
|
|
320
321
|
|
|
322
|
+
// ── All Logs Tab ───────────────────────────────────────────────────
|
|
323
|
+
|
|
324
|
+
let allLogsSources = new Map()
|
|
325
|
+
|
|
326
|
+
function loadAllLogs() {
|
|
327
|
+
const grid = document.getElementById('all-logs-grid')
|
|
328
|
+
if (!grid) return
|
|
329
|
+
|
|
330
|
+
// Close existing streams
|
|
331
|
+
for (const es of allLogsSources.values()) es.close()
|
|
332
|
+
allLogsSources.clear()
|
|
333
|
+
|
|
334
|
+
if (agents.length === 0) {
|
|
335
|
+
grid.innerHTML = '<div class="empty-state"><p>No agents running</p></div>'
|
|
336
|
+
return
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const runningAgents = agents.filter(a => a.status === 'running')
|
|
340
|
+
if (runningAgents.length === 0) {
|
|
341
|
+
grid.innerHTML = '<div class="empty-state"><p>No agents currently running</p></div>'
|
|
342
|
+
return
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
grid.innerHTML = runningAgents.map(a => {
|
|
346
|
+
const isDiscovered = a.id.startsWith('discovered-')
|
|
347
|
+
const name = isDiscovered ? a.workingDir.split('/').pop() || a.name : a.name
|
|
348
|
+
return `<div class="all-logs-card">
|
|
349
|
+
<div class="all-logs-card-header">
|
|
350
|
+
<span class="agent-name-pill"><span class="badge-dot pulse"></span>${esc(name)}</span>
|
|
351
|
+
<span style="font-size:11px;color:var(--text-500)">PID ${a.pid || '?'}</span>
|
|
352
|
+
</div>
|
|
353
|
+
<div class="log-viewer" id="all-logs-${a.id}"></div>
|
|
354
|
+
</div>`
|
|
355
|
+
}).join('')
|
|
356
|
+
|
|
357
|
+
// Connect SSE for each agent
|
|
358
|
+
for (const a of runningAgents) {
|
|
359
|
+
const es = new EventSource(`${API}/agents/${a.id}/logs/stream`)
|
|
360
|
+
es.onmessage = (e) => {
|
|
361
|
+
try {
|
|
362
|
+
const { logs } = JSON.parse(e.data)
|
|
363
|
+
const el = document.getElementById('all-logs-' + a.id)
|
|
364
|
+
if (el) {
|
|
365
|
+
el.innerHTML = colorizeLogs(logs)
|
|
366
|
+
el.scrollTop = el.scrollHeight
|
|
367
|
+
}
|
|
368
|
+
} catch {}
|
|
369
|
+
}
|
|
370
|
+
allLogsSources.set(a.id, es)
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// ANSI color code → HTML span conversion
|
|
375
|
+
function colorizeLogs(lines) {
|
|
376
|
+
return lines.map(line => {
|
|
377
|
+
let html = esc(line)
|
|
378
|
+
// Strip ANSI codes and apply CSS classes
|
|
379
|
+
html = html
|
|
380
|
+
// Colors
|
|
381
|
+
.replace(/\x1b\[32m|\x1b\[39m/g, '') // strip raw escapes from esc()
|
|
382
|
+
.replace(/\[32m/g, '<span class="ansi-green">')
|
|
383
|
+
.replace(/\[33m/g, '<span class="ansi-yellow">')
|
|
384
|
+
.replace(/\[34m/g, '<span class="ansi-blue">')
|
|
385
|
+
.replace(/\[31m/g, '<span class="ansi-red">')
|
|
386
|
+
.replace(/\[36m/g, '<span class="ansi-cyan">')
|
|
387
|
+
.replace(/\[35m/g, '<span class="ansi-magenta">')
|
|
388
|
+
.replace(/\[1m/g, '<span class="ansi-bold">')
|
|
389
|
+
.replace(/\[2m/g, '<span class="ansi-dim">')
|
|
390
|
+
.replace(/\[0?m/g, '</span>')
|
|
391
|
+
.replace(/\[39m/g, '</span>')
|
|
392
|
+
// Highlight patterns
|
|
393
|
+
if (html.includes('✓') || html.includes('✅')) html = `<span class="log-success">${html}</span>`
|
|
394
|
+
else if (html.includes('⚠') || html.includes('WARN')) html = `<span class="log-warn">${html}</span>`
|
|
395
|
+
else if (html.includes('✗') || html.includes('❌') || html.includes('ERROR')) html = `<span class="log-error">${html}</span>`
|
|
396
|
+
// Dim timestamps
|
|
397
|
+
html = html.replace(/\[(\d{2}:\d{2}:\d{2})\]/g, '<span class="log-timestamp">[$1]</span>')
|
|
398
|
+
return `<div class="log-line">${html}</div>`
|
|
399
|
+
}).join('')
|
|
400
|
+
}
|
|
401
|
+
|
|
321
402
|
// ── Fullscreen Logs ────────────────────────────────────────────────
|
|
322
403
|
|
|
323
404
|
let fullscreenLogId = null
|
|
@@ -336,7 +417,7 @@ function openFullscreenLogs(id, name) {
|
|
|
336
417
|
const { logs } = JSON.parse(e.data)
|
|
337
418
|
const el = document.getElementById('logs-fullscreen-content')
|
|
338
419
|
if (el) {
|
|
339
|
-
el.
|
|
420
|
+
el.innerHTML = colorizeLogs(logs)
|
|
340
421
|
el.scrollTop = el.scrollHeight
|
|
341
422
|
}
|
|
342
423
|
} catch {}
|
|
@@ -26,6 +26,10 @@
|
|
|
26
26
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 10h.01M10 10h.01M6 14h12"/></svg>
|
|
27
27
|
Agents
|
|
28
28
|
</button>
|
|
29
|
+
<button class="nav-item" data-tab="logs" onclick="switchTab('logs')">
|
|
30
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>
|
|
31
|
+
All Logs
|
|
32
|
+
</button>
|
|
29
33
|
<button class="nav-item" data-tab="health" onclick="switchTab('health')">
|
|
30
34
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 12h-4l-3 9L9 3l-3 9H2"/></svg>
|
|
31
35
|
System
|
|
@@ -74,6 +78,15 @@
|
|
|
74
78
|
<div id="agents-container"></div>
|
|
75
79
|
</div>
|
|
76
80
|
|
|
81
|
+
<!-- All Logs Tab -->
|
|
82
|
+
<div id="tab-logs" class="tab-content">
|
|
83
|
+
<div class="page-header">
|
|
84
|
+
<h1>All Logs</h1>
|
|
85
|
+
<p class="page-subtitle">Real-time logs from all agents</p>
|
|
86
|
+
</div>
|
|
87
|
+
<div id="all-logs-grid" class="all-logs-grid"></div>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
77
90
|
<!-- Health Tab -->
|
|
78
91
|
<div id="tab-health" class="tab-content">
|
|
79
92
|
<div class="page-header">
|
package/dist/ui/public/style.css
CHANGED
|
@@ -619,6 +619,66 @@ body {
|
|
|
619
619
|
border-top: 1px solid var(--bg-700);
|
|
620
620
|
}
|
|
621
621
|
|
|
622
|
+
/* ── All Logs Grid ──────────────────────────────────── */
|
|
623
|
+
.all-logs-grid {
|
|
624
|
+
display: grid;
|
|
625
|
+
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
|
|
626
|
+
gap: 12px;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.all-logs-card {
|
|
630
|
+
background: rgba(24,24,27,0.5);
|
|
631
|
+
border: 1px solid var(--bg-700);
|
|
632
|
+
border-radius: 12px;
|
|
633
|
+
overflow: hidden;
|
|
634
|
+
backdrop-filter: blur(10px);
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.all-logs-card-header {
|
|
638
|
+
display: flex;
|
|
639
|
+
justify-content: space-between;
|
|
640
|
+
align-items: center;
|
|
641
|
+
padding: 10px 14px;
|
|
642
|
+
background: var(--bg-900);
|
|
643
|
+
border-bottom: 1px solid var(--bg-700);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.all-logs-card-header .agent-name-pill {
|
|
647
|
+
display: flex;
|
|
648
|
+
align-items: center;
|
|
649
|
+
gap: 6px;
|
|
650
|
+
font-size: 13px;
|
|
651
|
+
font-weight: 600;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.all-logs-card-header .agent-name-pill .badge-dot {
|
|
655
|
+
width: 6px;
|
|
656
|
+
height: 6px;
|
|
657
|
+
border-radius: 50%;
|
|
658
|
+
background: var(--green);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.all-logs-card .log-viewer {
|
|
662
|
+
height: 350px;
|
|
663
|
+
border-radius: 0;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/* ── Log Colors (ANSI) ──────────────────────────────── */
|
|
667
|
+
.log-viewer .log-line { margin: 0; }
|
|
668
|
+
.log-viewer .ansi-green { color: #4ade80; }
|
|
669
|
+
.log-viewer .ansi-red { color: #f87171; }
|
|
670
|
+
.log-viewer .ansi-yellow { color: #facc15; }
|
|
671
|
+
.log-viewer .ansi-blue { color: #60a5fa; }
|
|
672
|
+
.log-viewer .ansi-cyan { color: #22d3ee; }
|
|
673
|
+
.log-viewer .ansi-magenta { color: #c084fc; }
|
|
674
|
+
.log-viewer .ansi-bold { font-weight: 700; }
|
|
675
|
+
.log-viewer .ansi-dim { opacity: 0.6; }
|
|
676
|
+
.log-viewer .log-timestamp { color: #52525b; }
|
|
677
|
+
.log-viewer .log-success { color: #4ade80; }
|
|
678
|
+
.log-viewer .log-warn { color: #facc15; }
|
|
679
|
+
.log-viewer .log-error { color: #f87171; }
|
|
680
|
+
.log-viewer .log-info { color: #60a5fa; }
|
|
681
|
+
|
|
622
682
|
/* ── Fullscreen Logs ────────────────────────────────── */
|
|
623
683
|
.logs-fullscreen {
|
|
624
684
|
display: none;
|