agentflow-dashboard 0.1.4 → 0.3.0

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/public/index.html CHANGED
@@ -4,271 +4,1124 @@
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>AgentFlow Dashboard</title>
7
+ <meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
8
+ <meta http-equiv="Pragma" content="no-cache">
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.28.1/cytoscape.min.js"></script>
7
10
  <style>
8
- * {
9
- margin: 0;
10
- padding: 0;
11
- box-sizing: border-box;
11
+ :root {
12
+ --bg-primary: #0d1117;
13
+ --bg-secondary: #161b22;
14
+ --bg-tertiary: #21262d;
15
+ --text-primary: #c9d1d9;
16
+ --text-secondary: #8b949e;
17
+ --accent-primary: #58a6ff;
18
+ --accent-success: #238636;
19
+ --accent-error: #da3633;
20
+ --accent-warning: #f0883e;
21
+ --border-color: #30363d;
12
22
  }
13
23
 
24
+ * { margin: 0; padding: 0; box-sizing: border-box; }
25
+
14
26
  body {
15
27
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
- background: #0f1419;
17
- color: #e6e6e6;
18
- line-height: 1.6;
28
+ background: var(--bg-primary);
29
+ color: var(--text-primary);
30
+ min-height: 100vh;
31
+ overflow: hidden;
19
32
  }
20
33
 
34
+ /* Header */
21
35
  .header {
22
- background: #1a1f2e;
23
- padding: 1rem 2rem;
24
- border-bottom: 1px solid #2a2f3e;
36
+ background: var(--bg-secondary);
37
+ border-bottom: 1px solid var(--border-color);
38
+ padding: 0.75rem 1.5rem;
39
+ display: flex;
40
+ justify-content: space-between;
41
+ align-items: center;
42
+ height: 56px;
43
+ z-index: 100;
25
44
  }
26
-
27
45
  .header h1 {
28
- color: #4f96ff;
29
- font-size: 1.5rem;
46
+ font-size: 1.35rem;
30
47
  font-weight: 600;
48
+ display: flex;
49
+ align-items: center;
50
+ gap: 0.5rem;
31
51
  }
32
-
33
- .header .subtitle {
34
- color: #9ca3af;
35
- font-size: 0.9rem;
36
- margin-top: 0.25rem;
52
+ .header h1 span { color: var(--accent-primary); }
53
+ .header-right {
54
+ display: flex;
55
+ align-items: center;
56
+ gap: 1rem;
57
+ }
58
+ .connection-status {
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 0.5rem;
62
+ font-size: 0.8rem;
63
+ color: var(--text-secondary);
64
+ }
65
+ .status-dot {
66
+ width: 8px;
67
+ height: 8px;
68
+ border-radius: 50%;
69
+ background: var(--accent-error);
70
+ transition: background 0.3s;
71
+ }
72
+ .status-dot.connected {
73
+ background: var(--accent-success);
74
+ animation: pulse 2s infinite;
75
+ }
76
+ @keyframes pulse {
77
+ 0%, 100% { opacity: 1; }
78
+ 50% { opacity: 0.5; }
37
79
  }
38
80
 
39
- .main {
40
- display: grid;
41
- grid-template-columns: 1fr 2fr;
42
- height: calc(100vh - 80px);
81
+ /* Layout */
82
+ .container {
83
+ display: flex;
84
+ height: calc(100vh - 56px);
43
85
  }
44
86
 
87
+ /* Sidebar */
45
88
  .sidebar {
46
- background: #1a1f2e;
47
- border-right: 1px solid #2a2f3e;
48
- padding: 1rem;
49
- overflow-y: auto;
89
+ width: 280px;
90
+ min-width: 280px;
91
+ background: var(--bg-secondary);
92
+ border-right: 1px solid var(--border-color);
93
+ display: flex;
94
+ flex-direction: column;
95
+ overflow: hidden;
50
96
  }
51
-
52
- .content {
53
- padding: 1rem;
54
- overflow-y: auto;
97
+ .sidebar-header {
98
+ padding: 0.75rem 1rem;
99
+ border-bottom: 1px solid var(--border-color);
100
+ }
101
+ .sidebar-header h3 {
102
+ font-size: 0.75rem;
103
+ text-transform: uppercase;
104
+ letter-spacing: 0.5px;
105
+ color: var(--text-secondary);
106
+ margin-bottom: 0.5rem;
107
+ }
108
+ .search-box {
109
+ position: relative;
110
+ }
111
+ .search-box input {
112
+ width: 100%;
113
+ padding: 0.5rem 0.75rem;
114
+ padding-left: 2rem;
115
+ background: var(--bg-tertiary);
116
+ border: 1px solid var(--border-color);
117
+ border-radius: 6px;
118
+ color: var(--text-primary);
119
+ font-size: 0.8rem;
120
+ outline: none;
121
+ }
122
+ .search-box input:focus {
123
+ border-color: var(--accent-primary);
124
+ }
125
+ .search-box::before {
126
+ content: "\1F50D";
127
+ position: absolute;
128
+ left: 0.5rem;
129
+ top: 50%;
130
+ transform: translateY(-50%);
131
+ font-size: 0.75rem;
132
+ opacity: 0.5;
55
133
  }
56
134
 
57
- .stats-grid {
58
- display: grid;
59
- grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
60
- gap: 1rem;
61
- margin-bottom: 2rem;
135
+ /* Sidebar filters */
136
+ .sidebar-filters {
137
+ padding: 0.5rem 1rem;
138
+ border-bottom: 1px solid var(--border-color);
139
+ display: flex;
140
+ flex-direction: column;
141
+ gap: 0.5rem;
142
+ }
143
+ .filter-row {
144
+ display: flex;
145
+ gap: 0.5rem;
146
+ }
147
+ .filter-group {
148
+ flex: 1;
149
+ }
150
+ .filter-group label {
151
+ display: block;
152
+ font-size: 0.65rem;
153
+ color: var(--text-secondary);
154
+ margin-bottom: 0.15rem;
155
+ text-transform: uppercase;
156
+ letter-spacing: 0.5px;
157
+ }
158
+ .filter-group select {
159
+ width: 100%;
160
+ padding: 0.25rem 0.4rem;
161
+ background: var(--bg-tertiary);
162
+ border: 1px solid var(--border-color);
163
+ border-radius: 4px;
164
+ color: var(--text-primary);
165
+ font-size: 0.75rem;
166
+ outline: none;
167
+ }
168
+ .filter-group select:focus {
169
+ border-color: var(--accent-primary);
62
170
  }
63
171
 
64
- .stat-card {
65
- background: #1a1f2e;
66
- border: 1px solid #2a2f3e;
67
- border-radius: 8px;
68
- padding: 1rem;
172
+ /* Trace list */
173
+ .trace-list {
174
+ flex: 1;
175
+ overflow-y: auto;
176
+ padding: 0.25rem 0;
69
177
  }
178
+ .trace-list::-webkit-scrollbar { width: 6px; }
179
+ .trace-list::-webkit-scrollbar-track { background: transparent; }
180
+ .trace-list::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
70
181
 
71
- .stat-card h3 {
182
+ .session-item {
183
+ padding: 0.6rem 1rem;
184
+ cursor: pointer;
185
+ border-left: 3px solid transparent;
186
+ border-bottom: 1px solid rgba(48, 54, 61, 0.5);
187
+ transition: all 0.15s;
188
+ }
189
+ .session-item:hover {
190
+ background: var(--bg-tertiary);
191
+ }
192
+ .session-item.active {
193
+ background: var(--bg-tertiary);
194
+ border-left-color: var(--accent-primary);
195
+ }
196
+ .session-id {
72
197
  font-size: 0.8rem;
73
- color: #9ca3af;
74
- text-transform: uppercase;
75
- margin-bottom: 0.5rem;
198
+ font-weight: 500;
199
+ white-space: nowrap;
200
+ overflow: hidden;
201
+ text-overflow: ellipsis;
202
+ margin-bottom: 0.2rem;
203
+ }
204
+ .session-meta {
205
+ display: flex;
206
+ justify-content: space-between;
207
+ align-items: center;
208
+ font-size: 0.7rem;
209
+ color: var(--text-secondary);
210
+ gap: 0.5rem;
211
+ }
212
+ .session-agent {
213
+ color: var(--accent-primary);
214
+ white-space: nowrap;
215
+ overflow: hidden;
216
+ text-overflow: ellipsis;
76
217
  }
77
218
 
78
- .stat-card .value {
79
- font-size: 1.8rem;
80
- font-weight: 700;
81
- color: #4f96ff;
219
+ .badge {
220
+ display: inline-flex;
221
+ align-items: center;
222
+ padding: 0.1rem 0.45rem;
223
+ border-radius: 12px;
224
+ font-size: 0.65rem;
225
+ font-weight: 500;
226
+ flex-shrink: 0;
227
+ }
228
+ .badge-success {
229
+ background: rgba(35, 134, 54, 0.2);
230
+ color: #3fb950;
231
+ }
232
+ .badge-error {
233
+ background: rgba(218, 54, 51, 0.2);
234
+ color: #f85149;
235
+ }
236
+ .badge-running {
237
+ background: rgba(88, 166, 255, 0.2);
238
+ color: var(--accent-primary);
239
+ }
240
+ .badge-unknown {
241
+ background: rgba(139, 148, 158, 0.2);
242
+ color: var(--text-secondary);
82
243
  }
83
244
 
84
- .agent-list {
85
- margin-bottom: 2rem;
245
+ /* Node type badges */
246
+ .badge-type {
247
+ font-size: 0.6rem;
248
+ padding: 0.05rem 0.35rem;
249
+ border-radius: 8px;
250
+ font-weight: 600;
251
+ letter-spacing: 0.02em;
252
+ }
253
+ .badge-agent {
254
+ background: rgba(88, 166, 255, 0.15);
255
+ color: #79b8ff;
256
+ }
257
+ .badge-tool {
258
+ background: rgba(240, 136, 62, 0.15);
259
+ color: #f0883e;
260
+ }
261
+ .badge-subagent {
262
+ background: rgba(188, 140, 255, 0.15);
263
+ color: #bc8cff;
264
+ }
265
+ .badge-other, .badge-custom, .badge-wait, .badge-decision, .badge-exec {
266
+ background: rgba(139, 148, 158, 0.15);
267
+ color: #8b949e;
268
+ }
269
+ .badge-unknown {
270
+ background: rgba(139, 148, 158, 0.1);
271
+ color: #6e7681;
86
272
  }
87
273
 
88
- .agent-item {
89
- background: #262b3d;
90
- border: 1px solid #363b4d;
91
- border-radius: 6px;
92
- padding: 1rem;
93
- margin-bottom: 0.5rem;
94
- cursor: pointer;
95
- transition: all 0.2s;
274
+ .trace-count-badge {
275
+ padding: 0.5rem 1rem;
276
+ font-size: 0.75rem;
277
+ color: var(--text-secondary);
278
+ border-top: 1px solid var(--border-color);
279
+ background: var(--bg-secondary);
280
+ text-align: center;
96
281
  }
97
282
 
98
- .agent-item:hover {
99
- border-color: #4f96ff;
100
- background: #2a2f3e;
283
+ /* Main content */
284
+ .main-content {
285
+ flex: 1;
286
+ display: flex;
287
+ flex-direction: column;
288
+ overflow: hidden;
289
+ min-width: 0;
101
290
  }
102
291
 
103
- .agent-item.active {
104
- border-color: #4f96ff;
105
- background: #2a2f3e;
292
+ /* Stats overview */
293
+ .stats-overview {
294
+ display: grid;
295
+ grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
296
+ gap: 0.75rem;
297
+ padding: 0.75rem 1rem;
298
+ border-bottom: 1px solid var(--border-color);
299
+ background: var(--bg-secondary);
300
+ }
301
+ .stat-card-mini {
302
+ padding: 0.4rem 0.6rem;
106
303
  }
304
+ .stat-card-mini .metric-label { font-size: 0.65rem; margin-bottom: 0.15rem; }
305
+ .stat-card-mini .metric-value { font-size: 1.2rem; }
107
306
 
108
- .agent-name {
109
- font-weight: 600;
110
- color: #e6e6e6;
111
- margin-bottom: 0.25rem;
307
+ /* Tabs */
308
+ .tabs {
309
+ display: flex;
310
+ background: var(--bg-secondary);
311
+ border-bottom: 1px solid var(--border-color);
312
+ padding: 0 1rem;
313
+ gap: 0;
314
+ overflow-x: auto;
315
+ }
316
+ .tab {
317
+ padding: 0.7rem 1rem;
318
+ font-size: 0.8rem;
319
+ color: var(--text-secondary);
320
+ cursor: pointer;
321
+ border-bottom: 2px solid transparent;
322
+ transition: all 0.15s;
323
+ white-space: nowrap;
324
+ user-select: none;
325
+ }
326
+ .tab:hover { color: var(--text-primary); }
327
+ .tab.active {
328
+ color: var(--accent-primary);
329
+ border-bottom-color: var(--accent-primary);
112
330
  }
113
331
 
114
- .agent-stats {
332
+ /* Toolbar */
333
+ .toolbar {
115
334
  display: flex;
116
335
  justify-content: space-between;
336
+ align-items: center;
337
+ padding: 0.5rem 1rem;
338
+ background: var(--bg-secondary);
339
+ border-bottom: 1px solid var(--border-color);
340
+ min-height: 40px;
341
+ }
342
+ .toolbar-group {
343
+ display: flex;
344
+ gap: 0.5rem;
345
+ align-items: center;
346
+ }
347
+ .toolbar-info {
348
+ font-size: 0.75rem;
349
+ color: var(--text-secondary);
350
+ }
351
+ .btn {
352
+ padding: 0.3rem 0.7rem;
353
+ border-radius: 6px;
117
354
  font-size: 0.8rem;
118
- color: #9ca3af;
355
+ cursor: pointer;
356
+ border: 1px solid var(--border-color);
357
+ background: var(--bg-tertiary);
358
+ color: var(--text-primary);
359
+ transition: all 0.15s;
360
+ white-space: nowrap;
119
361
  }
120
-
121
- .success-rate {
122
- color: #10b981;
362
+ .btn:hover {
363
+ border-color: var(--accent-primary);
364
+ background: rgba(88, 166, 255, 0.1);
365
+ }
366
+ .btn-primary {
367
+ background: var(--accent-primary);
368
+ color: #fff;
369
+ border-color: var(--accent-primary);
370
+ }
371
+ .btn-primary:hover { background: #79b8ff; }
372
+ .btn-icon {
373
+ padding: 0.3rem;
123
374
  }
124
375
 
125
- .success-rate.low {
126
- color: #f59e0b;
376
+ .live-indicator {
377
+ display: flex;
378
+ align-items: center;
379
+ gap: 0.4rem;
380
+ font-size: 0.8rem;
381
+ color: var(--text-secondary);
382
+ }
383
+ .live-indicator.active {
384
+ color: var(--accent-error);
385
+ }
386
+ .live-indicator .live-dot {
387
+ font-size: 0.7rem;
127
388
  }
128
389
 
129
- .success-rate.critical {
130
- color: #ef4444;
390
+ /* Alert Panel */
391
+ .alert-panel {
392
+ background: rgba(218, 54, 51, 0.1);
393
+ border: 1px solid var(--accent-error);
394
+ border-radius: 0;
395
+ padding: 0.75rem 1rem;
396
+ display: none;
397
+ font-size: 0.8rem;
398
+ }
399
+ .alert-panel.show {
400
+ display: block;
401
+ }
402
+ .alert-panel ul {
403
+ margin: 0.3rem 0 0 1.2rem;
404
+ font-size: 0.75rem;
131
405
  }
132
406
 
133
- .traces-section {
134
- margin-bottom: 2rem;
407
+ /* Content area */
408
+ .content-area {
409
+ flex: 1;
410
+ overflow: auto;
411
+ position: relative;
412
+ }
413
+ .tab-panel {
414
+ display: none;
415
+ height: 100%;
416
+ }
417
+ .tab-panel.active {
418
+ display: flex;
419
+ flex-direction: column;
135
420
  }
136
421
 
137
- .section-title {
138
- font-size: 1.2rem;
139
- font-weight: 600;
140
- margin-bottom: 1rem;
141
- color: #e6e6e6;
422
+ /* Graph */
423
+ #cy {
424
+ flex: 1;
425
+ min-height: 0;
426
+ background: var(--bg-primary);
142
427
  }
143
428
 
144
- .trace-item {
145
- background: #1a1f2e;
146
- border: 1px solid #2a2f3e;
147
- border-radius: 6px;
148
- padding: 1rem;
149
- margin-bottom: 0.75rem;
429
+ /* Empty / placeholder states */
430
+ .empty-state {
431
+ display: flex;
432
+ flex-direction: column;
433
+ align-items: center;
434
+ justify-content: center;
435
+ height: 100%;
436
+ color: var(--text-secondary);
437
+ gap: 0.75rem;
438
+ padding: 2rem;
439
+ }
440
+ .empty-state-icon {
441
+ font-size: 2.5rem;
442
+ opacity: 0.4;
443
+ }
444
+ .empty-state-title {
445
+ font-size: 1.1rem;
446
+ font-weight: 500;
447
+ color: var(--text-primary);
448
+ }
449
+ .empty-state-text {
450
+ font-size: 0.85rem;
451
+ text-align: center;
452
+ max-width: 360px;
150
453
  }
151
454
 
152
- .trace-header {
455
+ /* Node detail panel */
456
+ .node-detail-panel {
457
+ position: absolute;
458
+ top: 1rem;
459
+ right: 1rem;
460
+ width: 320px;
461
+ background: var(--bg-secondary);
462
+ border: 1px solid var(--border-color);
463
+ border-radius: 8px;
464
+ z-index: 50;
465
+ display: none;
466
+ box-shadow: 0 8px 32px rgba(0,0,0,0.4);
467
+ max-height: calc(100% - 2rem);
468
+ overflow-y: auto;
469
+ }
470
+ .node-detail-panel.active { display: block; }
471
+ .node-detail-header {
153
472
  display: flex;
154
473
  justify-content: space-between;
155
474
  align-items: center;
156
- margin-bottom: 0.5rem;
475
+ padding: 0.75rem 1rem;
476
+ border-bottom: 1px solid var(--border-color);
157
477
  }
158
-
159
- .trace-name {
160
- font-weight: 600;
161
- color: #e6e6e6;
478
+ .node-detail-header h4 { font-size: 0.9rem; }
479
+ .node-detail-close {
480
+ background: none;
481
+ border: none;
482
+ color: var(--text-secondary);
483
+ cursor: pointer;
484
+ font-size: 1.2rem;
485
+ padding: 0.25rem;
486
+ line-height: 1;
162
487
  }
163
-
164
- .trace-timestamp {
488
+ .node-detail-close:hover { color: var(--text-primary); }
489
+ .node-detail-body { padding: 0.75rem 1rem; }
490
+ .detail-row {
491
+ display: flex;
492
+ justify-content: space-between;
493
+ align-items: flex-start;
494
+ padding: 0.4rem 0;
495
+ border-bottom: 1px solid rgba(48, 54, 61, 0.4);
165
496
  font-size: 0.8rem;
166
- color: #9ca3af;
167
497
  }
498
+ .detail-row:last-child { border-bottom: none; }
499
+ .detail-label { color: var(--text-secondary); min-width: 80px; }
500
+ .detail-value {
501
+ color: var(--text-primary);
502
+ text-align: right;
503
+ word-break: break-all;
504
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
505
+ font-size: 0.75rem;
506
+ }
507
+ .detail-value.status-completed { color: var(--accent-success); }
508
+ .detail-value.status-failed { color: var(--accent-error); }
509
+ .detail-value.status-running { color: var(--accent-primary); }
510
+ .detail-value.status-hung { color: var(--accent-warning); }
511
+ .detail-value.status-timeout { color: var(--accent-warning); }
512
+ .detail-metadata {
513
+ margin-top: 0.5rem;
514
+ padding: 0.5rem;
515
+ background: var(--bg-tertiary);
516
+ border-radius: 4px;
517
+ font-size: 0.7rem;
518
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
519
+ color: var(--text-secondary);
520
+ max-height: 200px;
521
+ overflow-y: auto;
522
+ white-space: pre-wrap;
523
+ word-break: break-all;
524
+ }
525
+
526
+ /* Timeline view */
527
+ .timeline-container {
528
+ padding: 1rem;
529
+ overflow-y: auto;
530
+ flex: 1;
531
+ }
532
+ .timeline-item {
533
+ display: flex;
534
+ margin-bottom: 0.75rem;
535
+ padding: 0.75rem 1rem;
536
+ background: var(--bg-secondary);
537
+ border: 1px solid var(--border-color);
538
+ border-radius: 8px;
539
+ transition: all 0.2s;
540
+ }
541
+ .timeline-item:hover {
542
+ border-color: var(--accent-primary);
543
+ }
544
+ .timeline-marker {
545
+ width: 12px;
546
+ height: 12px;
547
+ border-radius: 50%;
548
+ margin-right: 1rem;
549
+ flex-shrink: 0;
550
+ margin-top: 0.2rem;
551
+ }
552
+ .timeline-marker.agent { background: var(--accent-primary); }
553
+ .timeline-marker.tool { background: var(--accent-warning); }
554
+ .timeline-marker.subagent { background: #a371f7; }
555
+ .timeline-marker.completed { background: var(--accent-success); }
556
+ .timeline-marker.failed { background: var(--accent-error); }
557
+ .timeline-marker.running { background: var(--accent-primary); }
558
+ .timeline-marker.hung, .timeline-marker.timeout { background: var(--accent-warning); }
168
559
 
169
- .trace-details {
560
+ .timeline-content {
561
+ flex: 1;
562
+ min-width: 0;
563
+ }
564
+ .timeline-header {
170
565
  display: flex;
171
566
  justify-content: space-between;
567
+ margin-bottom: 0.35rem;
568
+ }
569
+ .event-type {
570
+ font-weight: 500;
571
+ font-size: 0.85rem;
572
+ }
573
+ .event-time {
574
+ font-size: 0.7rem;
575
+ color: var(--text-secondary);
576
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
577
+ }
578
+ .event-details {
172
579
  font-size: 0.8rem;
580
+ color: var(--text-secondary);
173
581
  }
174
-
175
- .trace-agent {
176
- color: #4f96ff;
582
+ .event-duration {
583
+ display: inline-block;
584
+ margin-top: 0.25rem;
585
+ font-size: 0.7rem;
586
+ padding: 0.1rem 0.4rem;
587
+ background: var(--bg-tertiary);
588
+ border-radius: 4px;
589
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
590
+ color: var(--text-secondary);
177
591
  }
178
592
 
179
- .trace-trigger {
180
- color: #9ca3af;
593
+ /* Metrics view */
594
+ .metrics-container {
595
+ padding: 1rem;
596
+ overflow-y: auto;
597
+ flex: 1;
598
+ }
599
+ .metrics-grid {
600
+ display: grid;
601
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
602
+ gap: 1rem;
603
+ margin-bottom: 1.5rem;
604
+ }
605
+ .metric-card {
606
+ background: var(--bg-secondary);
607
+ border: 1px solid var(--border-color);
608
+ border-radius: 8px;
609
+ padding: 1rem 1.25rem;
610
+ }
611
+ .metric-label {
612
+ font-size: 0.7rem;
613
+ text-transform: uppercase;
614
+ letter-spacing: 0.5px;
615
+ color: var(--text-secondary);
616
+ margin-bottom: 0.4rem;
617
+ }
618
+ .metric-value {
619
+ font-size: 1.75rem;
620
+ font-weight: 700;
621
+ }
622
+ .metric-value.primary { color: var(--accent-primary); }
623
+ .metric-value.success { color: var(--accent-success); }
624
+ .metric-value.error { color: var(--accent-error); }
625
+ .metric-value.warning { color: var(--accent-warning); }
626
+ .metric-sub {
627
+ font-size: 0.7rem;
628
+ color: var(--text-secondary);
629
+ margin-top: 0.2rem;
181
630
  }
182
631
 
183
- .status-indicator {
632
+ /* Process health */
633
+ .process-health-section {
634
+ padding: 0.75rem 1rem;
635
+ border-bottom: 1px solid var(--border-color);
636
+ background: var(--bg-secondary);
637
+ }
638
+ .process-health-section h4 {
639
+ font-size: 0.7rem;
640
+ text-transform: uppercase;
641
+ letter-spacing: 0.05em;
642
+ color: var(--text-secondary);
643
+ margin-bottom: 0.5rem;
644
+ }
645
+ .ph-row {
646
+ display: flex;
647
+ align-items: center;
648
+ gap: 0.75rem;
649
+ margin-bottom: 0.35rem;
650
+ font-size: 0.75rem;
651
+ }
652
+ .ph-label {
653
+ color: var(--text-secondary);
654
+ min-width: 70px;
655
+ }
656
+ .ph-value {
657
+ color: var(--text-primary);
658
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
659
+ font-size: 0.75rem;
660
+ }
661
+ .ph-value.ok { color: var(--accent-success); }
662
+ .ph-value.warn { color: var(--accent-warning); }
663
+ .ph-value.bad { color: var(--accent-error); }
664
+ .worker-dots { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; }
665
+ .worker-dot {
184
666
  width: 8px;
185
667
  height: 8px;
186
668
  border-radius: 50%;
187
- display: inline-block;
188
- margin-right: 0.5rem;
189
669
  }
190
-
191
- .status-success {
192
- background: #10b981;
670
+ .worker-dot.alive { background: var(--accent-success); }
671
+ .worker-dot.stale { background: var(--accent-error); }
672
+ .worker-dot.unknown { background: var(--text-secondary); }
673
+ .worker-dot-label { font-size: 0.65rem; color: var(--text-secondary); margin-left: 1px; }
674
+ .orphan-table {
675
+ width: 100%;
676
+ border-collapse: collapse;
677
+ font-size: 0.7rem;
678
+ font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
679
+ margin-top: 0.5rem;
680
+ }
681
+ .orphan-table th {
682
+ text-align: left;
683
+ color: var(--text-secondary);
684
+ font-weight: 500;
685
+ padding: 0.3rem 0.5rem;
686
+ border-bottom: 1px solid var(--border-color);
687
+ }
688
+ .orphan-table td {
689
+ padding: 0.25rem 0.5rem;
690
+ color: var(--text-primary);
691
+ border-bottom: 1px solid rgba(48,54,61,0.4);
692
+ white-space: nowrap;
693
+ overflow: hidden;
694
+ text-overflow: ellipsis;
695
+ max-width: 250px;
696
+ }
697
+ .orphan-table tr:hover td { background: var(--bg-tertiary); }
698
+ .problems-list {
699
+ list-style: none;
700
+ padding: 0;
701
+ margin: 0.3rem 0 0 0;
702
+ }
703
+ .problems-list li {
704
+ font-size: 0.7rem;
705
+ color: var(--accent-error);
706
+ padding: 0.15rem 0;
707
+ }
708
+ .problems-list li::before {
709
+ content: "\2022";
710
+ margin-right: 0.4rem;
193
711
  }
194
712
 
195
- .status-failure {
196
- background: #ef4444;
713
+ /* Error Heatmap */
714
+ .heatmap-container {
715
+ padding: 1rem;
716
+ overflow-y: auto;
717
+ flex: 1;
718
+ }
719
+ .heatmap-header {
720
+ font-size: 0.9rem;
721
+ margin-bottom: 1rem;
722
+ color: var(--text-primary);
723
+ }
724
+ .heatmap-grid {
725
+ display: grid;
726
+ grid-template-columns: repeat(10, 1fr);
727
+ gap: 4px;
728
+ margin-bottom: 1rem;
729
+ }
730
+ .heatmap-cell {
731
+ aspect-ratio: 1;
732
+ border-radius: 4px;
733
+ cursor: pointer;
734
+ transition: transform 0.2s;
735
+ display: flex;
736
+ align-items: center;
737
+ justify-content: center;
738
+ font-size: 0.65rem;
739
+ font-weight: 600;
740
+ color: rgba(255,255,255,0.7);
741
+ position: relative;
742
+ }
743
+ .heatmap-cell:hover {
744
+ transform: scale(1.15);
745
+ z-index: 2;
746
+ }
747
+ .heatmap-tooltip {
748
+ position: absolute;
749
+ bottom: calc(100% + 6px);
750
+ left: 50%;
751
+ transform: translateX(-50%);
752
+ background: var(--bg-secondary);
753
+ border: 1px solid var(--border-color);
754
+ border-radius: 4px;
755
+ padding: 0.4rem 0.6rem;
756
+ font-size: 0.7rem;
757
+ white-space: nowrap;
758
+ display: none;
759
+ z-index: 100;
760
+ color: var(--text-primary);
761
+ box-shadow: 0 4px 12px rgba(0,0,0,0.4);
762
+ }
763
+ .heatmap-cell:hover .heatmap-tooltip {
764
+ display: block;
197
765
  }
198
766
 
199
- .status-unknown {
200
- background: #6b7280;
767
+ /* State Machine */
768
+ .state-machine-container {
769
+ padding: 1rem;
770
+ overflow-y: auto;
771
+ flex: 1;
772
+ }
773
+ .state-machine {
774
+ display: flex;
775
+ justify-content: center;
776
+ align-items: center;
777
+ gap: 1.5rem;
778
+ padding: 2rem;
779
+ flex-wrap: wrap;
780
+ }
781
+ .state {
782
+ display: flex;
783
+ flex-direction: column;
784
+ align-items: center;
785
+ gap: 0.5rem;
786
+ }
787
+ .state-circle {
788
+ width: 80px;
789
+ height: 80px;
790
+ border-radius: 50%;
791
+ display: flex;
792
+ flex-direction: column;
793
+ align-items: center;
794
+ justify-content: center;
795
+ font-size: 0.65rem;
796
+ font-weight: 600;
797
+ border: 3px solid var(--border-color);
798
+ transition: all 0.3s;
799
+ }
800
+ .state-circle .state-count {
801
+ font-size: 1.2rem;
802
+ font-weight: 700;
803
+ margin-bottom: 0.1rem;
804
+ }
805
+ .state-circle.pending {
806
+ border-color: var(--text-secondary);
807
+ background: rgba(139, 148, 158, 0.1);
808
+ }
809
+ .state-circle.running {
810
+ border-color: var(--accent-primary);
811
+ background: rgba(88, 166, 255, 0.1);
812
+ animation: glow 2s infinite;
813
+ }
814
+ .state-circle.completed {
815
+ border-color: var(--accent-success);
816
+ background: rgba(35, 134, 54, 0.1);
817
+ }
818
+ .state-circle.failed {
819
+ border-color: var(--accent-error);
820
+ background: rgba(218, 54, 51, 0.1);
821
+ }
822
+ @keyframes glow {
823
+ 0%, 100% { box-shadow: 0 0 5px var(--accent-primary); }
824
+ 50% { box-shadow: 0 0 20px var(--accent-primary); }
825
+ }
826
+ .state-label {
827
+ font-size: 0.75rem;
828
+ color: var(--text-secondary);
829
+ }
830
+ .state-arrow {
831
+ font-size: 1.5rem;
832
+ color: var(--text-secondary);
201
833
  }
202
834
 
203
- .connection-status {
204
- position: fixed;
205
- top: 1rem;
206
- right: 1rem;
207
- padding: 0.5rem 1rem;
835
+ /* Summary View */
836
+ .summary-container {
837
+ padding: 1rem;
838
+ overflow-y: auto;
839
+ flex: 1;
840
+ }
841
+ .summary-card {
842
+ background: var(--bg-secondary);
843
+ border: 1px solid var(--border-color);
844
+ border-radius: 8px;
845
+ padding: 1.5rem;
846
+ margin-bottom: 1rem;
847
+ }
848
+ .summary-title {
849
+ font-size: 1.1rem;
850
+ margin-bottom: 0.75rem;
851
+ padding-bottom: 0.5rem;
852
+ border-bottom: 1px solid var(--border-color);
853
+ }
854
+ .summary-text {
855
+ font-size: 0.85rem;
856
+ line-height: 1.6;
857
+ color: var(--text-secondary);
858
+ margin-bottom: 0.75rem;
859
+ }
860
+ .summary-details {
861
+ list-style: none;
862
+ padding: 0;
863
+ margin: 0 0 1rem 0;
864
+ }
865
+ .summary-details li {
866
+ font-size: 0.8rem;
867
+ padding: 0.25rem 0;
868
+ color: var(--text-secondary);
869
+ }
870
+ .summary-details li::before {
871
+ content: "\2022";
872
+ margin-right: 0.5rem;
873
+ color: var(--accent-primary);
874
+ }
875
+ .summary-recommendations {
876
+ margin-top: 0.75rem;
877
+ padding: 0.75rem;
878
+ background: var(--bg-tertiary);
208
879
  border-radius: 6px;
209
880
  font-size: 0.8rem;
210
- font-weight: 600;
881
+ color: var(--text-secondary);
211
882
  }
212
-
213
- .connected {
214
- background: #065f46;
215
- color: #10b981;
883
+ .summary-recommendations strong {
884
+ color: var(--text-primary);
216
885
  }
217
-
218
- .disconnected {
219
- background: #7f1d1d;
220
- color: #ef4444;
886
+ .confidence-bar {
887
+ display: flex;
888
+ align-items: center;
889
+ gap: 0.75rem;
890
+ margin-top: 1rem;
891
+ font-size: 0.8rem;
892
+ }
893
+ .bar {
894
+ flex: 1;
895
+ height: 8px;
896
+ background: var(--bg-tertiary);
897
+ border-radius: 4px;
898
+ overflow: hidden;
899
+ }
900
+ .bar-fill {
901
+ height: 100%;
902
+ background: linear-gradient(90deg, var(--accent-error), var(--accent-warning), var(--accent-success));
903
+ transition: width 0.3s;
221
904
  }
222
905
 
223
- .loading {
224
- text-align: center;
225
- padding: 2rem;
226
- color: #9ca3af;
906
+ /* Loading spinner */
907
+ .spinner {
908
+ width: 20px;
909
+ height: 20px;
910
+ border: 2px solid var(--border-color);
911
+ border-top-color: var(--accent-primary);
912
+ border-radius: 50%;
913
+ animation: spin 0.8s linear infinite;
914
+ margin: 0 auto;
227
915
  }
916
+ @keyframes spin { to { transform: rotate(360deg); } }
228
917
 
229
- @media (max-width: 768px) {
230
- .main {
231
- grid-template-columns: 1fr;
232
- }
918
+ /* Scrollbars */
919
+ ::-webkit-scrollbar { width: 6px; height: 6px; }
920
+ ::-webkit-scrollbar-track { background: transparent; }
921
+ ::-webkit-scrollbar-thumb { background: var(--border-color); border-radius: 3px; }
922
+ ::-webkit-scrollbar-thumb:hover { background: var(--text-secondary); }
233
923
 
234
- .sidebar {
235
- display: none;
236
- }
924
+ /* Chat bubbles for transcript */
925
+ .chat-bubble { max-width: 80%; padding: 0.75rem 1rem; border-radius: 12px; margin-bottom: 0.5rem; font-size: 0.85rem; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
926
+ .chat-user { margin-left: auto; background: rgba(88,166,255,0.15); border: 1px solid rgba(88,166,255,0.3); }
927
+ .chat-assistant { margin-right: auto; background: var(--bg-secondary); border: 1px solid var(--border-color); }
928
+ .chat-tool { margin: 0 auto; max-width: 90%; background: rgba(240,136,62,0.1); border: 1px solid rgba(240,136,62,0.3); font-family: monospace; font-size: 0.8rem; }
929
+ .chat-thinking { margin-right: auto; background: rgba(188,140,255,0.08); border: 1px solid rgba(188,140,255,0.2); font-style: italic; color: var(--text-secondary); }
930
+ .chat-meta { font-size: 0.7rem; color: var(--text-secondary); margin-top: 4px; }
931
+ .chat-tokens { font-size: 0.65rem; color: #bc8cff; }
932
+ .chat-thinking-toggle { cursor: pointer; user-select: none; font-size: 0.75rem; color: #bc8cff; }
933
+ .chat-thinking-body { display: none; margin-top: 0.5rem; }
934
+ .chat-thinking-body.open { display: block; }
935
+
936
+ /* Responsive */
937
+ @media (max-width: 900px) {
938
+ .sidebar { width: 240px; min-width: 240px; }
939
+ }
940
+ @media (max-width: 768px) {
941
+ .container { flex-direction: column; }
942
+ .sidebar { width: 100%; min-width: 100%; max-height: 200px; }
943
+ .state-machine { gap: 0.75rem; }
944
+ .state-circle { width: 60px; height: 60px; font-size: 0.6rem; }
237
945
  }
238
946
  </style>
239
947
  </head>
240
948
  <body>
241
- <div class="header">
242
- <h1>AgentFlow Dashboard</h1>
243
- <div class="subtitle">Real-time monitoring for AI agent executions</div>
244
- </div>
949
+ <header class="header">
950
+ <h1><span>AgentFlow</span> Dashboard <span style="font-size:0.6rem;color:var(--text-secondary);font-weight:400;margin-left:8px;">v0.2.3</span></h1>
951
+ <div class="header-right">
952
+ <div class="connection-status">
953
+ <span class="status-dot" id="connectionDot"></span>
954
+ <span id="connectionText">Connecting...</span>
955
+ </div>
956
+ </div>
957
+ </header>
245
958
 
246
- <div class="connection-status disconnected" id="connectionStatus">
247
- Connecting...
248
- </div>
959
+ <div class="container">
960
+ <aside class="sidebar">
961
+ <div class="sidebar-header">
962
+ <h3>Traces</h3>
963
+ <div class="search-box">
964
+ <input type="text" id="traceSearch" placeholder="Filter by name or agent ID...">
965
+ </div>
966
+ </div>
967
+ <div class="sidebar-filters">
968
+ <div class="filter-row">
969
+ <div class="filter-group">
970
+ <label>Time Range</label>
971
+ <select id="timeRangeFilter">
972
+ <option value="all">All Time</option>
973
+ <option value="1h">Last Hour</option>
974
+ <option value="24h">Last 24 Hours</option>
975
+ <option value="7d">Last 7 Days</option>
976
+ </select>
977
+ </div>
978
+ <div class="filter-group">
979
+ <label>Status</label>
980
+ <select id="statusFilter">
981
+ <option value="all">All</option>
982
+ <option value="success">Completed</option>
983
+ <option value="failure">Failed</option>
984
+ <option value="running">Running</option>
985
+ </select>
986
+ </div>
987
+ </div>
988
+ </div>
989
+ <div class="trace-list" id="traceList"></div>
990
+ <div class="trace-count-badge" id="traceCount">0 traces</div>
991
+ </aside>
992
+
993
+ <main class="main-content">
994
+ <!-- Process Health (above metrics, not a tab) -->
995
+ <div class="process-health-section" id="processHealthSection" style="display:none;"></div>
249
996
 
250
- <div class="main">
251
- <div class="sidebar">
252
- <h3 class="section-title">Agents</h3>
253
- <div class="agent-list" id="agentList">
254
- <div class="loading">Loading agents...</div>
997
+ <div class="stats-overview" id="statsOverview">
998
+ <div class="stat-card-mini">
999
+ <div class="metric-label">Agents</div>
1000
+ <div class="metric-value primary" id="statAgents">--</div>
1001
+ </div>
1002
+ <div class="stat-card-mini">
1003
+ <div class="metric-label">Executions</div>
1004
+ <div class="metric-value primary" id="statExecutions">--</div>
1005
+ </div>
1006
+ <div class="stat-card-mini">
1007
+ <div class="metric-label">Success Rate</div>
1008
+ <div class="metric-value success" id="statSuccessRate">--</div>
1009
+ </div>
1010
+ <div class="stat-card-mini">
1011
+ <div class="metric-label">Active</div>
1012
+ <div class="metric-value warning" id="statActive">--</div>
1013
+ </div>
255
1014
  </div>
256
- </div>
257
1015
 
258
- <div class="content">
259
- <div class="stats-grid" id="statsGrid">
260
- <div class="loading">Loading statistics...</div>
1016
+ <div class="tabs">
1017
+ <div class="tab active" data-tab="timeline">Timeline</div>
1018
+ <div class="tab" data-tab="metrics">Metrics</div>
1019
+ <div class="tab" data-tab="graph">Dependency Graph</div>
1020
+ <div class="tab" data-tab="heatmap">Error Heatmap</div>
1021
+ <div class="tab" data-tab="state">State Machine</div>
1022
+ <div class="tab" data-tab="summary">Summary</div>
1023
+ <div class="tab" data-tab="transcript">Transcript</div>
261
1024
  </div>
262
1025
 
263
- <div class="traces-section">
264
- <h3 class="section-title">Recent Executions</h3>
265
- <div class="traces-list" id="tracesList">
266
- <div class="loading">Loading traces...</div>
1026
+ <div class="toolbar" id="toolbar">
1027
+ <div class="toolbar-group">
1028
+ <button class="btn btn-icon" id="btnPlayPause" title="Pause/Resume live tail">&#9208;</button>
1029
+ <div class="live-indicator" id="liveIndicator">
1030
+ <span class="live-dot">&#9679;</span> Live Tail
1031
+ </div>
1032
+ <span class="toolbar-info" id="toolbarInfo"></span>
1033
+ </div>
1034
+ <div class="toolbar-group">
1035
+ <button class="btn" id="btnRefresh" title="Refresh data">Refresh</button>
1036
+ <button class="btn" id="btnExportPng" title="Export graph as PNG">Export PNG</button>
1037
+ <button class="btn" id="btnFit" title="Fit graph to view">Fit</button>
1038
+ <button class="btn" id="btnLayout" title="Re-run layout">Layout</button>
267
1039
  </div>
268
1040
  </div>
269
- </div>
1041
+
1042
+ <div class="alert-panel" id="alertPanel">
1043
+ <strong>Alerts:</strong>
1044
+ <ul id="alertList"></ul>
1045
+ </div>
1046
+
1047
+ <div class="content-area">
1048
+ <!-- Timeline tab -->
1049
+ <div class="tab-panel active" id="panel-timeline">
1050
+ <div class="timeline-container" id="timelineContent">
1051
+ <div class="empty-state">
1052
+ <div class="empty-state-icon">&#9776;</div>
1053
+ <div class="empty-state-title">Select a trace</div>
1054
+ <div class="empty-state-text">Choose a trace from the sidebar to view its execution timeline.</div>
1055
+ </div>
1056
+ </div>
1057
+ </div>
1058
+
1059
+ <!-- Metrics tab -->
1060
+ <div class="tab-panel" id="panel-metrics">
1061
+ <div class="metrics-container" id="metricsContent">
1062
+ <div class="empty-state">
1063
+ <div class="empty-state-text">Select a trace to view metrics.</div>
1064
+ </div>
1065
+ </div>
1066
+ </div>
1067
+
1068
+ <!-- Dependency Graph tab -->
1069
+ <div class="tab-panel" id="panel-graph">
1070
+ <div id="cy">
1071
+ <div class="empty-state" id="graphEmpty">
1072
+ <div class="empty-state-icon">&#9651;</div>
1073
+ <div class="empty-state-title">Select a trace</div>
1074
+ <div class="empty-state-text">Choose a trace from the sidebar to view its dependency graph.</div>
1075
+ </div>
1076
+ </div>
1077
+ <div class="node-detail-panel" id="nodeDetailPanel">
1078
+ <div class="node-detail-header">
1079
+ <h4 id="nodeDetailTitle">Node Details</h4>
1080
+ <button class="node-detail-close" id="nodeDetailClose">&times;</button>
1081
+ </div>
1082
+ <div class="node-detail-body" id="nodeDetailBody"></div>
1083
+ </div>
1084
+ </div>
1085
+
1086
+ <!-- Error Heatmap tab -->
1087
+ <div class="tab-panel" id="panel-heatmap">
1088
+ <div class="heatmap-container" id="heatmapContent">
1089
+ <div class="empty-state">
1090
+ <div class="empty-state-text">Select a trace to view the error heatmap.</div>
1091
+ </div>
1092
+ </div>
1093
+ </div>
1094
+
1095
+ <!-- State Machine tab -->
1096
+ <div class="tab-panel" id="panel-state">
1097
+ <div class="state-machine-container" id="stateContent">
1098
+ <div class="empty-state">
1099
+ <div class="empty-state-text">Select a trace to view state machine.</div>
1100
+ </div>
1101
+ </div>
1102
+ </div>
1103
+
1104
+ <!-- Summary tab -->
1105
+ <div class="tab-panel" id="panel-summary">
1106
+ <div class="summary-container" id="summaryContent">
1107
+ <div class="empty-state">
1108
+ <div class="empty-state-text">Select a trace to view summary.</div>
1109
+ </div>
1110
+ </div>
1111
+ </div>
1112
+
1113
+ <!-- Transcript tab -->
1114
+ <div class="tab-panel" id="panel-transcript">
1115
+ <div class="timeline-container" id="transcriptContent">
1116
+ <div class="empty-state">
1117
+ <div class="empty-state-text">Select a session trace to view transcript.</div>
1118
+ </div>
1119
+ </div>
1120
+ </div>
1121
+ </div>
1122
+ </main>
270
1123
  </div>
271
1124
 
272
- <script src="dashboard.js"></script>
1125
+ <script src="dashboard.js?v=0.2.2"></script>
273
1126
  </body>
274
- </html>
1127
+ </html>