claude-code-templates 1.5.2 → 1.5.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.
- package/package.json +1 -1
- package/src/analytics.js +248 -164
package/package.json
CHANGED
package/src/analytics.js
CHANGED
|
@@ -445,7 +445,7 @@ async function createWebDashboard() {
|
|
|
445
445
|
<head>
|
|
446
446
|
<meta charset="UTF-8">
|
|
447
447
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
448
|
-
<title>Claude Code Analytics
|
|
448
|
+
<title>Claude Code Analytics - Terminal</title>
|
|
449
449
|
<style>
|
|
450
450
|
* {
|
|
451
451
|
margin: 0;
|
|
@@ -454,234 +454,292 @@ async function createWebDashboard() {
|
|
|
454
454
|
}
|
|
455
455
|
|
|
456
456
|
body {
|
|
457
|
-
font-family:
|
|
458
|
-
background:
|
|
459
|
-
color: #
|
|
457
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
458
|
+
background: #0d1117;
|
|
459
|
+
color: #c9d1d9;
|
|
460
460
|
min-height: 100vh;
|
|
461
|
+
line-height: 1.4;
|
|
461
462
|
}
|
|
462
463
|
|
|
463
|
-
.
|
|
464
|
-
max-width:
|
|
464
|
+
.terminal {
|
|
465
|
+
max-width: 1400px;
|
|
465
466
|
margin: 0 auto;
|
|
466
467
|
padding: 20px;
|
|
467
468
|
}
|
|
468
469
|
|
|
469
|
-
.header {
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
margin-bottom:
|
|
470
|
+
.terminal-header {
|
|
471
|
+
border-bottom: 1px solid #30363d;
|
|
472
|
+
padding-bottom: 20px;
|
|
473
|
+
margin-bottom: 20px;
|
|
473
474
|
}
|
|
474
475
|
|
|
475
|
-
.
|
|
476
|
-
|
|
477
|
-
|
|
476
|
+
.terminal-title {
|
|
477
|
+
color: #58a6ff;
|
|
478
|
+
font-size: 1.25rem;
|
|
479
|
+
font-weight: normal;
|
|
480
|
+
display: flex;
|
|
481
|
+
align-items: center;
|
|
482
|
+
gap: 8px;
|
|
478
483
|
}
|
|
479
484
|
|
|
480
|
-
.status-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
height: 12px;
|
|
485
|
+
.status-dot {
|
|
486
|
+
width: 8px;
|
|
487
|
+
height: 8px;
|
|
484
488
|
border-radius: 50%;
|
|
485
|
-
background: #
|
|
489
|
+
background: #3fb950;
|
|
486
490
|
animation: pulse 2s infinite;
|
|
487
|
-
margin-right: 8px;
|
|
488
491
|
}
|
|
489
492
|
|
|
490
493
|
@keyframes pulse {
|
|
491
494
|
0%, 100% { opacity: 1; }
|
|
492
|
-
50% { opacity: 0.
|
|
495
|
+
50% { opacity: 0.6; }
|
|
493
496
|
}
|
|
494
497
|
|
|
495
|
-
.
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
margin-bottom: 30px;
|
|
498
|
+
.terminal-subtitle {
|
|
499
|
+
color: #7d8590;
|
|
500
|
+
font-size: 0.875rem;
|
|
501
|
+
margin-top: 4px;
|
|
500
502
|
}
|
|
501
503
|
|
|
502
|
-
.
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
transition: transform 0.2s ease;
|
|
504
|
+
.stats-bar {
|
|
505
|
+
display: flex;
|
|
506
|
+
gap: 40px;
|
|
507
|
+
margin: 20px 0;
|
|
508
|
+
flex-wrap: wrap;
|
|
508
509
|
}
|
|
509
510
|
|
|
510
|
-
.stat
|
|
511
|
-
|
|
511
|
+
.stat {
|
|
512
|
+
display: flex;
|
|
513
|
+
align-items: center;
|
|
514
|
+
gap: 8px;
|
|
512
515
|
}
|
|
513
516
|
|
|
514
|
-
.stat-
|
|
515
|
-
color: #
|
|
517
|
+
.stat-label {
|
|
518
|
+
color: #7d8590;
|
|
516
519
|
font-size: 0.875rem;
|
|
517
|
-
text-transform: uppercase;
|
|
518
|
-
letter-spacing: 0.05em;
|
|
519
|
-
margin-bottom: 8px;
|
|
520
520
|
}
|
|
521
521
|
|
|
522
|
-
.stat-
|
|
523
|
-
|
|
522
|
+
.stat-value {
|
|
523
|
+
color: #58a6ff;
|
|
524
524
|
font-weight: bold;
|
|
525
|
-
color: #1f2937;
|
|
526
|
-
margin-bottom: 4px;
|
|
527
525
|
}
|
|
528
526
|
|
|
529
|
-
.
|
|
530
|
-
|
|
527
|
+
.filter-bar {
|
|
528
|
+
display: flex;
|
|
529
|
+
align-items: center;
|
|
530
|
+
gap: 16px;
|
|
531
|
+
margin: 20px 0;
|
|
532
|
+
padding: 12px 0;
|
|
533
|
+
border-top: 1px solid #21262d;
|
|
534
|
+
border-bottom: 1px solid #21262d;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.filter-label {
|
|
538
|
+
color: #7d8590;
|
|
531
539
|
font-size: 0.875rem;
|
|
532
540
|
}
|
|
533
541
|
|
|
534
|
-
.
|
|
535
|
-
display:
|
|
536
|
-
|
|
537
|
-
gap: 20px;
|
|
542
|
+
.filter-buttons {
|
|
543
|
+
display: flex;
|
|
544
|
+
gap: 8px;
|
|
538
545
|
}
|
|
539
546
|
|
|
540
|
-
.
|
|
541
|
-
background:
|
|
542
|
-
border
|
|
543
|
-
|
|
544
|
-
|
|
547
|
+
.filter-btn {
|
|
548
|
+
background: none;
|
|
549
|
+
border: 1px solid #30363d;
|
|
550
|
+
color: #7d8590;
|
|
551
|
+
padding: 4px 12px;
|
|
552
|
+
border-radius: 4px;
|
|
553
|
+
cursor: pointer;
|
|
554
|
+
font-family: inherit;
|
|
555
|
+
font-size: 0.875rem;
|
|
556
|
+
transition: all 0.2s ease;
|
|
545
557
|
}
|
|
546
558
|
|
|
547
|
-
.
|
|
548
|
-
color: #
|
|
549
|
-
|
|
550
|
-
font-size: 1.25rem;
|
|
559
|
+
.filter-btn:hover {
|
|
560
|
+
border-color: #58a6ff;
|
|
561
|
+
color: #58a6ff;
|
|
551
562
|
}
|
|
552
563
|
|
|
553
|
-
.
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
564
|
+
.filter-btn.active {
|
|
565
|
+
background: #58a6ff;
|
|
566
|
+
border-color: #58a6ff;
|
|
567
|
+
color: #0d1117;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.sessions-table {
|
|
571
|
+
width: 100%;
|
|
572
|
+
border-collapse: collapse;
|
|
559
573
|
}
|
|
560
574
|
|
|
561
|
-
.
|
|
562
|
-
|
|
575
|
+
.sessions-table th {
|
|
576
|
+
text-align: left;
|
|
577
|
+
padding: 8px 12px;
|
|
578
|
+
color: #7d8590;
|
|
579
|
+
font-size: 0.875rem;
|
|
580
|
+
font-weight: normal;
|
|
581
|
+
border-bottom: 1px solid #30363d;
|
|
563
582
|
}
|
|
564
583
|
|
|
565
|
-
.
|
|
566
|
-
|
|
584
|
+
.sessions-table td {
|
|
585
|
+
padding: 8px 12px;
|
|
567
586
|
font-size: 0.875rem;
|
|
568
|
-
|
|
587
|
+
border-bottom: 1px solid #21262d;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
.sessions-table tr:hover {
|
|
591
|
+
background: #161b22;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.session-id {
|
|
595
|
+
color: #58a6ff;
|
|
596
|
+
font-family: monospace;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.session-project {
|
|
600
|
+
color: #c9d1d9;
|
|
569
601
|
}
|
|
570
602
|
|
|
571
|
-
.
|
|
572
|
-
color: #
|
|
573
|
-
font-size: 0.75rem;
|
|
603
|
+
.session-messages {
|
|
604
|
+
color: #7d8590;
|
|
574
605
|
}
|
|
575
606
|
|
|
576
|
-
.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
607
|
+
.session-tokens {
|
|
608
|
+
color: #f85149;
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
.session-time {
|
|
612
|
+
color: #7d8590;
|
|
613
|
+
font-size: 0.8rem;
|
|
581
614
|
}
|
|
582
615
|
|
|
583
616
|
.status-active {
|
|
584
|
-
|
|
585
|
-
|
|
617
|
+
color: #3fb950;
|
|
618
|
+
font-weight: bold;
|
|
586
619
|
}
|
|
587
620
|
|
|
588
621
|
.status-recent {
|
|
589
|
-
|
|
590
|
-
color: #92400e;
|
|
622
|
+
color: #d29922;
|
|
591
623
|
}
|
|
592
624
|
|
|
593
625
|
.status-inactive {
|
|
594
|
-
|
|
595
|
-
color: #6b7280;
|
|
626
|
+
color: #7d8590;
|
|
596
627
|
}
|
|
597
628
|
|
|
598
|
-
.loading {
|
|
629
|
+
.loading, .error {
|
|
599
630
|
text-align: center;
|
|
600
|
-
color: white;
|
|
601
631
|
padding: 40px;
|
|
632
|
+
color: #7d8590;
|
|
602
633
|
}
|
|
603
634
|
|
|
604
635
|
.error {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
636
|
+
color: #f85149;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.no-sessions {
|
|
640
|
+
text-align: center;
|
|
641
|
+
padding: 40px;
|
|
642
|
+
color: #7d8590;
|
|
643
|
+
font-style: italic;
|
|
610
644
|
}
|
|
611
645
|
|
|
612
646
|
@media (max-width: 768px) {
|
|
613
|
-
.
|
|
614
|
-
|
|
647
|
+
.stats-bar {
|
|
648
|
+
gap: 20px;
|
|
615
649
|
}
|
|
616
650
|
|
|
617
|
-
.
|
|
618
|
-
|
|
651
|
+
.filter-bar {
|
|
652
|
+
flex-direction: column;
|
|
653
|
+
align-items: flex-start;
|
|
654
|
+
gap: 8px;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.sessions-table {
|
|
658
|
+
font-size: 0.8rem;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.sessions-table th,
|
|
662
|
+
.sessions-table td {
|
|
663
|
+
padding: 6px 8px;
|
|
619
664
|
}
|
|
620
665
|
}
|
|
621
666
|
</style>
|
|
622
667
|
</head>
|
|
623
668
|
<body>
|
|
624
|
-
<div class="
|
|
625
|
-
<div class="header">
|
|
626
|
-
<
|
|
627
|
-
<span class="status-
|
|
628
|
-
|
|
629
|
-
</
|
|
630
|
-
<
|
|
631
|
-
<
|
|
669
|
+
<div class="terminal">
|
|
670
|
+
<div class="terminal-header">
|
|
671
|
+
<div class="terminal-title">
|
|
672
|
+
<span class="status-dot"></span>
|
|
673
|
+
claude-code-analytics
|
|
674
|
+
</div>
|
|
675
|
+
<div class="terminal-subtitle">real-time monitoring dashboard</div>
|
|
676
|
+
<div class="terminal-subtitle" id="lastUpdate"></div>
|
|
632
677
|
</div>
|
|
633
678
|
|
|
634
679
|
<div id="loading" class="loading">
|
|
635
|
-
|
|
680
|
+
loading claude code data...
|
|
636
681
|
</div>
|
|
637
682
|
|
|
638
683
|
<div id="error" class="error" style="display: none;">
|
|
639
|
-
|
|
684
|
+
error: failed to load claude code data
|
|
640
685
|
</div>
|
|
641
686
|
|
|
642
687
|
<div id="dashboard" style="display: none;">
|
|
643
|
-
<div class="stats-
|
|
644
|
-
<div class="stat
|
|
645
|
-
<
|
|
646
|
-
<
|
|
647
|
-
<div class="label">Conversations</div>
|
|
688
|
+
<div class="stats-bar">
|
|
689
|
+
<div class="stat">
|
|
690
|
+
<span class="stat-label">sessions:</span>
|
|
691
|
+
<span class="stat-value" id="totalSessions">0</span>
|
|
648
692
|
</div>
|
|
649
|
-
<div class="stat
|
|
650
|
-
<
|
|
651
|
-
<
|
|
652
|
-
<div class="label">Estimated</div>
|
|
693
|
+
<div class="stat">
|
|
694
|
+
<span class="stat-label">tokens:</span>
|
|
695
|
+
<span class="stat-value" id="totalTokens">0</span>
|
|
653
696
|
</div>
|
|
654
|
-
<div class="stat
|
|
655
|
-
<
|
|
656
|
-
<
|
|
657
|
-
<div class="label">Currently</div>
|
|
697
|
+
<div class="stat">
|
|
698
|
+
<span class="stat-label">projects:</span>
|
|
699
|
+
<span class="stat-value" id="activeProjects">0</span>
|
|
658
700
|
</div>
|
|
659
|
-
<div class="stat
|
|
660
|
-
<
|
|
661
|
-
<
|
|
662
|
-
<div class="label">Total</div>
|
|
701
|
+
<div class="stat">
|
|
702
|
+
<span class="stat-label">storage:</span>
|
|
703
|
+
<span class="stat-value" id="dataSize">0</span>
|
|
663
704
|
</div>
|
|
664
705
|
</div>
|
|
665
706
|
|
|
666
|
-
<div class="
|
|
667
|
-
<
|
|
668
|
-
|
|
669
|
-
<
|
|
670
|
-
|
|
671
|
-
</
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
<div class="panel">
|
|
675
|
-
<h2>Active Projects</h2>
|
|
676
|
-
<div id="projects">
|
|
677
|
-
<!-- Projects will be loaded here -->
|
|
678
|
-
</div>
|
|
707
|
+
<div class="filter-bar">
|
|
708
|
+
<span class="filter-label">filter sessions:</span>
|
|
709
|
+
<div class="filter-buttons">
|
|
710
|
+
<button class="filter-btn active" data-filter="active">active</button>
|
|
711
|
+
<button class="filter-btn" data-filter="recent">recent</button>
|
|
712
|
+
<button class="filter-btn" data-filter="inactive">inactive</button>
|
|
713
|
+
<button class="filter-btn" data-filter="all">all</button>
|
|
679
714
|
</div>
|
|
680
715
|
</div>
|
|
716
|
+
|
|
717
|
+
<table class="sessions-table">
|
|
718
|
+
<thead>
|
|
719
|
+
<tr>
|
|
720
|
+
<th>session id</th>
|
|
721
|
+
<th>project</th>
|
|
722
|
+
<th>messages</th>
|
|
723
|
+
<th>tokens</th>
|
|
724
|
+
<th>last activity</th>
|
|
725
|
+
<th>status</th>
|
|
726
|
+
</tr>
|
|
727
|
+
</thead>
|
|
728
|
+
<tbody id="sessionsTable">
|
|
729
|
+
<!-- Sessions will be loaded here -->
|
|
730
|
+
</tbody>
|
|
731
|
+
</table>
|
|
732
|
+
|
|
733
|
+
<div id="noSessions" class="no-sessions" style="display: none;">
|
|
734
|
+
no sessions found for current filter
|
|
735
|
+
</div>
|
|
681
736
|
</div>
|
|
682
737
|
</div>
|
|
683
738
|
|
|
684
739
|
<script>
|
|
740
|
+
let allConversations = [];
|
|
741
|
+
let currentFilter = 'active';
|
|
742
|
+
|
|
685
743
|
async function loadData() {
|
|
686
744
|
try {
|
|
687
745
|
const response = await fetch('/api/data');
|
|
@@ -694,11 +752,11 @@ async function createWebDashboard() {
|
|
|
694
752
|
|
|
695
753
|
// Update timestamp
|
|
696
754
|
document.getElementById('lastUpdate').textContent =
|
|
697
|
-
\`
|
|
755
|
+
\`last update: \${data.lastUpdate}\`;
|
|
698
756
|
|
|
699
757
|
updateStats(data.summary);
|
|
700
|
-
|
|
701
|
-
|
|
758
|
+
allConversations = data.conversations;
|
|
759
|
+
updateSessionsTable();
|
|
702
760
|
|
|
703
761
|
} catch (error) {
|
|
704
762
|
document.getElementById('loading').style.display = 'none';
|
|
@@ -714,44 +772,70 @@ async function createWebDashboard() {
|
|
|
714
772
|
document.getElementById('dataSize').textContent = summary.totalFileSize;
|
|
715
773
|
}
|
|
716
774
|
|
|
717
|
-
function
|
|
718
|
-
const
|
|
775
|
+
function updateSessionsTable() {
|
|
776
|
+
const tableBody = document.getElementById('sessionsTable');
|
|
777
|
+
const noSessionsDiv = document.getElementById('noSessions');
|
|
778
|
+
|
|
779
|
+
// Filter conversations based on current filter
|
|
780
|
+
let filteredConversations = allConversations;
|
|
781
|
+
if (currentFilter !== 'all') {
|
|
782
|
+
filteredConversations = allConversations.filter(conv => conv.status === currentFilter);
|
|
783
|
+
}
|
|
719
784
|
|
|
720
|
-
if (
|
|
721
|
-
|
|
785
|
+
if (filteredConversations.length === 0) {
|
|
786
|
+
tableBody.innerHTML = '';
|
|
787
|
+
noSessionsDiv.style.display = 'block';
|
|
722
788
|
return;
|
|
723
789
|
}
|
|
724
790
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
</
|
|
731
|
-
<
|
|
732
|
-
|
|
791
|
+
noSessionsDiv.style.display = 'none';
|
|
792
|
+
|
|
793
|
+
tableBody.innerHTML = filteredConversations.map(conv => \`
|
|
794
|
+
<tr>
|
|
795
|
+
<td class="session-id">\${conv.id.substring(0, 8)}...</td>
|
|
796
|
+
<td class="session-project">\${conv.project}</td>
|
|
797
|
+
<td class="session-messages">\${conv.messageCount}</td>
|
|
798
|
+
<td class="session-tokens">\${conv.tokens.toLocaleString()}</td>
|
|
799
|
+
<td class="session-time">\${formatTime(conv.lastModified)}</td>
|
|
800
|
+
<td class="status-\${conv.status}">\${conv.status}</td>
|
|
801
|
+
</tr>
|
|
733
802
|
\`).join('');
|
|
734
803
|
}
|
|
735
804
|
|
|
736
|
-
function
|
|
737
|
-
const
|
|
805
|
+
function formatTime(date) {
|
|
806
|
+
const now = new Date();
|
|
807
|
+
const diff = now - new Date(date);
|
|
808
|
+
const minutes = Math.floor(diff / (1000 * 60));
|
|
809
|
+
const hours = Math.floor(minutes / 60);
|
|
810
|
+
const days = Math.floor(hours / 24);
|
|
738
811
|
|
|
739
|
-
if (
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
container.innerHTML = projects.slice(0, 10).map(project => \`
|
|
745
|
-
<div class="project-item">
|
|
746
|
-
<div class="item-info">
|
|
747
|
-
<h4>\${project.name}</h4>
|
|
748
|
-
<p>\${project.todoFiles} todo files</p>
|
|
749
|
-
</div>
|
|
750
|
-
<span class="status-badge status-\${project.status}">\${project.status}</span>
|
|
751
|
-
</div>
|
|
752
|
-
\`).join('');
|
|
812
|
+
if (minutes < 1) return 'now';
|
|
813
|
+
if (minutes < 60) return \`\${minutes}m ago\`;
|
|
814
|
+
if (hours < 24) return \`\${hours}h ago\`;
|
|
815
|
+
return \`\${days}d ago\`;
|
|
753
816
|
}
|
|
754
817
|
|
|
818
|
+
// Filter button handlers
|
|
819
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
820
|
+
const filterButtons = document.querySelectorAll('.filter-btn');
|
|
821
|
+
|
|
822
|
+
filterButtons.forEach(button => {
|
|
823
|
+
button.addEventListener('click', function() {
|
|
824
|
+
// Remove active class from all buttons
|
|
825
|
+
filterButtons.forEach(btn => btn.classList.remove('active'));
|
|
826
|
+
|
|
827
|
+
// Add active class to clicked button
|
|
828
|
+
this.classList.add('active');
|
|
829
|
+
|
|
830
|
+
// Update current filter
|
|
831
|
+
currentFilter = this.dataset.filter;
|
|
832
|
+
|
|
833
|
+
// Update table
|
|
834
|
+
updateSessionsTable();
|
|
835
|
+
});
|
|
836
|
+
});
|
|
837
|
+
});
|
|
838
|
+
|
|
755
839
|
// Manual refresh function
|
|
756
840
|
async function forceRefresh() {
|
|
757
841
|
try {
|