fluxflow-cli 4.16.2 → 4.16.3

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.
@@ -0,0 +1,1916 @@
1
+ import{n as v}from"./chunk-WKHYRBBK.js";import{c as f}from"./chunk-FDNLMLIM.js";import b from"http";import{exec as p}from"child_process";var g="data:image/png;base64,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";var m=null,n=null;function u(){let t=g;return`<!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>FluxFlow Token Usage & Analytics Dashboard</title>
7
+ ${t?`<link rel="icon" type="image/png" href="${t}">`:""}
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
11
+ <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"></script>
12
+ <style>
13
+ :root {
14
+ --bg-base: #07090e;
15
+ --bg-card: rgba(16, 22, 34, 0.75);
16
+ --bg-card-hover: rgba(22, 30, 48, 0.85);
17
+ --border-subtle: rgba(255, 255, 255, 0.08);
18
+ --border-glow: rgba(56, 189, 248, 0.25);
19
+ --text-main: #f1f5f9;
20
+ --text-muted: #94a3b8;
21
+ --text-dim: #64748b;
22
+ --accent-cyan: #38bdf8;
23
+ --accent-emerald: #10b981;
24
+ --accent-violet: #a855f7;
25
+ --accent-amber: #f59e0b;
26
+ --accent-rose: #f43f5e;
27
+ --accent-blue: #3b82f6;
28
+ --radius-lg: 16px;
29
+ --radius-md: 10px;
30
+ --radius-sm: 6px;
31
+ }
32
+
33
+ * {
34
+ box-sizing: border-box;
35
+ margin: 0;
36
+ padding: 0;
37
+ }
38
+
39
+ body {
40
+ background-color: var(--bg-base);
41
+ color: var(--text-main);
42
+ font-family: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, sans-serif;
43
+ min-height: 100vh;
44
+ overflow-x: hidden;
45
+ user-select: none;
46
+ -webkit-user-select: none;
47
+ background-image:
48
+ radial-gradient(circle at 15% 10%, rgba(56, 189, 248, 0.08) 0%, transparent 45%),
49
+ radial-gradient(circle at 85% 20%, rgba(168, 85, 247, 0.08) 0%, transparent 45%),
50
+ radial-gradient(circle at 50% 80%, rgba(16, 185, 129, 0.06) 0%, transparent 50%);
51
+ background-attachment: fixed;
52
+ }
53
+
54
+ input {
55
+ user-select: auto;
56
+ -webkit-user-select: auto;
57
+ }
58
+
59
+ .mono {
60
+ font-family: 'JetBrains Mono', monospace;
61
+ }
62
+
63
+ .glass-panel {
64
+ background: var(--bg-card);
65
+ backdrop-filter: blur(16px);
66
+ -webkit-backdrop-filter: blur(16px);
67
+ border: 1px solid var(--border-subtle);
68
+ border-radius: var(--radius-lg);
69
+ box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.37);
70
+ transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
71
+ }
72
+
73
+ .glass-panel:hover {
74
+ border-color: rgba(255, 255, 255, 0.14);
75
+ }
76
+
77
+ header {
78
+ position: sticky;
79
+ top: 0;
80
+ z-index: 100;
81
+ backdrop-filter: blur(24px);
82
+ background: rgba(7, 9, 14, 0.3);
83
+ border-bottom: 1px solid var(--border-subtle);
84
+ padding: 1rem 2rem;
85
+ display: flex;
86
+ justify-content: space-between;
87
+ align-items: center;
88
+ }
89
+
90
+ .brand-container {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 12px;
94
+ }
95
+
96
+ .brand-badge {
97
+ width: 40px;
98
+ height: 40px;
99
+ border-radius: 10px;
100
+ background: linear-gradient(135deg, #38bdf8 0%, #a855f7 100%);
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ font-weight: 800;
105
+ font-size: 1.2rem;
106
+ color: #fff;
107
+ box-shadow: 0 0 20px rgba(56, 189, 248, 0.4);
108
+ }
109
+
110
+ .brand-title {
111
+ font-size: clamp(1.1rem, 1.6vw, 1.4rem);
112
+ font-weight: 700;
113
+ letter-spacing: -0.02em;
114
+ background: linear-gradient(to right, #ffffff, #94a3b8);
115
+ -webkit-background-clip: text;
116
+ -webkit-text-fill-color: transparent;
117
+ }
118
+
119
+ .brand-subtitle {
120
+ font-size: clamp(0.7rem, 0.9vw, 0.8rem);
121
+ color: var(--text-dim);
122
+ font-weight: 500;
123
+ }
124
+
125
+ .header-actions {
126
+ display: flex;
127
+ align-items: center;
128
+ gap: 12px;
129
+ }
130
+
131
+ .status-pill {
132
+ display: flex;
133
+ align-items: center;
134
+ gap: 8px;
135
+ padding: 6px 14px;
136
+ border-radius: 9999px;
137
+ background: rgba(16, 185, 129, 0.1);
138
+ border: 1px solid rgba(16, 185, 129, 0.25);
139
+ color: #34d399;
140
+ font-size: clamp(0.75rem, 0.9vw, 0.825rem);
141
+ font-weight: 600;
142
+ }
143
+
144
+ .pulse-dot {
145
+ width: 8px;
146
+ height: 8px;
147
+ background-color: #10b981;
148
+ border-radius: 50%;
149
+ box-shadow: 0 0 8px #10b981;
150
+ animation: pulse-ring 2s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
151
+ }
152
+
153
+ @keyframes pulse-ring {
154
+ 0% { transform: scale(0.9); opacity: 0.8; }
155
+ 50% { transform: scale(1.3); opacity: 1; filter: drop-shadow(0 0 4px #10b981); }
156
+ 100% { transform: scale(0.9); opacity: 0.8; }
157
+ }
158
+
159
+ .btn {
160
+ background: rgba(255, 255, 255, 0.05);
161
+ border: 1px solid var(--border-subtle);
162
+ color: var(--text-main);
163
+ padding: 8px 16px;
164
+ border-radius: var(--radius-md);
165
+ font-size: clamp(0.78rem, 0.9vw, 0.85rem);
166
+ font-weight: 600;
167
+ cursor: pointer;
168
+ display: inline-flex;
169
+ align-items: center;
170
+ gap: 8px;
171
+ transition: all 0.2s ease;
172
+ }
173
+
174
+ .btn:hover {
175
+ background: rgba(255, 255, 255, 0.1);
176
+ border-color: rgba(255, 255, 255, 0.25);
177
+ transform: translateY(-1px);
178
+ }
179
+
180
+ .btn-primary {
181
+ background: linear-gradient(135deg, #0284c7 0%, #6366f1 100%);
182
+ border: none;
183
+ color: white;
184
+ box-shadow: 0 4px 14px rgba(2, 132, 199, 0.3);
185
+ }
186
+
187
+ .btn-primary:hover {
188
+ box-shadow: 0 6px 20px rgba(2, 132, 199, 0.5);
189
+ background: linear-gradient(135deg, #0369a1 0%, #4f46e5 100%);
190
+ }
191
+
192
+ .container {
193
+ max-width: 1480px;
194
+ margin: 0 auto;
195
+ padding: clamp(1rem, 2.5vw, 2.5rem);
196
+ display: flex;
197
+ flex-direction: column;
198
+ gap: clamp(1.25rem, 2vw, 2rem);
199
+ }
200
+
201
+ .controls-bar {
202
+ display: flex;
203
+ flex-wrap: wrap;
204
+ justify-content: space-between;
205
+ align-items: center;
206
+ gap: 1rem;
207
+ padding: 1rem 1.5rem;
208
+ }
209
+
210
+ .tabs-group {
211
+ display: flex;
212
+ background: rgba(0, 0, 0, 0.3);
213
+ border: 1px solid var(--border-subtle);
214
+ border-radius: var(--radius-md);
215
+ padding: 4px;
216
+ gap: 4px;
217
+ }
218
+
219
+ .tab-btn {
220
+ background: transparent;
221
+ border: none;
222
+ color: var(--text-muted);
223
+ padding: 6px 16px;
224
+ font-size: clamp(0.78rem, 0.9vw, 0.85rem);
225
+ font-weight: 600;
226
+ border-radius: var(--radius-sm);
227
+ cursor: pointer;
228
+ transition: all 0.2s ease;
229
+ }
230
+
231
+ .tab-btn.active {
232
+ background: rgba(56, 189, 248, 0.15);
233
+ color: var(--accent-cyan);
234
+ border: 1px solid rgba(56, 189, 248, 0.3);
235
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
236
+ }
237
+
238
+ .metrics-grid {
239
+ display: grid;
240
+ grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
241
+ gap: 1.25rem;
242
+ }
243
+
244
+ .metric-card {
245
+ padding: clamp(1.15rem, 1.8vw, 1.6rem);
246
+ position: relative;
247
+ overflow: hidden;
248
+ display: flex;
249
+ flex-direction: column;
250
+ justify-content: space-between;
251
+ }
252
+
253
+ .metric-card::before {
254
+ content: '';
255
+ position: absolute;
256
+ top: 0;
257
+ left: 0;
258
+ width: 100%;
259
+ height: 3px;
260
+ background: linear-gradient(90deg, transparent, var(--card-accent, var(--accent-cyan)), transparent);
261
+ opacity: 0.8;
262
+ }
263
+
264
+ .metric-header {
265
+ display: flex;
266
+ justify-content: space-between;
267
+ align-items: flex-start;
268
+ margin-bottom: 0.75rem;
269
+ }
270
+
271
+ .metric-label {
272
+ font-size: clamp(0.75rem, 0.9vw, 0.825rem);
273
+ font-weight: 600;
274
+ text-transform: uppercase;
275
+ letter-spacing: 0.05em;
276
+ color: var(--text-muted);
277
+ }
278
+
279
+ .metric-icon {
280
+ width: 32px;
281
+ height: 32px;
282
+ border-radius: 8px;
283
+ background: rgba(255, 255, 255, 0.04);
284
+ display: flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ font-size: 1.1rem;
288
+ color: var(--card-accent, var(--accent-cyan));
289
+ }
290
+
291
+ .metric-value {
292
+ font-size: clamp(1.2rem, 1.65vw, 1.65rem);
293
+ font-weight: 800;
294
+ letter-spacing: -0.02em;
295
+ color: var(--text-main);
296
+ margin-bottom: 0.4rem;
297
+ line-height: 1.2;
298
+ white-space: nowrap;
299
+ overflow: hidden;
300
+ text-overflow: ellipsis;
301
+ }
302
+
303
+ .metric-sub {
304
+ font-size: clamp(0.725rem, 0.85vw, 0.8rem);
305
+ color: var(--text-dim);
306
+ display: flex;
307
+ align-items: center;
308
+ gap: 6px;
309
+ }
310
+
311
+ .badge-positive {
312
+ color: var(--accent-emerald);
313
+ background: rgba(16, 185, 129, 0.1);
314
+ padding: 2px 6px;
315
+ border-radius: 4px;
316
+ font-weight: 600;
317
+ }
318
+
319
+ .badge-info {
320
+ color: var(--accent-cyan);
321
+ background: rgba(56, 189, 248, 0.1);
322
+ padding: 2px 6px;
323
+ border-radius: 4px;
324
+ font-weight: 600;
325
+ }
326
+
327
+ .chart-row {
328
+ display: grid;
329
+ grid-template-columns: 2fr 1fr;
330
+ gap: 1.5rem;
331
+ }
332
+
333
+ @media (max-width: 1024px) {
334
+ .chart-row {
335
+ grid-template-columns: 1fr;
336
+ }
337
+ }
338
+
339
+ .chart-box {
340
+ padding: clamp(1.15rem, 1.8vw, 1.6rem);
341
+ display: flex;
342
+ flex-direction: column;
343
+ gap: 1rem;
344
+ min-height: 450px;
345
+ max-height: 70vh;
346
+ overflow: hidden;
347
+ }
348
+
349
+ .chart-header {
350
+ display: flex;
351
+ justify-content: space-between;
352
+ align-items: center;
353
+ flex-wrap: wrap;
354
+ gap: 0.5rem;
355
+ }
356
+
357
+ .chart-title-group {
358
+ display: flex;
359
+ flex-direction: column;
360
+ gap: 4px;
361
+ }
362
+
363
+ .chart-title {
364
+ font-size: clamp(1rem, 1.3vw, 1.2rem);
365
+ font-weight: 700;
366
+ color: var(--text-main);
367
+ }
368
+
369
+ .chart-subtitle {
370
+ font-size: clamp(0.75rem, 0.9vw, 0.85rem);
371
+ color: var(--text-muted);
372
+ }
373
+
374
+ .chart-controls {
375
+ display: flex;
376
+ gap: 6px;
377
+ }
378
+
379
+ .chart-btn {
380
+ background: rgba(255, 255, 255, 0.05);
381
+ border: 1px solid var(--border-subtle);
382
+ color: var(--text-muted);
383
+ padding: 4px 10px;
384
+ border-radius: var(--radius-sm);
385
+ font-size: 0.75rem;
386
+ font-weight: 600;
387
+ cursor: pointer;
388
+ }
389
+
390
+ .chart-btn.active {
391
+ background: rgba(56, 189, 248, 0.2);
392
+ color: var(--accent-cyan);
393
+ border-color: rgba(56, 189, 248, 0.4);
394
+ }
395
+
396
+ .canvas-wrapper {
397
+ position: relative;
398
+ flex: 1;
399
+ width: 100%;
400
+ min-height: 280px;
401
+ max-height: calc(70vh - 90px);
402
+ }
403
+
404
+ .pie-canvas-wrapper {
405
+ position: relative;
406
+ width: 100%;
407
+ height: 210px;
408
+ max-height: 220px;
409
+ min-height: 180px;
410
+ display: flex;
411
+ align-items: center;
412
+ justify-content: center;
413
+ flex-shrink: 0;
414
+ }
415
+
416
+ .secondary-grid {
417
+ display: grid;
418
+ grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
419
+ gap: 1.5rem;
420
+ }
421
+
422
+ .budget-box {
423
+ padding: clamp(1.15rem, 1.8vw, 1.6rem);
424
+ display: flex;
425
+ flex-direction: column;
426
+ gap: 1rem;
427
+ }
428
+
429
+ .budget-grid {
430
+ display: grid;
431
+ grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
432
+ gap: 1.25rem;
433
+ margin-top: 0.25rem;
434
+ }
435
+
436
+ .budget-card {
437
+ background: rgba(255, 255, 255, 0.02);
438
+ border: 1px solid var(--border-subtle);
439
+ border-radius: var(--radius-md);
440
+ padding: 1.25rem;
441
+ display: flex;
442
+ flex-direction: column;
443
+ gap: 0.9rem;
444
+ transition: all 0.2s ease;
445
+ }
446
+
447
+ .budget-card:hover {
448
+ border-color: rgba(255, 255, 255, 0.12);
449
+ background: rgba(255, 255, 255, 0.035);
450
+ }
451
+
452
+ .budget-card-header {
453
+ display: flex;
454
+ justify-content: space-between;
455
+ align-items: center;
456
+ padding-bottom: 0.4rem;
457
+ border-bottom: 1px solid rgba(255, 255, 255, 0.06);
458
+ }
459
+
460
+ .budget-group-title {
461
+ font-size: 0.95rem;
462
+ font-weight: 700;
463
+ color: var(--text-main);
464
+ display: flex;
465
+ align-items: center;
466
+ gap: 7px;
467
+ }
468
+
469
+ .budget-sub-block {
470
+ display: flex;
471
+ flex-direction: column;
472
+ gap: 0.45rem;
473
+ }
474
+
475
+ .budget-sub-header {
476
+ display: flex;
477
+ justify-content: space-between;
478
+ align-items: center;
479
+ }
480
+
481
+ .budget-sub-title {
482
+ font-size: 0.8rem;
483
+ font-weight: 600;
484
+ color: var(--text-muted);
485
+ display: flex;
486
+ align-items: center;
487
+ gap: 5px;
488
+ }
489
+
490
+ .budget-sub-divider {
491
+ height: 1px;
492
+ background: rgba(255, 255, 255, 0.04);
493
+ margin: 0.15rem 0;
494
+ }
495
+
496
+ .budget-title {
497
+ font-size: 0.85rem;
498
+ font-weight: 700;
499
+ color: var(--text-main);
500
+ display: flex;
501
+ align-items: center;
502
+ gap: 6px;
503
+ }
504
+
505
+ .budget-tag {
506
+ font-size: 0.7rem;
507
+ padding: 2px 8px;
508
+ border-radius: 999px;
509
+ font-weight: 600;
510
+ background: rgba(255, 255, 255, 0.05);
511
+ color: var(--text-muted);
512
+ }
513
+
514
+ .budget-values {
515
+ display: flex;
516
+ justify-content: space-between;
517
+ align-items: baseline;
518
+ }
519
+
520
+ .budget-cur {
521
+ font-size: clamp(1.2rem, 1.6vw, 1.5rem);
522
+ font-weight: 800;
523
+ color: var(--text-main);
524
+ }
525
+
526
+ .budget-max {
527
+ font-size: 0.8rem;
528
+ color: var(--text-dim);
529
+ font-weight: 500;
530
+ }
531
+
532
+ .budget-progress-track {
533
+ width: 100%;
534
+ height: 8px;
535
+ background: rgba(255, 255, 255, 0.05);
536
+ border-radius: 999px;
537
+ overflow: hidden;
538
+ position: relative;
539
+ }
540
+
541
+ .budget-progress-fill {
542
+ height: 100%;
543
+ border-radius: 999px;
544
+ transition: width 0.6s cubic-bezier(0.16, 1, 0.3, 1);
545
+ }
546
+
547
+ .budget-footer {
548
+ display: flex;
549
+ justify-content: space-between;
550
+ align-items: center;
551
+ font-size: 0.75rem;
552
+ color: var(--text-dim);
553
+ }
554
+
555
+ .table-box {
556
+ padding: 1.5rem;
557
+ overflow: hidden;
558
+ }
559
+
560
+ .table-wrapper {
561
+ overflow-x: auto;
562
+ margin-top: 1rem;
563
+ }
564
+
565
+ table {
566
+ width: 100%;
567
+ border-collapse: collapse;
568
+ text-align: left;
569
+ font-size: clamp(0.78rem, 0.9vw, 0.85rem);
570
+ }
571
+
572
+ th {
573
+ padding: 12px 16px;
574
+ background: rgba(0, 0, 0, 0.2);
575
+ color: var(--text-muted);
576
+ font-weight: 600;
577
+ border-bottom: 1px solid var(--border-subtle);
578
+ text-transform: uppercase;
579
+ font-size: clamp(0.68rem, 0.8vw, 0.75rem);
580
+ letter-spacing: 0.05em;
581
+ }
582
+
583
+ th.sortable {
584
+ cursor: pointer;
585
+ user-select: none;
586
+ transition: all 0.2s ease;
587
+ }
588
+
589
+ th.sortable:hover {
590
+ color: var(--accent-cyan);
591
+ background: rgba(56, 189, 248, 0.08);
592
+ }
593
+
594
+ th .sort-icon {
595
+ display: inline-block;
596
+ margin-left: 5px;
597
+ height: 20px;
598
+ width: 20px;
599
+ font-size: 0.75rem;
600
+ color: var(--text-dim);
601
+ transition: transform 0.15s ease, color 0.15s ease;
602
+ }
603
+
604
+ th:first-child,
605
+ td:first-child {
606
+ width: 300px;
607
+ min-width: 300px;
608
+ max-width: 300px;
609
+ }
610
+
611
+ th.col-code,
612
+ td.col-code {
613
+ width: 170px;
614
+ min-width: 170px;
615
+ white-space: nowrap;
616
+ }
617
+
618
+ td {
619
+ padding: 12px 16px;
620
+ border-bottom: 1px solid rgba(255, 255, 255, 0.04);
621
+ color: var(--text-main);
622
+ }
623
+
624
+ tr:hover td {
625
+ background: rgba(255, 255, 255, 0.02);
626
+ }
627
+
628
+ .breakdown-list {
629
+ display: flex;
630
+ flex-direction: column;
631
+ gap: 10px;
632
+ margin-top: 8px;
633
+ overflow-y: auto;
634
+ max-height: 160px;
635
+ padding-right: 4px;
636
+ }
637
+
638
+ .breakdown-item {
639
+ display: flex;
640
+ flex-direction: column;
641
+ gap: 6px;
642
+ }
643
+
644
+ .breakdown-header {
645
+ display: flex;
646
+ justify-content: space-between;
647
+ font-size: 0.825rem;
648
+ }
649
+
650
+ .progress-bar-bg {
651
+ width: 100%;
652
+ height: 6px;
653
+ background: rgba(255, 255, 255, 0.06);
654
+ border-radius: 999px;
655
+ overflow: hidden;
656
+ }
657
+
658
+ .progress-bar-fill {
659
+ height: 100%;
660
+ border-radius: 999px;
661
+ background: linear-gradient(90deg, var(--accent-cyan), var(--accent-violet));
662
+ transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
663
+ }
664
+
665
+ footer {
666
+ margin-top: 3rem;
667
+ padding: 1.5rem 2rem;
668
+ border-top: 1px solid var(--border-subtle);
669
+ text-align: center;
670
+ color: var(--text-dim);
671
+ font-size: 0.8rem;
672
+ display: flex;
673
+ justify-content: space-between;
674
+ align-items: center;
675
+ flex-wrap: wrap;
676
+ gap: 1rem;
677
+ }
678
+ </style>
679
+ </head>
680
+ <body>
681
+ <header>
682
+ <div class="brand-container">
683
+ <div class="brand-badge">
684
+ ${t?`<img src="${t}" alt="FluxFlow" style="width: 100%; height: 100%; object-fit: cover; border-radius: 10px;" />`:"\u26A1"}
685
+ </div>
686
+ <div>
687
+ <div class="brand-title">FluxFlow Analytics</div>
688
+ <div class="brand-subtitle">Token Intelligence & Activity Monitor</div>
689
+ </div>
690
+ </div>
691
+ <div class="header-actions">
692
+ <button class="btn" id="btn-export-json" title="Export Token Usage as JSON">
693
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
694
+ Export JSON
695
+ </button>
696
+ <button class="btn" id="btn-export-csv" title="Export Token Usage as CSV">
697
+ <svg width="14" height="14" 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>
698
+ Export CSV
699
+ </button>
700
+ <button class="btn btn-primary" id="btn-refresh">
701
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67"/></svg>
702
+ Sync Now
703
+ </button>
704
+ </div>
705
+ </header>
706
+
707
+ <div class="container">
708
+ <!-- Controls Bar -->
709
+ <div class="glass-panel controls-bar">
710
+ <div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
711
+ <span style="font-size: 0.85rem; font-weight: 700; color: var(--text-muted);">TIME RANGE:</span>
712
+ <div class="tabs-group" id="range-tabs">
713
+ <button class="tab-btn" data-range="today">Today</button>
714
+ <button class="tab-btn active" data-range="7d">Last 7 Days</button>
715
+ <button class="tab-btn" data-range="14d">Last 14 Days</button>
716
+ <button class="tab-btn" data-range="30d">Last 30 Days</button>
717
+ </div>
718
+ </div>
719
+ <div style="display: flex; align-items: center; gap: 12px;">
720
+ <label style="font-size: 0.8rem; color: var(--text-dim); display: flex; align-items: center; gap: 6px; cursor: pointer;">
721
+ <input type="checkbox" id="auto-refresh-check" style="accent-color: var(--accent-cyan);">
722
+ Auto-Sync (60s)
723
+ </label>
724
+ <span style="font-size: 0.75rem; color: var(--text-dim);" id="last-sync-time">Last synced: Just now</span>
725
+ </div>
726
+ </div>
727
+
728
+ <!-- Metrics Cards -->
729
+ <div class="metrics-grid">
730
+ <div class="glass-panel metric-card" style="--card-accent: var(--accent-cyan);">
731
+ <div class="metric-header">
732
+ <span class="metric-label">Total Tokens</span>
733
+ <div class="metric-icon">\u2726</div>
734
+ </div>
735
+ <div class="metric-value mono" id="m-total-tokens">0</div>
736
+ <div class="metric-sub">
737
+ <span class="badge-info" id="m-tokens-detail">0 In / 0 Out</span>
738
+ </div>
739
+ </div>
740
+
741
+ <div class="glass-panel metric-card" style="--card-accent: var(--accent-emerald);">
742
+ <div class="metric-header">
743
+ <span class="metric-label">Cache Ratio</span>
744
+ <div class="metric-icon">\u26A1</div>
745
+ </div>
746
+ <div class="metric-value mono" id="m-cached-tokens">0%</div>
747
+ <div class="metric-sub">
748
+ <span class="badge-positive" id="m-cached-saved">0 cached tokens</span>
749
+ </div>
750
+ </div>
751
+
752
+ <div class="glass-panel metric-card" style="--card-accent: var(--accent-amber);">
753
+ <div class="metric-header">
754
+ <span class="metric-label">API Calls</span>
755
+ <div class="metric-icon">\u2699\uFE0F</div>
756
+ </div>
757
+ <div class="metric-value mono" id="m-total-requests">0</div>
758
+ <div class="metric-sub">
759
+ <span id="m-requests-sub">0 Agent / 0 Sub-agents</span>
760
+ </div>
761
+ </div>
762
+
763
+ <div class="glass-panel metric-card" style="--card-accent: var(--accent-rose);">
764
+ <div class="metric-header">
765
+ <span class="metric-label">Tool Reliability</span>
766
+ <div class="metric-icon">\u{1F6E0}\uFE0F</div>
767
+ </div>
768
+ <div class="metric-value mono" id="m-tool-rate">100%</div>
769
+ <div class="metric-sub">
770
+ <span id="m-tool-sub">0 ok / 0 err / 0 denied</span>
771
+ </div>
772
+ </div>
773
+
774
+ <div class="glass-panel metric-card" style="--card-accent: var(--accent-blue);">
775
+ <div class="metric-header">
776
+ <span class="metric-label">Code Impact</span>
777
+ <div class="metric-icon">\u{1F4DD}</div>
778
+ </div>
779
+ <div class="metric-value mono" id="m-code-delta">+0 / -0</div>
780
+ <div class="metric-sub">
781
+ <span id="m-code-net">Net: 0 lines</span>
782
+ </div>
783
+ </div>
784
+ </div>
785
+
786
+ <!-- Budget & Quota Tracking -->
787
+ <div class="glass-panel budget-box" id="budget-section">
788
+ <div class="chart-header">
789
+ <div class="chart-title-group">
790
+ <div class="chart-title" style="display: flex; align-items: center; gap: 8px;">
791
+ <span>\u{1F4B0}</span>
792
+ <span>Budget & Quota Tracking</span>
793
+ <span id="budget-tier-pill" style="display: none; font-size: 0.7rem; margin-left: 4px;"></span>
794
+ </div>
795
+ <div class="chart-subtitle" id="budget-subtitle">Real-time spend against configured daily and monthly token limits</div>
796
+ </div>
797
+ <div id="budget-reset-badge" style="font-size: 0.75rem; color: var(--text-muted); background: rgba(0,0,0,0.3); padding: 4px 10px; border-radius: var(--radius-sm); border: 1px solid var(--border-subtle);">
798
+ Reset Mode: Daily
799
+ </div>
800
+ </div>
801
+ <div class="budget-grid" id="budget-grid-cards">
802
+ <!-- Dynamically populated by JS -->
803
+ </div>
804
+ </div>
805
+
806
+ <!-- Main Chart Row -->
807
+ <div class="chart-row">
808
+ <!-- Timeline Chart -->
809
+ <div class="glass-panel chart-box">
810
+ <div class="chart-header">
811
+ <div class="chart-title-group">
812
+ <div class="chart-title">Token Consumption Trends</div>
813
+ <div class="chart-subtitle">Prompt (Input), Candidate (Output), and Cached tokens breakdown</div>
814
+ </div>
815
+ <div class="chart-controls">
816
+ <button class="chart-btn active" data-chart-type="bar">Stacked Bar</button>
817
+ <button class="chart-btn" data-chart-type="line">Area Chart</button>
818
+ </div>
819
+ </div>
820
+ <div class="canvas-wrapper">
821
+ <canvas id="timelineChart"></canvas>
822
+ </div>
823
+ </div>
824
+
825
+ <!-- Provider / Model Share -->
826
+ <div class="glass-panel chart-box">
827
+ <div class="chart-header">
828
+ <div class="chart-title-group">
829
+ <div class="chart-title">Token Share by Provider</div>
830
+ <div class="chart-subtitle">Distribution of tokens across Inference Providers</div>
831
+ </div>
832
+ </div>
833
+ <div class="pie-canvas-wrapper">
834
+ <canvas id="providerPieChart"></canvas>
835
+ </div>
836
+ <div class="breakdown-list" id="provider-breakdown-list"></div>
837
+ </div>
838
+ </div>
839
+
840
+ <!-- Secondary Charts -->
841
+ <div class="secondary-grid">
842
+ <!-- Tool Execution Health -->
843
+ <div class="glass-panel chart-box">
844
+ <div class="chart-header">
845
+ <div class="chart-title-group">
846
+ <div class="chart-title">Tool Executions & Reliability</div>
847
+ <div class="chart-subtitle">Success, Error & Permission Denial breakdown</div>
848
+ </div>
849
+ </div>
850
+ <div class="canvas-wrapper">
851
+ <canvas id="toolChart"></canvas>
852
+ </div>
853
+ </div>
854
+
855
+ <!-- Code Velocity -->
856
+ <div class="glass-panel chart-box">
857
+ <div class="chart-header">
858
+ <div class="chart-title-group">
859
+ <div class="chart-title">Code Modification Volume</div>
860
+ <div class="chart-subtitle">Lines of code written (+) vs deleted (-) by agents</div>
861
+ </div>
862
+ </div>
863
+ <div class="canvas-wrapper">
864
+ <canvas id="codeChart"></canvas>
865
+ </div>
866
+ </div>
867
+ </div>
868
+
869
+ <!-- Detailed Breakdown Table -->
870
+ <div class="glass-panel table-box">
871
+ <div class="chart-header">
872
+ <div class="chart-title-group">
873
+ <div class="chart-title" id="table-view-title">Daily Detailed Token Records</div>
874
+ <div class="chart-subtitle" id="table-view-subtitle">Itemized log of daily token counts, cache ratios, and tool operations</div>
875
+ </div>
876
+ <div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap;">
877
+ <div class="tabs-group" id="table-mode-tabs">
878
+ <button class="tab-btn active" data-table-mode="daily">Daily Records</button>
879
+ <button class="tab-btn" data-table-mode="models">Model Stats</button>
880
+ </div>
881
+ <input type="text" id="table-search" placeholder="Search..." style="background: rgba(0,0,0,0.3); border: 1px solid var(--border-subtle); color: var(--text-main); padding: 6px 12px; border-radius: var(--radius-sm); font-size: 0.8rem; outline: none;">
882
+ </div>
883
+ </div>
884
+ <div class="table-wrapper">
885
+ <table id="usage-table">
886
+ <thead id="usage-table-head">
887
+ <!-- Populated by JS -->
888
+ </thead>
889
+ <tbody id="usage-table-body">
890
+ <!-- Populated by JS -->
891
+ </tbody>
892
+ </table>
893
+ </div>
894
+ </div>
895
+ </div>
896
+
897
+ <footer>
898
+ <div>FluxFlow CLI \u2022 High-Fidelity Agentic Terminal</div>
899
+ <div>Data stored locally in ${f.replaceAll("\\\\","/").replaceAll("\\","/")}</div>
900
+ </footer>
901
+
902
+ <script>
903
+ let rawData = null;
904
+ let activeRange = '7d';
905
+ let chartType = 'bar';
906
+ let tableMode = 'daily';
907
+ let dailySortField = 'date';
908
+ let dailySortOrder = 'desc';
909
+ let modelSortField = 'tokens';
910
+ let modelSortOrder = 'desc';
911
+ let timelineChart = null;
912
+ let providerPieChart = null;
913
+ let toolChart = null;
914
+ let codeChart = null;
915
+
916
+ function formatNumber(num) {
917
+ if (num === undefined || num === null) return '0';
918
+ if (num >= 1_000_000) return (num / 1_000_000).toFixed(2) + 'M';
919
+ if (num >= 1_000) return (num / 1_000).toFixed(1) + 'k';
920
+ return num.toLocaleString();
921
+ }
922
+
923
+ function filterTimelineByRange(timeline, range) {
924
+ if (!timeline || timeline.length === 0) return [];
925
+ const todayStr = rawData.currentDate || new Date().toISOString().split('T')[0];
926
+ const todayTime = new Date(todayStr).getTime();
927
+
928
+ let days = 7;
929
+ if (range === 'today') days = 1;
930
+ else if (range === '7d') days = 7;
931
+ else if (range === '14d') days = 14;
932
+ else if (range === '30d') days = 30;
933
+ else days = 30;
934
+
935
+ const cutoff = todayTime - (days - 1) * 24 * 60 * 60 * 1000;
936
+ return timeline.filter(item => {
937
+ const itemTime = new Date(item.date).getTime();
938
+ return itemTime >= cutoff;
939
+ });
940
+ }
941
+
942
+ async function fetchData() {
943
+ try {
944
+ const res = await fetch('/api/usage');
945
+ rawData = await res.json();
946
+ renderDashboard();
947
+ document.getElementById('last-sync-time').textContent = 'Last synced: ' + new Date().toLocaleTimeString();
948
+ } catch (err) {
949
+ console.error('Failed to sync usage data:', err);
950
+ }
951
+ }
952
+
953
+ function renderDashboard() {
954
+ if (!rawData || !rawData.timeline) return;
955
+
956
+ const filtered = filterTimelineByRange(rawData.timeline, activeRange);
957
+
958
+ let totalTokens = 0;
959
+ let cachedTokens = 0;
960
+ let candidateTokens = 0;
961
+ let promptTokens = 0;
962
+ let agentRequests = 0;
963
+ let bgRequests = 0;
964
+ let searchRequests = 0;
965
+ let toolSuccess = 0;
966
+ let toolFailure = 0;
967
+ let toolDenied = 0;
968
+ let linesAdded = 0;
969
+ let linesRemoved = 0;
970
+
971
+ const providerTokens = {};
972
+ const modelTokens = {};
973
+
974
+ filtered.forEach(item => {
975
+ totalTokens += item.tokens || 0;
976
+ cachedTokens += item.cachedTokens || 0;
977
+ candidateTokens += item.candidateTokens || 0;
978
+ promptTokens += item.promptTokens || 0;
979
+ agentRequests += item.agent || 0;
980
+ bgRequests += item.background || 0;
981
+ searchRequests += item.search || 0;
982
+ toolSuccess += item.toolSuccess || 0;
983
+ toolFailure += item.toolFailure || 0;
984
+ toolDenied += item.toolDenied || 0;
985
+ linesAdded += item.linesAdded || 0;
986
+ linesRemoved += item.linesRemoved || 0;
987
+
988
+ const models = item.models || {};
989
+ for (const prov in models) {
990
+ providerTokens[prov] = (providerTokens[prov] || 0);
991
+ for (const m in models[prov]) {
992
+ const mTok = models[prov][m]?.tokens || 0;
993
+ providerTokens[prov] += mTok;
994
+ modelTokens[m] = (modelTokens[m] || 0) + mTok;
995
+ }
996
+ }
997
+ });
998
+
999
+ document.getElementById('m-total-tokens').textContent = formatNumber(totalTokens);
1000
+ document.getElementById('m-tokens-detail').textContent = \`\${formatNumber(promptTokens)} In / \${formatNumber(candidateTokens)} Out\`;
1001
+
1002
+ const cachePercent = promptTokens > 0 ? ((cachedTokens / promptTokens) * 100).toFixed(1) : 0;
1003
+ document.getElementById('m-cached-tokens').textContent = cachePercent + '%';
1004
+ document.getElementById('m-cached-saved').textContent = \`\${formatNumber(cachedTokens)} / \${formatNumber(promptTokens)} Cached\`;
1005
+
1006
+ const totalReq = agentRequests + bgRequests + searchRequests;
1007
+ document.getElementById('m-total-requests').textContent = totalReq.toLocaleString();
1008
+ document.getElementById('m-requests-sub').textContent = \`\${agentRequests} Agent / \${bgRequests} Background\`;
1009
+
1010
+ const totalTools = toolSuccess + toolFailure + toolDenied;
1011
+ const toolRate = totalTools > 0 ? ((toolSuccess / totalTools) * 100).toFixed(1) : 100;
1012
+ document.getElementById('m-tool-rate').textContent = toolRate + '%';
1013
+ document.getElementById('m-tool-sub').textContent = \`\${toolSuccess} ok / \${toolFailure} err / \${toolDenied} denied\`;
1014
+
1015
+ document.getElementById('m-code-delta').innerHTML = \`<span style="color: #38bdf8;">+\${formatNumber(linesAdded)}</span> <span style="color: #64748b; font-size: 0.85em;">/</span> <span style="color: #f43f5e;">-\${formatNumber(linesRemoved)}</span>\`;
1016
+ document.getElementById('m-code-net').textContent = \`Net: \${linesAdded - linesRemoved >= 0 ? '+' : ''}\${formatNumber(linesAdded - linesRemoved)} lines\`;
1017
+
1018
+ if (rawData && rawData.budget) {
1019
+ renderBudget(rawData.budget);
1020
+ }
1021
+
1022
+ renderTimelineChart(filtered);
1023
+ renderProviderChart(providerTokens, totalTokens);
1024
+ renderToolChart(filtered);
1025
+ renderCodeChart(filtered);
1026
+ renderTable(filtered);
1027
+ }
1028
+
1029
+ function getProviderBrandIcon(providerName, size = 20) {
1030
+ const p = (providerName || '').toLowerCase().trim();
1031
+ if (p.includes('google') || p.includes('gemini')) {
1032
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1033
+ <defs>
1034
+ <linearGradient id="gg-gemini" x1="0%" y1="0%" x2="100%" y2="100%">
1035
+ <stop offset="0%" stop-color="#4285F4"/>
1036
+ <stop offset="45%" stop-color="#9B72CB"/>
1037
+ <stop offset="100%" stop-color="#EA4335"/>
1038
+ </linearGradient>
1039
+ </defs>
1040
+ <path d="M12 1C12 7.075 7.075 12 1 12C7.075 12 12 16.925 12 23C12 16.925 16.925 12 23 12C16.925 12 12 7.075 12 1Z" fill="url(#gg-gemini)"/>
1041
+ </svg>\`;
1042
+ } else if (p.includes('nvidia')) {
1043
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1044
+ <path d="M9.85 7.15c.61-.17 1.43-.27 2.15-.27 3.32 0 6.01 2.37 6.01 5.3s-2.69 5.3-6.01 5.3c-.72 0-1.54-.1-2.15-.27V7.15zM2.5 12.18c0-3.32 2.3-6.17 5.75-6.9v13.8c-3.45-.73-5.75-3.58-5.75-6.9zm13.1 4.74c1.88-1.07 3.15-2.88 3.15-4.74 0-1.86-1.27-3.67-3.15-4.74l1.58-1.58C19.98 7.37 21.5 9.61 21.5 12.18s-1.52 4.81-4.32 6.32l-1.58-1.58z" fill="#76B900"/>
1045
+ </svg>\`;
1046
+ } else if (p.includes('deepseek')) {
1047
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1048
+ <path d="M12 2C6.48 2 2 6.48 2 12c0 3.82 2.15 7.14 5.3 8.84.18-.7.42-1.65.42-2.3 0-.82-.24-1.22-.52-1.74-.75-1.39-1.2-2.63-1.2-4.4 0-3.1 2.33-5.6 5.21-5.6 2.88 0 5.21 2.5 5.21 5.6 0 2.22-.73 4.14-2.11 5.42-.51.48-.96 1.05-.96 1.83 0 .7.26 1.58.42 2.24C17.65 20.25 22 16.63 22 12c0-5.52-4.48-10-10-10z" fill="#1D4ED8"/>
1049
+ <circle cx="10" cy="11.5" r="1.4" fill="#60A5FA"/>
1050
+ <circle cx="14" cy="11.5" r="1.4" fill="#60A5FA"/>
1051
+ </svg>\`;
1052
+ } else if (p.includes('mistral')) {
1053
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1054
+ <rect x="2" y="3" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1055
+ <rect x="18.4" y="3" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1056
+ <rect x="2" y="8.4" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1057
+ <rect x="7.4" y="8.4" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1058
+ <rect x="13" y="8.4" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1059
+ <rect x="18.4" y="8.4" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1060
+ <rect x="2" y="13.8" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1061
+ <rect x="7.4" y="13.8" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1062
+ <rect x="13" y="13.8" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1063
+ <rect x="18.4" y="13.8" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1064
+ <rect x="2" y="19.2" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1065
+ <rect x="18.4" y="19.2" width="3.6" height="3.6" rx="0.5" fill="#FF7000"/>
1066
+ </svg>\`;
1067
+ } else if (p.includes('openrouter')) {
1068
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1069
+ <rect x="3" y="3" width="7" height="7" rx="2" fill="#6366F1"/>
1070
+ <rect x="14" y="3" width="7" height="7" rx="2" fill="#38BDF8"/>
1071
+ <rect x="3" y="14" width="7" height="7" rx="2" fill="#38BDF8"/>
1072
+ <rect x="14" y="14" width="7" height="7" rx="2" fill="#6366F1"/>
1073
+ <path d="M10 6.5h4M6.5 10v4M17.5 10v4M10 17.5h4" stroke="rgba(255,255,255,0.85)" stroke-width="1.6" stroke-linecap="round"/>
1074
+ </svg>\`;
1075
+ } else if (p.includes('ollama')) {
1076
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1077
+ <path d="M8 3h3v4.5h2V4h3v8.5c0 2.2-1.8 4-4 4h-1v4.5H9V16.5H8c-2.2 0-4-1.8-4-4V7c0-2.2 1.8-4 4-4z" fill="#F59E0B"/>
1078
+ <circle cx="10" cy="5.8" r="1.1" fill="#1E293B"/>
1079
+ <circle cx="14" cy="5.8" r="1.1" fill="#1E293B"/>
1080
+ </svg>\`;
1081
+ } else if (p.includes('inferx')) {
1082
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1083
+ <defs>
1084
+ <linearGradient id="inf-grad" x1="0%" y1="0%" x2="100%" y2="100%">
1085
+ <stop offset="0%" stop-color="#EC4899"/>
1086
+ <stop offset="100%" stop-color="#8B5CF6"/>
1087
+ </linearGradient>
1088
+ </defs>
1089
+ <path d="M4 4l6.5 7L4 20h3.5l4.5-5.2 4.5 5.2H20l-6.5-9L20 4h-3.5L12 9.2 7.5 4H4z" fill="url(#inf-grad)"/>
1090
+ </svg>\`;
1091
+ } else if (p.includes('sensenova') || p.includes('sense')) {
1092
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1093
+ <defs>
1094
+ <linearGradient id="sense-grad" x1="0%" y1="0%" x2="100%" y2="100%">
1095
+ <stop offset="0%" stop-color="#06B6D4"/>
1096
+ <stop offset="100%" stop-color="#6366F1"/>
1097
+ </linearGradient>
1098
+ </defs>
1099
+ <circle cx="12" cy="12" r="8.5" stroke="url(#sense-grad)" stroke-width="2"/>
1100
+ <path d="M12 5v14M5 12h14M7 7l10 10M17 7L7 17" stroke="url(#sense-grad)" stroke-width="1.5" stroke-linecap="round"/>
1101
+ </svg>\`;
1102
+ } else if (p.includes('poolside') || p.includes('pool')) {
1103
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1104
+ <path d="M2 12C2 12 5 9 12 9C19 9 22 12 22 12C22 12 19 15 12 15C5 15 2 12 2 12Z" stroke="#38BDF8" stroke-width="2" stroke-linejoin="round"/>
1105
+ <circle cx="12" cy="12" r="2.5" fill="#38BDF8"/>
1106
+ <path d="M4 17C6 19 9 20 12 20C15 20 18 19 20 17" stroke="#38BDF8" stroke-width="1.5" stroke-linecap="round"/>
1107
+ </svg>\`;
1108
+ } else if (p.includes('9router') || p.includes('router')) {
1109
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1110
+ <circle cx="12" cy="12" r="9" stroke="#EC4899" stroke-width="2"/>
1111
+ <path d="M12 7v5l3 3" stroke="#EC4899" stroke-width="2" stroke-linecap="round"/>
1112
+ <circle cx="12" cy="12" r="2" fill="#EC4899"/>
1113
+ </svg>\`;
1114
+ } else if (p.includes('aihubmix') || p.includes('hubmix')) {
1115
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1116
+ <circle cx="12" cy="4.5" r="2.8" fill="#A855F7"/>
1117
+ <circle cx="5" cy="18" r="2.8" fill="#D946EF"/>
1118
+ <circle cx="19" cy="18" r="2.8" fill="#EC4899"/>
1119
+ <path d="M12 7.5v6.5M12 14L6.8 16.8M12 14l5.2 2.8" stroke="#A855F7" stroke-width="1.8" stroke-linecap="round"/>
1120
+ </svg>\`;
1121
+ } else if (p.includes('anthropic') || p.includes('claude')) {
1122
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1123
+ <path d="M14.5 3L8 21h3.5l1.3-3.8h4.4L18.5 21H22L15.5 3h-1zm.3 4.2l1.6 6.8h-3.2l1.6-6.8zM2 21h3.5L9.5 3H6L2 21z" fill="#D97757"/>
1124
+ </svg>\`;
1125
+ } else if (p.includes('openai')) {
1126
+ return \`<svg width="\${size}" height="\${size}" viewBox="0 0 24 24" fill="none" style="vertical-align: middle; flex-shrink: 0;" xmlns="http://www.w3.org/2000/svg">
1127
+ <path d="M20.5 10.3a5.5 5.5 0 0 0-.4-4.5 5.6 5.6 0 0 0-5.8-2.6A5.5 5.5 0 0 0 9.8 1.8a5.6 5.6 0 0 0-5.3 3.9 5.5 5.5 0 0 0-3.3 3.6 5.6 5.6 0 0 0 .9 6.2 5.5 5.5 0 0 0 .4 4.5 5.6 5.6 0 0 0 5.8 2.6 5.5 5.5 0 0 0 4.5 1.4 5.6 5.6 0 0 0 5.3-3.9 5.5 5.5 0 0 0 3.3-3.6 5.6 5.6 0 0 0-.9-6.2z" stroke="#10A37F" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"/>
1128
+ </svg>\`;
1129
+ }
1130
+ return \`<span style="color: var(--accent-cyan); font-size: 1.1rem; vertical-align: middle;">\u2726</span>\`;
1131
+ }
1132
+
1133
+ function renderBudget(budgetData) {
1134
+ const grid = document.getElementById('budget-grid-cards');
1135
+ const tierPill = document.getElementById('budget-tier-pill');
1136
+ const resetBadge = document.getElementById('budget-reset-badge');
1137
+ const subtitleEl = document.getElementById('budget-subtitle');
1138
+
1139
+ if (!budgetData) {
1140
+ grid.innerHTML = '<div style="color: var(--text-dim); padding: 1rem;">No budget constraints configured.</div>';
1141
+ return;
1142
+ }
1143
+
1144
+ const isProviderMode = budgetData.providerBudgetsList && budgetData.providerBudgetsList.length > 0;
1145
+
1146
+ if (isProviderMode) {
1147
+ tierPill.style.display = 'inline-block';
1148
+ tierPill.className = 'badge-positive';
1149
+ tierPill.textContent = \`Provider Mode (\${budgetData.providerBudgetsList.length} Active)\`;
1150
+ subtitleEl.textContent = 'Enforcing provider-specific daily, monthly, and turn quotas';
1151
+ } else {
1152
+ tierPill.style.display = 'none';
1153
+ subtitleEl.textContent = 'Real-time spend against configured global daily and monthly token limits';
1154
+ }
1155
+
1156
+ resetBadge.textContent = 'Reset: ' + (budgetData.resetMode || 'None') + (budgetData.resetMode === 'Custom' ? \` (Day \${budgetData.resetDay})\` : '');
1157
+
1158
+ let cardsHtml = '';
1159
+
1160
+ if (isProviderMode) {
1161
+ budgetData.providerBudgetsList.forEach(prov => {
1162
+ const dailyTokens = prov.dailyTokens || 0;
1163
+ const dailyLimit = prov.dailyTokenLimit || 0;
1164
+ const isDailyUnlimited = prov.isDailyUnlimited;
1165
+ const dailyPct = (!isDailyUnlimited && dailyLimit > 0) ? Math.min(100, (dailyTokens / dailyLimit) * 100) : 0;
1166
+ const dailyColor = dailyPct >= 90 ? 'linear-gradient(90deg, #f43f5e, #e11d48)' : dailyPct >= 75 ? 'linear-gradient(90deg, #f59e0b, #d97706)' : 'linear-gradient(90deg, #38bdf8, #0284c7)';
1167
+
1168
+ const monthlyTokens = prov.monthlyTokens || 0;
1169
+ const monthlyLimit = prov.monthlyTokenLimit || 0;
1170
+ const isMonthlyUnlimited = prov.isMonthlyUnlimited;
1171
+ const monthlyPct = (!isMonthlyUnlimited && monthlyLimit > 0) ? Math.min(100, (monthlyTokens / monthlyLimit) * 100) : 0;
1172
+ const monthlyColor = monthlyPct >= 90 ? 'linear-gradient(90deg, #f43f5e, #e11d48)' : monthlyPct >= 75 ? 'linear-gradient(90deg, #f59e0b, #d97706)' : 'linear-gradient(90deg, #a855f7, #7c3aed)';
1173
+
1174
+ // Unified Provider Card grouping both Daily and Monthly
1175
+ cardsHtml += \`
1176
+ <div class="budget-card">
1177
+ <div class="budget-card-header">
1178
+ <div class="budget-group-title">
1179
+ \${getProviderBrandIcon(prov.provider, 22)}
1180
+ <span>\${prov.provider}</span>
1181
+ </div>
1182
+ </div>
1183
+
1184
+ <!-- Daily Budget Sub-Block -->
1185
+ <div class="budget-sub-block">
1186
+ <div class="budget-sub-header">
1187
+ <span class="budget-sub-title">\u26A1 Daily Token Budget</span>
1188
+ <span class="budget-tag" style="font-size: 0.68rem; padding: 1px 6px;">\${isDailyUnlimited ? 'Unlimited' : dailyPct.toFixed(1) + '%'}</span>
1189
+ </div>
1190
+ <div class="budget-values">
1191
+ <div class="budget-cur mono">\${formatNumber(dailyTokens)}</div>
1192
+ <div class="budget-max mono">/ \${isDailyUnlimited ? '\u221E Limit' : formatNumber(dailyLimit)}</div>
1193
+ </div>
1194
+ <div class="budget-progress-track">
1195
+ <div class="budget-progress-fill" style="width: \${isDailyUnlimited ? 100 : dailyPct}%; background: \${isDailyUnlimited ? 'rgba(56,189,248,0.3)' : dailyColor};"></div>
1196
+ </div>
1197
+ <div class="budget-footer">
1198
+ <span>\${isDailyUnlimited ? 'No daily cap' : \`\${formatNumber(Math.max(0, dailyLimit - dailyTokens))} remaining\`}</span>
1199
+ <span class="mono">\${isDailyUnlimited ? 'Active' : \`\${dailyPct.toFixed(0)}% used\`}</span>
1200
+ </div>
1201
+ </div>
1202
+
1203
+ <div class="budget-sub-divider"></div>
1204
+
1205
+ <!-- Monthly Budget Sub-Block -->
1206
+ <div class="budget-sub-block">
1207
+ <div class="budget-sub-header">
1208
+ <span class="budget-sub-title">\u{1F4C5} Monthly / Cycle Budget</span>
1209
+ <span class="budget-tag" style="font-size: 0.68rem; padding: 1px 6px;">\${isMonthlyUnlimited ? 'Unlimited' : monthlyPct.toFixed(1) + '%'}</span>
1210
+ </div>
1211
+ <div class="budget-values">
1212
+ <div class="budget-cur mono">\${formatNumber(monthlyTokens)}</div>
1213
+ <div class="budget-max mono">/ \${isMonthlyUnlimited ? '\u221E Limit' : formatNumber(monthlyLimit)}</div>
1214
+ </div>
1215
+ <div class="budget-progress-track">
1216
+ <div class="budget-progress-fill" style="width: \${isMonthlyUnlimited ? 100 : monthlyPct}%; background: \${isMonthlyUnlimited ? 'rgba(168,85,247,0.3)' : monthlyColor};"></div>
1217
+ </div>
1218
+ <div class="budget-footer">
1219
+ <span>\${isMonthlyUnlimited ? 'No monthly cap' : \`\${formatNumber(Math.max(0, monthlyLimit - monthlyTokens))} remaining\`}</span>
1220
+ <span class="mono">\${isMonthlyUnlimited ? 'Active' : \`\${monthlyPct.toFixed(0)}% used\`}</span>
1221
+ </div>
1222
+ </div>
1223
+ </div>
1224
+ \`;
1225
+ });
1226
+ } else {
1227
+ // Global Mode Cards
1228
+ const daily = budgetData.daily || {};
1229
+ const monthly = budgetData.monthly || {};
1230
+
1231
+ const dailyTokens = daily.tokensUsed || 0;
1232
+ const dailyLimit = daily.tokenLimit || 0;
1233
+ const isDailyUnlimited = daily.isUnlimitedTokens;
1234
+ const dailyPct = (!isDailyUnlimited && dailyLimit > 0) ? Math.min(100, (dailyTokens / dailyLimit) * 100) : 0;
1235
+ const dailyColor = dailyPct >= 90 ? 'linear-gradient(90deg, #f43f5e, #e11d48)' : dailyPct >= 75 ? 'linear-gradient(90deg, #f59e0b, #d97706)' : 'linear-gradient(90deg, #38bdf8, #0284c7)';
1236
+
1237
+ const monthlyTokens = monthly.tokensUsed || 0;
1238
+ const monthlyLimit = monthly.tokenLimit || 0;
1239
+ const isMonthlyUnlimited = monthly.isUnlimitedTokens;
1240
+ const monthlyPct = (!isMonthlyUnlimited && monthlyLimit > 0) ? Math.min(100, (monthlyTokens / monthlyLimit) * 100) : 0;
1241
+ const monthlyColor = monthlyPct >= 90 ? 'linear-gradient(90deg, #f43f5e, #e11d48)' : monthlyPct >= 75 ? 'linear-gradient(90deg, #f59e0b, #d97706)' : 'linear-gradient(90deg, #a855f7, #7c3aed)';
1242
+
1243
+ cardsHtml += \`
1244
+ <div class="budget-card">
1245
+ <div class="budget-card-header">
1246
+ <div class="budget-group-title">
1247
+ <span style="color: var(--accent-cyan);">\u26A1</span>
1248
+ <span>Global Budget Quotas</span>
1249
+ </div>
1250
+ <span class="budget-tag">Global Cap</span>
1251
+ </div>
1252
+
1253
+ <!-- Daily Budget Sub-Block -->
1254
+ <div class="budget-sub-block">
1255
+ <div class="budget-sub-header">
1256
+ <span class="budget-sub-title">\u26A1 Daily Token Budget</span>
1257
+ <span class="budget-tag" style="font-size: 0.68rem; padding: 1px 6px;">\${isDailyUnlimited ? 'Unlimited' : dailyPct.toFixed(1) + '%'}</span>
1258
+ </div>
1259
+ <div class="budget-values">
1260
+ <div class="budget-cur mono">\${formatNumber(dailyTokens)}</div>
1261
+ <div class="budget-max mono">/ \${isDailyUnlimited ? '\u221E Limit' : formatNumber(dailyLimit)}</div>
1262
+ </div>
1263
+ <div class="budget-progress-track">
1264
+ <div class="budget-progress-fill" style="width: \${isDailyUnlimited ? 100 : dailyPct}%; background: \${isDailyUnlimited ? 'rgba(56,189,248,0.3)' : dailyColor};"></div>
1265
+ </div>
1266
+ <div class="budget-footer">
1267
+ <span>\${isDailyUnlimited ? 'No daily cap enforced' : \`\${formatNumber(Math.max(0, dailyLimit - dailyTokens))} remaining\`}</span>
1268
+ <span class="mono">\${isDailyUnlimited ? 'Active' : \`\${dailyPct.toFixed(0)}% used\`}</span>
1269
+ </div>
1270
+ </div>
1271
+
1272
+ <div class="budget-sub-divider"></div>
1273
+
1274
+ <!-- Monthly Budget Sub-Block -->
1275
+ <div class="budget-sub-block">
1276
+ <div class="budget-sub-header">
1277
+ <span class="budget-sub-title">\u{1F4C5} Monthly / Cycle Budget</span>
1278
+ <span class="budget-tag" style="font-size: 0.68rem; padding: 1px 6px;">\${isMonthlyUnlimited ? 'Unlimited' : monthlyPct.toFixed(1) + '%'}</span>
1279
+ </div>
1280
+ <div class="budget-values">
1281
+ <div class="budget-cur mono">\${formatNumber(monthlyTokens)}</div>
1282
+ <div class="budget-max mono">/ \${isMonthlyUnlimited ? '\u221E Limit' : formatNumber(monthlyLimit)}</div>
1283
+ </div>
1284
+ <div class="budget-progress-track">
1285
+ <div class="budget-progress-fill" style="width: \${isMonthlyUnlimited ? 100 : monthlyPct}%; background: \${isMonthlyUnlimited ? 'rgba(168,85,247,0.3)' : monthlyColor};"></div>
1286
+ </div>
1287
+ <div class="budget-footer">
1288
+ <span>\${isMonthlyUnlimited ? 'No monthly cap enforced' : \`\${formatNumber(Math.max(0, monthlyLimit - monthlyTokens))} remaining\`}</span>
1289
+ <span class="mono">\${isMonthlyUnlimited ? 'Active' : \`\${monthlyPct.toFixed(0)}% used\`}</span>
1290
+ </div>
1291
+ </div>
1292
+ </div>
1293
+ \`;
1294
+ }
1295
+
1296
+ grid.innerHTML = cardsHtml;
1297
+ }
1298
+
1299
+ function renderTimelineChart(timeline) {
1300
+ const ctx = document.getElementById('timelineChart').getContext('2d');
1301
+ const labels = timeline.map(t => {
1302
+ const parts = t.date.split('-');
1303
+ return parts.length === 3 ? parts[1] + '/' + parts[2] : t.date;
1304
+ });
1305
+
1306
+ const uncachedPromptData = timeline.map(t => t.uncachedPromptTokens !== undefined ? t.uncachedPromptTokens : Math.max(0, (t.promptTokens || 0) - (t.cachedTokens || 0)));
1307
+ const cachedData = timeline.map(t => t.cachedTokens || 0);
1308
+ const candidateData = timeline.map(t => t.candidateTokens || 0);
1309
+
1310
+ if (timelineChart) timelineChart.destroy();
1311
+
1312
+ const isLine = chartType === 'line';
1313
+
1314
+ timelineChart = new Chart(ctx, {
1315
+ type: isLine ? 'line' : 'bar',
1316
+ data: {
1317
+ labels: labels,
1318
+ datasets: [
1319
+ {
1320
+ label: 'Input (Cached)',
1321
+ data: cachedData,
1322
+ backgroundColor: isLine ? 'rgba(4, 120, 87, 0.4)' : '#047857',
1323
+ borderColor: '#047857',
1324
+ borderWidth: isLine ? 2 : 0,
1325
+ fill: isLine,
1326
+ stack: 'tokens',
1327
+ tension: 0.3
1328
+ },
1329
+ {
1330
+ label: 'Input (Uncached)',
1331
+ data: uncachedPromptData,
1332
+ backgroundColor: isLine ? 'rgba(16, 185, 129, 0.65)' : '#10b981',
1333
+ borderColor: '#10b981',
1334
+ borderWidth: isLine ? 2 : 0,
1335
+ fill: isLine,
1336
+ stack: 'tokens',
1337
+ tension: 0.3
1338
+ },
1339
+ {
1340
+ label: 'Output (Candidate)',
1341
+ data: candidateData,
1342
+ backgroundColor: isLine ? 'rgba(168, 85, 247, 0.65)' : '#a855f7',
1343
+ borderColor: '#a855f7',
1344
+ borderWidth: isLine ? 2 : 0,
1345
+ fill: isLine,
1346
+ stack: 'tokens',
1347
+ tension: 0.3
1348
+ }
1349
+ ]
1350
+ },
1351
+ options: {
1352
+ responsive: true,
1353
+ maintainAspectRatio: false,
1354
+ interaction: { mode: 'index', intersect: false },
1355
+ plugins: {
1356
+ legend: {
1357
+ position: 'top',
1358
+ labels: { color: '#94a3b8', boxWidth: 12, font: { family: 'Plus Jakarta Sans', size: 11, weight: '600' } }
1359
+ },
1360
+ tooltip: {
1361
+ backgroundColor: 'rgba(15, 23, 42, 0.95)',
1362
+ titleColor: '#f8fafc',
1363
+ bodyColor: '#e2e8f0',
1364
+ borderColor: 'rgba(255, 255, 255, 0.12)',
1365
+ borderWidth: 1,
1366
+ padding: 10,
1367
+ boxPadding: 4,
1368
+ callbacks: {
1369
+ labelColor: function(context) {
1370
+ const c = context.dataset.borderColor || context.dataset.backgroundColor;
1371
+ return {
1372
+ borderColor: c,
1373
+ backgroundColor: c
1374
+ };
1375
+ },
1376
+ label: function(context) {
1377
+ return context.dataset.label + ': ' + context.parsed.y.toLocaleString() + ' tokens';
1378
+ }
1379
+ }
1380
+ }
1381
+ },
1382
+ scales: {
1383
+ x: {
1384
+ stacked: true,
1385
+ grid: { color: 'rgba(255, 255, 255, 0.05)' },
1386
+ ticks: { color: '#64748b' }
1387
+ },
1388
+ y: {
1389
+ stacked: true,
1390
+ grid: { color: 'rgba(255, 255, 255, 0.05)' },
1391
+ ticks: {
1392
+ color: '#64748b',
1393
+ callback: val => formatNumber(val)
1394
+ }
1395
+ }
1396
+ }
1397
+ }
1398
+ });
1399
+ }
1400
+
1401
+ function renderProviderChart(providerTokens, totalTokens) {
1402
+ const ctx = document.getElementById('providerPieChart').getContext('2d');
1403
+ const listEl = document.getElementById('provider-breakdown-list');
1404
+
1405
+ const providers = Object.keys(providerTokens).sort((a, b) => (providerTokens[b] || 0) - (providerTokens[a] || 0));
1406
+ const dataVals = providers.map(p => providerTokens[p]);
1407
+
1408
+ if (providerPieChart) providerPieChart.destroy();
1409
+
1410
+ const colors = ['#38bdf8', '#a855f7', '#10b981', '#f59e0b', '#f43f5e', '#3b82f6', '#06b6d4'];
1411
+
1412
+ if (providers.length === 0) {
1413
+ listEl.innerHTML = '<div style="color: var(--text-dim); font-size: 0.8rem; text-align: center; padding: 1rem;">No multi-provider usage recorded yet.</div>';
1414
+ return;
1415
+ }
1416
+
1417
+ providerPieChart = new Chart(ctx, {
1418
+ type: 'doughnut',
1419
+ data: {
1420
+ labels: providers,
1421
+ datasets: [{
1422
+ data: dataVals,
1423
+ backgroundColor: colors.slice(0, providers.length),
1424
+ borderWidth: 0,
1425
+ hoverOffset: 4
1426
+ }]
1427
+ },
1428
+ options: {
1429
+ responsive: true,
1430
+ maintainAspectRatio: false,
1431
+ cutout: '70%',
1432
+ plugins: {
1433
+ legend: { display: false }
1434
+ }
1435
+ }
1436
+ });
1437
+
1438
+ listEl.innerHTML = providers.map((p, idx) => {
1439
+ const count = providerTokens[p];
1440
+ const pct = totalTokens > 0 ? ((count / totalTokens) * 100).toFixed(1) : 0;
1441
+ const col = colors[idx % colors.length];
1442
+ return \`
1443
+ <div class="breakdown-item">
1444
+ <div class="breakdown-header">
1445
+ <span style="display: flex; align-items: center; gap: 8px;">
1446
+ \${getProviderBrandIcon(p, 16)}
1447
+ <strong style="color: var(--text-main);">\${p}</strong>
1448
+ </span>
1449
+ <span class="mono" style="color: var(--text-muted);">\${formatNumber(count)} tokens (\${pct}%)</span>
1450
+ </div>
1451
+ <div class="progress-bar-bg">
1452
+ <div class="progress-bar-fill" style="width: \${pct}%; background: \${col};"></div>
1453
+ </div>
1454
+ </div>
1455
+ \`;
1456
+ }).join('');
1457
+ }
1458
+
1459
+ function renderToolChart(timeline) {
1460
+ const ctx = document.getElementById('toolChart').getContext('2d');
1461
+ const labels = timeline.map(t => t.date.split('-').slice(1).join('/'));
1462
+
1463
+ if (toolChart) toolChart.destroy();
1464
+
1465
+ toolChart = new Chart(ctx, {
1466
+ type: 'bar',
1467
+ data: {
1468
+ labels: labels,
1469
+ datasets: [
1470
+ {
1471
+ label: 'Success',
1472
+ data: timeline.map(t => t.toolSuccess || 0),
1473
+ backgroundColor: 'rgba(16, 185, 129, 0.75)',
1474
+ borderRadius: 4
1475
+ },
1476
+ {
1477
+ label: 'Failed',
1478
+ data: timeline.map(t => t.toolFailure || 0),
1479
+ backgroundColor: 'rgba(244, 63, 94, 0.75)',
1480
+ borderRadius: 4
1481
+ },
1482
+ {
1483
+ label: 'Denied',
1484
+ data: timeline.map(t => t.toolDenied || 0),
1485
+ backgroundColor: 'rgba(245, 158, 11, 0.75)',
1486
+ borderRadius: 4
1487
+ }
1488
+ ]
1489
+ },
1490
+ options: {
1491
+ responsive: true,
1492
+ maintainAspectRatio: false,
1493
+ scales: {
1494
+ x: { stacked: true, grid: { display: false } },
1495
+ y: { stacked: true, grid: { color: 'rgba(255, 255, 255, 0.05)' } }
1496
+ },
1497
+ plugins: {
1498
+ legend: { position: 'bottom' }
1499
+ }
1500
+ }
1501
+ });
1502
+ }
1503
+
1504
+ function renderCodeChart(timeline) {
1505
+ const ctx = document.getElementById('codeChart').getContext('2d');
1506
+ const labels = timeline.map(t => t.date.split('-').slice(1).join('/'));
1507
+
1508
+ if (codeChart) codeChart.destroy();
1509
+
1510
+ codeChart = new Chart(ctx, {
1511
+ type: 'bar',
1512
+ data: {
1513
+ labels: labels,
1514
+ datasets: [
1515
+ {
1516
+ label: 'Lines Added (+)',
1517
+ data: timeline.map(t => t.linesAdded || 0),
1518
+ backgroundColor: 'rgba(56, 189, 248, 0.85)',
1519
+ borderRadius: { topLeft: 4, topRight: 4, bottomLeft: 0, bottomRight: 0 },
1520
+ stack: 'codeStack'
1521
+ },
1522
+ {
1523
+ label: 'Lines Removed (-)',
1524
+ data: timeline.map(t => -(t.linesRemoved || 0)),
1525
+ backgroundColor: 'rgba(244, 63, 94, 0.85)',
1526
+ borderRadius: { topLeft: 0, topRight: 0, bottomLeft: 4, bottomRight: 4 },
1527
+ stack: 'codeStack'
1528
+ }
1529
+ ]
1530
+ },
1531
+ options: {
1532
+ responsive: true,
1533
+ maintainAspectRatio: false,
1534
+ scales: {
1535
+ x: {
1536
+ stacked: true,
1537
+ grid: { display: false },
1538
+ ticks: { color: '#64748b' }
1539
+ },
1540
+ y: {
1541
+ stacked: true,
1542
+ grid: {
1543
+ color: function(context) {
1544
+ if (context.tick && context.tick.value === 0) {
1545
+ return 'rgba(255, 255, 255, 0.25)';
1546
+ }
1547
+ return 'rgba(255, 255, 255, 0.05)';
1548
+ }
1549
+ },
1550
+ ticks: {
1551
+ color: '#64748b',
1552
+ callback: function(val) {
1553
+ const abs = Math.abs(val);
1554
+ if (abs === 0) return '0';
1555
+ return (val > 0 ? '+' : '-') + formatNumber(abs);
1556
+ }
1557
+ }
1558
+ }
1559
+ },
1560
+ plugins: {
1561
+ legend: {
1562
+ position: 'bottom',
1563
+ labels: { color: '#94a3b8', boxWidth: 12, font: { family: 'Plus Jakarta Sans', size: 11, weight: '600' } }
1564
+ },
1565
+ tooltip: {
1566
+ callbacks: {
1567
+ label: function(context) {
1568
+ const val = context.raw;
1569
+ const abs = Math.abs(val);
1570
+ return (context.dataset.label || '') + ': ' + (val >= 0 ? '+' : '-') + abs.toLocaleString() + ' lines';
1571
+ }
1572
+ }
1573
+ }
1574
+ }
1575
+ }
1576
+ });
1577
+ }
1578
+
1579
+ function getSortIndicator(field, currentField, currentOrder) {
1580
+ if (field !== currentField) {
1581
+ return '<span class="sort-icon" style="opacity: 0.35;">\u21C5</span>';
1582
+ }
1583
+ return currentOrder === 'asc'
1584
+ ? '<span class="sort-icon" style="color: var(--accent-cyan); opacity: 1; font-weight: bold;">\u2191</span>'
1585
+ : '<span class="sort-icon" style="color: var(--accent-cyan); opacity: 1; font-weight: bold;">\u2193</span>';
1586
+ }
1587
+
1588
+ window.handleSort = function(field) {
1589
+ if (tableMode === 'daily') {
1590
+ if (dailySortField === field) {
1591
+ dailySortOrder = dailySortOrder === 'asc' ? 'desc' : 'asc';
1592
+ } else {
1593
+ dailySortField = field;
1594
+ dailySortOrder = (field === 'date') ? 'desc' : 'desc';
1595
+ }
1596
+ } else {
1597
+ if (modelSortField === field) {
1598
+ modelSortOrder = modelSortOrder === 'asc' ? 'desc' : 'asc';
1599
+ } else {
1600
+ modelSortField = field;
1601
+ modelSortOrder = (field === 'model' || field === 'provider') ? 'asc' : 'desc';
1602
+ }
1603
+ }
1604
+ if (rawData && rawData.timeline) {
1605
+ renderTable(filterTimelineByRange(rawData.timeline, activeRange));
1606
+ }
1607
+ };
1608
+
1609
+ function renderTable(timeline) {
1610
+ const thead = document.getElementById('usage-table-head');
1611
+ const tbody = document.getElementById('usage-table-body');
1612
+ const titleEl = document.getElementById('table-view-title');
1613
+ const subtitleEl = document.getElementById('table-view-subtitle');
1614
+ const searchInput = document.getElementById('table-search');
1615
+ const filterText = (searchInput.value || '').toLowerCase();
1616
+
1617
+ if (tableMode === 'daily') {
1618
+ titleEl.textContent = 'Daily Detailed Token Records';
1619
+ subtitleEl.textContent = 'Itemized log of daily token counts, cache ratios, and tool operations (click headers to sort)';
1620
+ searchInput.placeholder = 'Filter by date...';
1621
+
1622
+ thead.innerHTML = \`
1623
+ <tr>
1624
+ <th class="sortable" onclick="handleSort('date')">Date \${getSortIndicator('date', dailySortField, dailySortOrder)}</th>
1625
+ <th class="sortable" onclick="handleSort('tokens')">Total Tokens \${getSortIndicator('tokens', dailySortField, dailySortOrder)}</th>
1626
+ <th class="sortable" onclick="handleSort('promptTokens')">Prompt (In) \${getSortIndicator('promptTokens', dailySortField, dailySortOrder)}</th>
1627
+ <th class="sortable" onclick="handleSort('candidateTokens')">Candidate (Out) \${getSortIndicator('candidateTokens', dailySortField, dailySortOrder)}</th>
1628
+ <th class="sortable" onclick="handleSort('cachedTokens')">Cached Tokens \${getSortIndicator('cachedTokens', dailySortField, dailySortOrder)}</th>
1629
+ <th class="sortable" onclick="handleSort('cachePct')">Cache % \${getSortIndicator('cachePct', dailySortField, dailySortOrder)}</th>
1630
+ <th class="sortable" onclick="handleSort('requests')">Requests \${getSortIndicator('requests', dailySortField, dailySortOrder)}</th>
1631
+ <th class="sortable" onclick="handleSort('toolSuccessRate')">Tool Success \${getSortIndicator('toolSuccessRate', dailySortField, dailySortOrder)}</th>
1632
+ <th class="sortable col-code" onclick="handleSort('linesAdded')">Code Lines \${getSortIndicator('linesAdded', dailySortField, dailySortOrder)}</th>
1633
+ </tr>
1634
+ \`;
1635
+
1636
+ let rows = [...timeline].filter(item => {
1637
+ return !filterText || item.date.toLowerCase().includes(filterText);
1638
+ });
1639
+
1640
+ rows.sort((a, b) => {
1641
+ let valA, valB;
1642
+ if (dailySortField === 'date') {
1643
+ valA = new Date(a.date).getTime();
1644
+ valB = new Date(b.date).getTime();
1645
+ } else if (dailySortField === 'requests') {
1646
+ valA = a.totalRequests || 0;
1647
+ valB = b.totalRequests || 0;
1648
+ } else if (dailySortField === 'cachePct') {
1649
+ valA = (a.promptTokens || 0) > 0 ? ((a.cachedTokens || 0) / (a.promptTokens || 1)) : 0;
1650
+ valB = (b.promptTokens || 0) > 0 ? ((b.cachedTokens || 0) / (b.promptTokens || 1)) : 0;
1651
+ } else if (dailySortField === 'linesAdded') {
1652
+ valA = (a.linesAdded || 0) - (a.linesRemoved || 0);
1653
+ valB = (b.linesAdded || 0) - (b.linesRemoved || 0);
1654
+ } else {
1655
+ valA = a[dailySortField] || 0;
1656
+ valB = b[dailySortField] || 0;
1657
+ }
1658
+ return dailySortOrder === 'asc' ? (valA > valB ? 1 : -1) : (valA < valB ? 1 : -1);
1659
+ });
1660
+
1661
+ if (rows.length === 0) {
1662
+ tbody.innerHTML = '<tr><td colspan="9" style="text-align: center; color: var(--text-dim); padding: 2rem;">No matching daily token records found.</td></tr>';
1663
+ return;
1664
+ }
1665
+
1666
+ tbody.innerHTML = rows.map(item => {
1667
+ const total = item.tokens || 0;
1668
+ const cached = item.cachedTokens || 0;
1669
+ const prompt = item.promptTokens || 0;
1670
+ const cand = item.candidateTokens || 0;
1671
+ const cachePct = prompt > 0 ? ((cached / prompt) * 100).toFixed(1) : '0.0';
1672
+
1673
+ return \`
1674
+ <tr>
1675
+ <td class="mono" style="font-weight: 600; color: var(--accent-cyan);">\${item.date}</td>
1676
+ <td class="mono" style="font-weight: 700;">\${formatNumber(total)}</td>
1677
+ <td class="mono" style="color: var(--accent-emerald);">\${formatNumber(prompt)}</td>
1678
+ <td class="mono" style="color: var(--accent-violet);">\${formatNumber(cand)}</td>
1679
+ <td class="mono" style="color: #059669;">\${formatNumber(cached)}</td>
1680
+ <td>
1681
+ <span class="badge-positive" style="font-size: 0.75rem;">\${cachePct}%</span>
1682
+ </td>
1683
+ <td>\${item.totalRequests || 0} req</td>
1684
+ <td>
1685
+ <span class="badge-info" style="font-size: 0.75rem;">\${item.toolSuccessRate}%</span>
1686
+ </td>
1687
+ <td class="mono col-code">
1688
+ <span style="color: #38bdf8;">+\${formatNumber(item.linesAdded)}</span> /
1689
+ <span style="color: #f43f5e;">-\${formatNumber(item.linesRemoved)}</span>
1690
+ </td>
1691
+ </tr>
1692
+ \`;
1693
+ }).join('');
1694
+ } else {
1695
+ titleEl.textContent = 'Model Token Statistics';
1696
+ subtitleEl.textContent = 'Aggregated token distribution, cache performance and share per model (click headers to sort)';
1697
+ searchInput.placeholder = 'Filter by model or provider...';
1698
+
1699
+ thead.innerHTML = \`
1700
+ <tr>
1701
+ <th class="sortable" onclick="handleSort('model')">Model Name \${getSortIndicator('model', modelSortField, modelSortOrder)}</th>
1702
+ <th class="sortable" onclick="handleSort('provider')">Provider \${getSortIndicator('provider', modelSortField, modelSortOrder)}</th>
1703
+ <th class="sortable" onclick="handleSort('tokens')">Total Tokens \${getSortIndicator('tokens', modelSortField, modelSortOrder)}</th>
1704
+ <th class="sortable" onclick="handleSort('promptTokens')">Prompt (In) \${getSortIndicator('promptTokens', modelSortField, modelSortOrder)}</th>
1705
+ <th class="sortable" onclick="handleSort('candidateTokens')">Candidate (Out) \${getSortIndicator('candidateTokens', modelSortField, modelSortOrder)}</th>
1706
+ <th class="sortable" onclick="handleSort('cachedTokens')">Cached Tokens \${getSortIndicator('cachedTokens', modelSortField, modelSortOrder)}</th>
1707
+ <th class="sortable" onclick="handleSort('cachePct')">Cache % \${getSortIndicator('cachePct', modelSortField, modelSortOrder)}</th>
1708
+ <th class="sortable" onclick="handleSort('sharePct')">Token Share \${getSortIndicator('sharePct', modelSortField, modelSortOrder)}</th>
1709
+ </tr>
1710
+ \`;
1711
+
1712
+ const modelMap = {};
1713
+ let aggregateTokens = 0;
1714
+
1715
+ timeline.forEach(day => {
1716
+ const models = day.models || {};
1717
+ for (const prov in models) {
1718
+ for (const m in models[prov]) {
1719
+ const entry = models[prov][m] || {};
1720
+ const key = prov + '___' + m;
1721
+ if (!modelMap[key]) {
1722
+ modelMap[key] = {
1723
+ model: m,
1724
+ provider: prov,
1725
+ tokens: 0,
1726
+ promptTokens: 0,
1727
+ candidateTokens: 0,
1728
+ cachedTokens: 0
1729
+ };
1730
+ }
1731
+ const tTok = entry.tokens || 0;
1732
+ const tCand = entry.candidateTokens || 0;
1733
+ const tPrompt = (entry.promptTokens !== undefined && entry.promptTokens !== null)
1734
+ ? entry.promptTokens
1735
+ : Math.max(0, tTok - tCand);
1736
+ const tCache = entry.cachedTokens || 0;
1737
+
1738
+ modelMap[key].tokens += tTok;
1739
+ modelMap[key].promptTokens += tPrompt;
1740
+ modelMap[key].candidateTokens += tCand;
1741
+ modelMap[key].cachedTokens += tCache;
1742
+ aggregateTokens += tTok;
1743
+ }
1744
+ }
1745
+ });
1746
+
1747
+ let modelList = Object.values(modelMap).map(item => {
1748
+ const cachePct = item.promptTokens > 0
1749
+ ? ((item.cachedTokens / item.promptTokens) * 100).toFixed(1)
1750
+ : (item.tokens > 0 ? ((item.cachedTokens / item.tokens) * 100).toFixed(1) : '0.0');
1751
+ const sharePct = aggregateTokens > 0 ? ((item.tokens / aggregateTokens) * 100).toFixed(1) : '0.0';
1752
+ return {
1753
+ ...item,
1754
+ cachePct: parseFloat(cachePct),
1755
+ sharePct: parseFloat(sharePct)
1756
+ };
1757
+ });
1758
+
1759
+ modelList.sort((a, b) => {
1760
+ let valA = a[modelSortField];
1761
+ let valB = b[modelSortField];
1762
+ if (modelSortField === 'model' || modelSortField === 'provider') {
1763
+ valA = (valA || '').toLowerCase();
1764
+ valB = (valB || '').toLowerCase();
1765
+ return modelSortOrder === 'asc' ? valA.localeCompare(valB) : valB.localeCompare(valA);
1766
+ } else {
1767
+ valA = valA || 0;
1768
+ valB = valB || 0;
1769
+ return modelSortOrder === 'asc' ? (valA > valB ? 1 : -1) : (valA < valB ? 1 : -1);
1770
+ }
1771
+ });
1772
+
1773
+ if (filterText) {
1774
+ modelList = modelList.filter(m => {
1775
+ return m.model.toLowerCase().includes(filterText) || m.provider.toLowerCase().includes(filterText);
1776
+ });
1777
+ }
1778
+
1779
+ if (modelList.length === 0) {
1780
+ tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; color: var(--text-dim); padding: 2rem;">No matching models found.</td></tr>';
1781
+ return;
1782
+ }
1783
+
1784
+ tbody.innerHTML = modelList.map(m => {
1785
+ return \`
1786
+ <tr>
1787
+ <td class="mono" style="font-weight: 600; color: var(--text-main);">
1788
+ <span style="display: inline-flex; align-items: center; gap: 8px;">
1789
+ \${getProviderBrandIcon(m.provider, 16)}
1790
+ <span>\${m.model}</span>
1791
+ </span>
1792
+ </td>
1793
+ <td>
1794
+ <span class="badge-info" style="font-size: 0.75rem; display: inline-flex; align-items: center; gap: 5px;">
1795
+ \${m.provider}
1796
+ </span>
1797
+ </td>
1798
+ <td class="mono" style="font-weight: 700; color: var(--text-main);">\${formatNumber(m.tokens)}</td>
1799
+ <td class="mono" style="color: var(--accent-emerald);">\${formatNumber(m.promptTokens)}</td>
1800
+ <td class="mono" style="color: var(--accent-violet);">\${formatNumber(m.candidateTokens)}</td>
1801
+ <td class="mono" style="color: #059669;">\${formatNumber(m.cachedTokens)}</td>
1802
+ <td>
1803
+ <span class="badge-positive" style="font-size: 0.75rem;">\${m.cachePct}%</span>
1804
+ </td>
1805
+ <td>
1806
+ <div style="display: flex; align-items: center; gap: 8px;">
1807
+ <div style="flex: 1; min-width: 60px; height: 6px; background: rgba(255,255,255,0.06); border-radius: 999px; overflow: hidden;">
1808
+ <div style="width: \${m.sharePct}%; height: 100%; background: linear-gradient(90deg, #38bdf8, #a855f7); border-radius: 999px;"></div>
1809
+ </div>
1810
+ <span class="mono" style="font-size: 0.75rem; color: var(--text-muted); min-width: 38px;">\${m.sharePct}%</span>
1811
+ </div>
1812
+ </td>
1813
+ </tr>
1814
+ \`;
1815
+ }).join('');
1816
+ }
1817
+ }
1818
+
1819
+ function exportJson() {
1820
+ if (!rawData) return;
1821
+ const blob = new Blob([JSON.stringify(rawData, null, 2)], { type: 'application/json' });
1822
+ const url = URL.createObjectURL(blob);
1823
+ const a = document.createElement('a');
1824
+ a.href = url;
1825
+ a.download = \`fluxflow-token-usage-\${new Date().toISOString().split('T')[0]}.json\`;
1826
+ a.click();
1827
+ URL.revokeObjectURL(url);
1828
+ }
1829
+
1830
+ function exportCsv() {
1831
+ if (!rawData || !rawData.timeline) return;
1832
+ const headers = ['Date', 'TotalTokens', 'PromptTokens', 'CandidateTokens', 'CachedTokens', 'CachePercent', 'AgentRequests', 'BackgroundRequests', 'SearchRequests', 'ToolSuccess', 'ToolFailure', 'ToolDenied', 'LinesAdded', 'LinesRemoved'];
1833
+ const csvRows = [headers.join(',')];
1834
+
1835
+ rawData.timeline.forEach(t => {
1836
+ const total = t.tokens || 0;
1837
+ const cached = t.cachedTokens || 0;
1838
+ const cachePct = total > 0 ? ((cached / total) * 100).toFixed(1) : '0.0';
1839
+ const row = [
1840
+ t.date,
1841
+ total,
1842
+ t.promptTokens || 0,
1843
+ t.candidateTokens || 0,
1844
+ cached,
1845
+ cachePct,
1846
+ t.agent || 0,
1847
+ t.background || 0,
1848
+ t.search || 0,
1849
+ t.toolSuccess || 0,
1850
+ t.toolFailure || 0,
1851
+ t.toolDenied || 0,
1852
+ t.linesAdded || 0,
1853
+ t.linesRemoved || 0
1854
+ ];
1855
+ csvRows.push(row.join(','));
1856
+ });
1857
+
1858
+ const blob = new Blob([csvRows.join('\\n')], { type: 'text/csv' });
1859
+ const url = URL.createObjectURL(blob);
1860
+ const a = document.createElement('a');
1861
+ a.href = url;
1862
+ a.download = \`fluxflow-token-usage-\${new Date().toISOString().split('T')[0]}.csv\`;
1863
+ a.click();
1864
+ URL.revokeObjectURL(url);
1865
+ }
1866
+
1867
+ document.querySelectorAll('#range-tabs .tab-btn').forEach(btn => {
1868
+ btn.addEventListener('click', (e) => {
1869
+ document.querySelectorAll('#range-tabs .tab-btn').forEach(b => b.classList.remove('active'));
1870
+ btn.classList.add('active');
1871
+ activeRange = btn.dataset.range;
1872
+ renderDashboard();
1873
+ });
1874
+ });
1875
+
1876
+ document.querySelectorAll('#table-mode-tabs .tab-btn').forEach(btn => {
1877
+ btn.addEventListener('click', (e) => {
1878
+ document.querySelectorAll('#table-mode-tabs .tab-btn').forEach(b => b.classList.remove('active'));
1879
+ btn.classList.add('active');
1880
+ tableMode = btn.dataset.tableMode;
1881
+ if (rawData && rawData.timeline) {
1882
+ renderTable(filterTimelineByRange(rawData.timeline, activeRange));
1883
+ }
1884
+ });
1885
+ });
1886
+
1887
+ document.querySelectorAll('.chart-btn').forEach(btn => {
1888
+ btn.addEventListener('click', () => {
1889
+ document.querySelectorAll('.chart-btn').forEach(b => b.classList.remove('active'));
1890
+ btn.classList.add('active');
1891
+ chartType = btn.dataset.chartType;
1892
+ if (rawData && rawData.timeline) {
1893
+ renderTimelineChart(filterTimelineByRange(rawData.timeline, activeRange));
1894
+ }
1895
+ });
1896
+ });
1897
+
1898
+ document.getElementById('btn-refresh').addEventListener('click', fetchData);
1899
+ document.getElementById('btn-export-json').addEventListener('click', exportJson);
1900
+ document.getElementById('btn-export-csv').addEventListener('click', exportCsv);
1901
+ document.getElementById('table-search').addEventListener('input', () => {
1902
+ if (rawData && rawData.timeline) {
1903
+ renderTable(filterTimelineByRange(rawData.timeline, activeRange));
1904
+ }
1905
+ });
1906
+
1907
+ setInterval(() => {
1908
+ if (document.getElementById('auto-refresh-check').checked) {
1909
+ fetchData();
1910
+ }
1911
+ }, 60000);
1912
+
1913
+ fetchData();
1914
+ </script>
1915
+ </body>
1916
+ </html>`}async function w(t=52140){if(m&&n)return{port:n,url:`http://localhost:${n}`,isNew:!1};let r=b.createServer(async(a,e)=>{if(e.setHeader("Access-Control-Allow-Origin","*"),e.setHeader("Access-Control-Allow-Methods","GET, OPTIONS"),a.method==="OPTIONS"){e.writeHead(204),e.end();return}let i=new URL(a.url,`http://${a.headers.host||"localhost"}`);if(i.pathname==="/api/usage"){try{let A=await v();e.writeHead(200,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(A))}catch(A){e.writeHead(500,{"Content-Type":"application/json"}),e.end(JSON.stringify({error:A.message}))}return}if(i.pathname==="/"||i.pathname==="/index.html"||i.pathname==="/usage"){let A=u();e.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),e.end(A);return}e.writeHead(404,{"Content-Type":"text/plain"}),e.end("Not Found")}),o=await(a=>new Promise((e,i)=>{let A=d=>{r.once("error",c=>{c.code==="EADDRINUSE"?A(d+1):i(c)}),r.listen(d,"127.0.0.1",()=>{m=r,n=d,e(d)})};A(a)}))(t),l=`http://localhost:${o}`;return{port:o,url:l,isNew:!0}}async function D(t=52140){let{url:r,isNew:s}=await w(t),o=process.platform,l=o==="win32"?"start":o==="darwin"?"open":"xdg-open";try{p(`${l} ${r}`)}catch{}return{url:r,port:n,isNew:s}}export{w as a,D as b};