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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/analytics.js +248 -164
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
5
5
  "main": "src/index.js",
6
6
  "bin": {
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 Dashboard</title>
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: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
458
- background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
459
- color: #333;
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
- .container {
464
- max-width: 1200px;
464
+ .terminal {
465
+ max-width: 1400px;
465
466
  margin: 0 auto;
466
467
  padding: 20px;
467
468
  }
468
469
 
469
- .header {
470
- text-align: center;
471
- color: white;
472
- margin-bottom: 30px;
470
+ .terminal-header {
471
+ border-bottom: 1px solid #30363d;
472
+ padding-bottom: 20px;
473
+ margin-bottom: 20px;
473
474
  }
474
475
 
475
- .header h1 {
476
- font-size: 2.5rem;
477
- margin-bottom: 10px;
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-indicator {
481
- display: inline-block;
482
- width: 12px;
483
- height: 12px;
485
+ .status-dot {
486
+ width: 8px;
487
+ height: 8px;
484
488
  border-radius: 50%;
485
- background: #4ade80;
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.5; }
495
+ 50% { opacity: 0.6; }
493
496
  }
494
497
 
495
- .stats-grid {
496
- display: grid;
497
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
498
- gap: 20px;
499
- margin-bottom: 30px;
498
+ .terminal-subtitle {
499
+ color: #7d8590;
500
+ font-size: 0.875rem;
501
+ margin-top: 4px;
500
502
  }
501
503
 
502
- .stat-card {
503
- background: white;
504
- border-radius: 12px;
505
- padding: 24px;
506
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
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-card:hover {
511
- transform: translateY(-2px);
511
+ .stat {
512
+ display: flex;
513
+ align-items: center;
514
+ gap: 8px;
512
515
  }
513
516
 
514
- .stat-card h3 {
515
- color: #6b7280;
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-card .value {
523
- font-size: 2rem;
522
+ .stat-value {
523
+ color: #58a6ff;
524
524
  font-weight: bold;
525
- color: #1f2937;
526
- margin-bottom: 4px;
527
525
  }
528
526
 
529
- .stat-card .label {
530
- color: #9ca3af;
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
- .content-grid {
535
- display: grid;
536
- grid-template-columns: 1fr 1fr;
537
- gap: 20px;
542
+ .filter-buttons {
543
+ display: flex;
544
+ gap: 8px;
538
545
  }
539
546
 
540
- .panel {
541
- background: white;
542
- border-radius: 12px;
543
- padding: 24px;
544
- box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
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
- .panel h2 {
548
- color: #1f2937;
549
- margin-bottom: 20px;
550
- font-size: 1.25rem;
559
+ .filter-btn:hover {
560
+ border-color: #58a6ff;
561
+ color: #58a6ff;
551
562
  }
552
563
 
553
- .conversation-item, .project-item {
554
- display: flex;
555
- justify-content: space-between;
556
- align-items: center;
557
- padding: 12px 0;
558
- border-bottom: 1px solid #f3f4f6;
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
- .conversation-item:last-child, .project-item:last-child {
562
- border-bottom: none;
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
- .item-info h4 {
566
- color: #1f2937;
584
+ .sessions-table td {
585
+ padding: 8px 12px;
567
586
  font-size: 0.875rem;
568
- margin-bottom: 4px;
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
- .item-info p {
572
- color: #6b7280;
573
- font-size: 0.75rem;
603
+ .session-messages {
604
+ color: #7d8590;
574
605
  }
575
606
 
576
- .status-badge {
577
- padding: 4px 8px;
578
- border-radius: 12px;
579
- font-size: 0.75rem;
580
- font-weight: 500;
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
- background: #d1fae5;
585
- color: #065f46;
617
+ color: #3fb950;
618
+ font-weight: bold;
586
619
  }
587
620
 
588
621
  .status-recent {
589
- background: #fef3c7;
590
- color: #92400e;
622
+ color: #d29922;
591
623
  }
592
624
 
593
625
  .status-inactive {
594
- background: #f3f4f6;
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
- background: #fef2f2;
606
- color: #dc2626;
607
- padding: 16px;
608
- border-radius: 8px;
609
- margin: 20px 0;
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
- .content-grid {
614
- grid-template-columns: 1fr;
647
+ .stats-bar {
648
+ gap: 20px;
615
649
  }
616
650
 
617
- .header h1 {
618
- font-size: 2rem;
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="container">
625
- <div class="header">
626
- <h1>
627
- <span class="status-indicator"></span>
628
- Claude Code Analytics
629
- </h1>
630
- <p>Real-time monitoring of your Claude Code usage</p>
631
- <p id="lastUpdate" style="font-size: 0.75rem; opacity: 0.8;"></p>
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
- <p>Loading analytics data...</p>
680
+ loading claude code data...
636
681
  </div>
637
682
 
638
683
  <div id="error" class="error" style="display: none;">
639
- <p>Failed to load analytics data. Please check if Claude Code is installed.</p>
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-grid">
644
- <div class="stat-card">
645
- <h3>Total Sessions</h3>
646
- <div class="value" id="totalSessions">0</div>
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-card">
650
- <h3>Total Tokens</h3>
651
- <div class="value" id="totalTokens">0</div>
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-card">
655
- <h3>Active Projects</h3>
656
- <div class="value" id="activeProjects">0</div>
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-card">
660
- <h3>Data Size</h3>
661
- <div class="value" id="dataSize">0</div>
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="content-grid">
667
- <div class="panel">
668
- <h2>Recent Conversations</h2>
669
- <div id="conversations">
670
- <!-- Conversations will be loaded here -->
671
- </div>
672
- </div>
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
- \`Last updated: \${data.lastUpdate}\`;
755
+ \`last update: \${data.lastUpdate}\`;
698
756
 
699
757
  updateStats(data.summary);
700
- updateConversations(data.conversations);
701
- updateProjects(data.activeProjects);
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 updateConversations(conversations) {
718
- const container = document.getElementById('conversations');
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 (conversations.length === 0) {
721
- container.innerHTML = '<p style="color: #6b7280; text-align: center; padding: 20px;">No conversations found</p>';
785
+ if (filteredConversations.length === 0) {
786
+ tableBody.innerHTML = '';
787
+ noSessionsDiv.style.display = 'block';
722
788
  return;
723
789
  }
724
790
 
725
- container.innerHTML = conversations.slice(0, 10).map(conv => \`
726
- <div class="conversation-item">
727
- <div class="item-info">
728
- <h4>\${conv.project}</h4>
729
- <p>\${conv.messageCount} messages • \${conv.tokens.toLocaleString()} tokens</p>
730
- </div>
731
- <span class="status-badge status-\${conv.status}">\${conv.status}</span>
732
- </div>
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 updateProjects(projects) {
737
- const container = document.getElementById('projects');
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 (projects.length === 0) {
740
- container.innerHTML = '<p style="color: #6b7280; text-align: center; padding: 20px;">No projects found</p>';
741
- return;
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 {