claude-code-templates 1.12.1 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/analytics/core/AgentAnalyzer.js +341 -0
- package/src/analytics/core/SessionAnalyzer.js +101 -46
- package/src/analytics-web/components/AgentAnalytics.js +710 -0
- package/src/analytics-web/components/DashboardPage.js +810 -39
- package/src/analytics-web/components/SessionTimer.js +14 -11
- package/src/analytics-web/index.html +666 -65
- package/src/analytics.js +112 -10
- package/src/analytics-web/components/Dashboard.js.deprecated +0 -589
package/src/analytics.js
CHANGED
|
@@ -10,6 +10,7 @@ const ProcessDetector = require('./analytics/core/ProcessDetector');
|
|
|
10
10
|
const ConversationAnalyzer = require('./analytics/core/ConversationAnalyzer');
|
|
11
11
|
const FileWatcher = require('./analytics/core/FileWatcher');
|
|
12
12
|
const SessionAnalyzer = require('./analytics/core/SessionAnalyzer');
|
|
13
|
+
const AgentAnalyzer = require('./analytics/core/AgentAnalyzer');
|
|
13
14
|
const DataCache = require('./analytics/data/DataCache');
|
|
14
15
|
const WebSocketServer = require('./analytics/notifications/WebSocketServer');
|
|
15
16
|
const NotificationManager = require('./analytics/notifications/NotificationManager');
|
|
@@ -24,6 +25,7 @@ class ClaudeAnalytics {
|
|
|
24
25
|
this.processDetector = new ProcessDetector();
|
|
25
26
|
this.fileWatcher = new FileWatcher();
|
|
26
27
|
this.sessionAnalyzer = new SessionAnalyzer();
|
|
28
|
+
this.agentAnalyzer = new AgentAnalyzer();
|
|
27
29
|
this.dataCache = new DataCache();
|
|
28
30
|
this.performanceMonitor = new PerformanceMonitor({
|
|
29
31
|
enabled: true,
|
|
@@ -667,6 +669,28 @@ class ClaudeAnalytics {
|
|
|
667
669
|
}
|
|
668
670
|
});
|
|
669
671
|
|
|
672
|
+
// Agent usage analytics endpoint
|
|
673
|
+
this.app.get('/api/agents', async (req, res) => {
|
|
674
|
+
try {
|
|
675
|
+
const startDate = req.query.startDate;
|
|
676
|
+
const endDate = req.query.endDate;
|
|
677
|
+
const dateRange = (startDate || endDate) ? { startDate, endDate } : null;
|
|
678
|
+
|
|
679
|
+
const agentAnalysis = await this.agentAnalyzer.analyzeAgentUsage(this.data.conversations, dateRange);
|
|
680
|
+
const agentSummary = this.agentAnalyzer.generateSummary(agentAnalysis);
|
|
681
|
+
|
|
682
|
+
res.json({
|
|
683
|
+
...agentAnalysis,
|
|
684
|
+
summary: agentSummary,
|
|
685
|
+
dateRange,
|
|
686
|
+
timestamp: new Date().toISOString()
|
|
687
|
+
});
|
|
688
|
+
} catch (error) {
|
|
689
|
+
console.error('Error getting agent analytics:', error);
|
|
690
|
+
res.status(500).json({ error: 'Failed to get agent analytics' });
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
|
|
670
694
|
this.app.get('/api/realtime', async (req, res) => {
|
|
671
695
|
const realtimeWithTimestamp = {
|
|
672
696
|
...this.data.realtimeStats,
|
|
@@ -1661,12 +1685,88 @@ class ClaudeAnalytics {
|
|
|
1661
1685
|
const timeSinceLastUpdate = now - lastUpdate;
|
|
1662
1686
|
const timeSinceLastUpdateMinutes = Math.floor(timeSinceLastUpdate / (1000 * 60));
|
|
1663
1687
|
|
|
1664
|
-
//
|
|
1665
|
-
|
|
1666
|
-
const
|
|
1667
|
-
const
|
|
1668
|
-
|
|
1669
|
-
|
|
1688
|
+
// CORRECTED: Calculate next reset time based on scheduled reset hours
|
|
1689
|
+
// Claude sessions reset at specific times, not fixed durations
|
|
1690
|
+
const resetHours = [1, 7, 13, 19]; // 1am, 7am, 1pm, 7pm local time
|
|
1691
|
+
const sessionStartDate = new Date(startTime);
|
|
1692
|
+
|
|
1693
|
+
// Find next reset time after session start
|
|
1694
|
+
let nextResetTime = new Date(sessionStartDate);
|
|
1695
|
+
nextResetTime.setMinutes(0, 0, 0); // Set to exact hour
|
|
1696
|
+
|
|
1697
|
+
// Find the next reset hour
|
|
1698
|
+
let foundReset = false;
|
|
1699
|
+
for (let i = 0; i < resetHours.length * 2; i++) { // Check up to 2 full days
|
|
1700
|
+
const currentDay = Math.floor(i / resetHours.length);
|
|
1701
|
+
const hourIndex = i % resetHours.length;
|
|
1702
|
+
const resetHour = resetHours[hourIndex];
|
|
1703
|
+
|
|
1704
|
+
const testResetTime = new Date(sessionStartDate);
|
|
1705
|
+
testResetTime.setDate(testResetTime.getDate() + currentDay);
|
|
1706
|
+
testResetTime.setHours(resetHour, 0, 0, 0);
|
|
1707
|
+
|
|
1708
|
+
if (testResetTime > sessionStartDate) {
|
|
1709
|
+
nextResetTime = testResetTime;
|
|
1710
|
+
foundReset = true;
|
|
1711
|
+
break;
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
|
|
1715
|
+
if (!foundReset) {
|
|
1716
|
+
// Fallback: assume next day 7am if no pattern found
|
|
1717
|
+
nextResetTime.setDate(nextResetTime.getDate() + 1);
|
|
1718
|
+
nextResetTime.setHours(7, 0, 0, 0);
|
|
1719
|
+
}
|
|
1720
|
+
|
|
1721
|
+
const sessionLimitMs = nextResetTime.getTime() - startTime;
|
|
1722
|
+
let timeRemaining = nextResetTime.getTime() - now;
|
|
1723
|
+
let timeRemainingMinutes = Math.floor(timeRemaining / (1000 * 60));
|
|
1724
|
+
let timeRemainingHours = Math.floor(timeRemainingMinutes / 60);
|
|
1725
|
+
let remainingMinutesDisplay = timeRemainingMinutes % 60;
|
|
1726
|
+
|
|
1727
|
+
// If session is expired but has recent activity, calculate next reset time
|
|
1728
|
+
if (timeRemaining <= 0) {
|
|
1729
|
+
const RECENT_ACTIVITY_THRESHOLD = 5 * 60 * 1000; // 5 minutes
|
|
1730
|
+
const timeSinceLastUpdate = now - lastUpdate;
|
|
1731
|
+
|
|
1732
|
+
if (timeSinceLastUpdate < RECENT_ACTIVITY_THRESHOLD) {
|
|
1733
|
+
// Session was renewed, find the NEXT reset time
|
|
1734
|
+
let nextNextResetTime = new Date(nextResetTime);
|
|
1735
|
+
let foundNextReset = false;
|
|
1736
|
+
|
|
1737
|
+
for (let i = 0; i < resetHours.length; i++) {
|
|
1738
|
+
const resetHour = resetHours[i];
|
|
1739
|
+
const testResetTime = new Date(nextResetTime);
|
|
1740
|
+
|
|
1741
|
+
if (resetHour > nextResetTime.getHours()) {
|
|
1742
|
+
// Same day, later hour
|
|
1743
|
+
testResetTime.setHours(resetHour, 0, 0, 0);
|
|
1744
|
+
} else {
|
|
1745
|
+
// Next day
|
|
1746
|
+
testResetTime.setDate(testResetTime.getDate() + 1);
|
|
1747
|
+
testResetTime.setHours(resetHour, 0, 0, 0);
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
if (testResetTime > nextResetTime) {
|
|
1751
|
+
nextNextResetTime = testResetTime;
|
|
1752
|
+
foundNextReset = true;
|
|
1753
|
+
break;
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
if (!foundNextReset) {
|
|
1758
|
+
// Default to next day 1am
|
|
1759
|
+
nextNextResetTime.setDate(nextNextResetTime.getDate() + 1);
|
|
1760
|
+
nextNextResetTime.setHours(1, 0, 0, 0);
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
timeRemaining = nextNextResetTime.getTime() - now;
|
|
1764
|
+
timeRemainingMinutes = Math.floor(timeRemaining / (1000 * 60));
|
|
1765
|
+
timeRemainingHours = Math.floor(timeRemainingMinutes / 60);
|
|
1766
|
+
remainingMinutesDisplay = timeRemainingMinutes % 60;
|
|
1767
|
+
nextResetTime = nextNextResetTime;
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1670
1770
|
|
|
1671
1771
|
return {
|
|
1672
1772
|
hasSession: true,
|
|
@@ -1691,13 +1791,15 @@ class ClaudeAnalytics {
|
|
|
1691
1791
|
hours: timeRemainingHours,
|
|
1692
1792
|
remainingMinutes: remainingMinutesDisplay,
|
|
1693
1793
|
formatted: timeRemaining > 0 ? `${timeRemainingHours}h ${remainingMinutesDisplay}m` : 'Session expired',
|
|
1694
|
-
isExpired: timeRemaining <= 0
|
|
1794
|
+
isExpired: timeRemaining <= 0 && timeSinceLastUpdate >= (5 * 60 * 1000) // Expired only if past reset time AND no recent activity
|
|
1695
1795
|
},
|
|
1696
1796
|
sessionLimit: {
|
|
1697
1797
|
ms: sessionLimitMs,
|
|
1698
|
-
hours:
|
|
1699
|
-
minutes:
|
|
1700
|
-
formatted:
|
|
1798
|
+
hours: Math.floor(sessionLimitMs / (1000 * 60 * 60)),
|
|
1799
|
+
minutes: Math.floor((sessionLimitMs % (1000 * 60 * 60)) / (1000 * 60)),
|
|
1800
|
+
formatted: `${Math.floor(sessionLimitMs / (1000 * 60 * 60))}h ${Math.floor((sessionLimitMs % (1000 * 60 * 60)) / (1000 * 60))}m`,
|
|
1801
|
+
nextResetTime: nextResetTime.toISOString(),
|
|
1802
|
+
resetHour: nextResetTime.getHours()
|
|
1701
1803
|
}
|
|
1702
1804
|
};
|
|
1703
1805
|
} catch (error) {
|