claude-code-templates 1.12.2 → 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
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentAnalytics - Component for displaying agent usage analytics and charts
|
|
3
|
+
* Shows comprehensive agent usage statistics, trends, and workflow patterns
|
|
4
|
+
*/
|
|
5
|
+
class AgentAnalytics {
|
|
6
|
+
constructor(container, services) {
|
|
7
|
+
this.container = container;
|
|
8
|
+
this.dataService = services.data;
|
|
9
|
+
this.stateService = services.state;
|
|
10
|
+
|
|
11
|
+
this.agentData = null;
|
|
12
|
+
this.charts = {};
|
|
13
|
+
this.isInitialized = false;
|
|
14
|
+
|
|
15
|
+
// Date filter state
|
|
16
|
+
this.dateFilters = {
|
|
17
|
+
startDate: null,
|
|
18
|
+
endDate: null
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// Subscribe to data refresh events
|
|
22
|
+
this.dataService.onDataRefresh(this.handleDataRefresh.bind(this));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the agent analytics component
|
|
27
|
+
*/
|
|
28
|
+
async initialize() {
|
|
29
|
+
if (this.isInitialized) return;
|
|
30
|
+
|
|
31
|
+
try {
|
|
32
|
+
this.stateService.setLoading(true);
|
|
33
|
+
await this.render();
|
|
34
|
+
await this.loadAgentData();
|
|
35
|
+
this.setupEventListeners();
|
|
36
|
+
this.isInitialized = true;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error('Error initializing agent analytics:', error);
|
|
39
|
+
this.stateService.setError(error);
|
|
40
|
+
} finally {
|
|
41
|
+
this.stateService.setLoading(false);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Render the agent analytics UI
|
|
47
|
+
*/
|
|
48
|
+
async render() {
|
|
49
|
+
this.container.innerHTML = `
|
|
50
|
+
<div class="agent-analytics">
|
|
51
|
+
<!-- Header Section -->
|
|
52
|
+
<div class="analytics-header">
|
|
53
|
+
<div class="header-content">
|
|
54
|
+
<h2 class="analytics-title">
|
|
55
|
+
<span class="title-icon">🤖</span>
|
|
56
|
+
Agent Usage Analytics
|
|
57
|
+
</h2>
|
|
58
|
+
<p class="analytics-subtitle">Specialized Claude Code agent usage patterns and workflow insights</p>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Date Filter Controls -->
|
|
62
|
+
<div class="date-filters">
|
|
63
|
+
<div class="filter-group">
|
|
64
|
+
<label for="start-date">From:</label>
|
|
65
|
+
<input type="date" id="start-date" class="date-input">
|
|
66
|
+
</div>
|
|
67
|
+
<div class="filter-group">
|
|
68
|
+
<label for="end-date">To:</label>
|
|
69
|
+
<input type="date" id="end-date" class="date-input">
|
|
70
|
+
</div>
|
|
71
|
+
<button class="refresh-btn" id="refresh-analytics">
|
|
72
|
+
<span class="btn-icon">🔄</span>
|
|
73
|
+
Refresh
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<!-- Summary Metrics -->
|
|
79
|
+
<div class="metrics-grid" id="metrics-grid">
|
|
80
|
+
<div class="metric-card loading">
|
|
81
|
+
<div class="metric-icon">🔄</div>
|
|
82
|
+
<div class="metric-content">
|
|
83
|
+
<div class="metric-value">Loading...</div>
|
|
84
|
+
<div class="metric-label">Agent Data</div>
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<!-- Charts Section -->
|
|
90
|
+
<div class="charts-container">
|
|
91
|
+
<!-- Agent Usage Overview -->
|
|
92
|
+
<div class="chart-card">
|
|
93
|
+
<div class="chart-header">
|
|
94
|
+
<h3>Agent Usage Distribution</h3>
|
|
95
|
+
<p>Total invocations per specialized agent type</p>
|
|
96
|
+
</div>
|
|
97
|
+
<div class="chart-content">
|
|
98
|
+
<canvas id="agent-usage-chart" width="400" height="200"></canvas>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<!-- Usage Timeline -->
|
|
103
|
+
<div class="chart-card">
|
|
104
|
+
<div class="chart-header">
|
|
105
|
+
<h3>Agent Usage Timeline</h3>
|
|
106
|
+
<p>Agent invocations over time showing workflow patterns</p>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="chart-content">
|
|
109
|
+
<canvas id="agent-timeline-chart" width="400" height="200"></canvas>
|
|
110
|
+
</div>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<!-- Hourly Usage Pattern -->
|
|
114
|
+
<div class="chart-card">
|
|
115
|
+
<div class="chart-header">
|
|
116
|
+
<h3>Popular Usage Hours</h3>
|
|
117
|
+
<p>Agent activity distribution throughout the day</p>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="chart-content">
|
|
120
|
+
<canvas id="hourly-usage-chart" width="400" height="200"></canvas>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
|
|
124
|
+
<!-- Agent Efficiency Metrics -->
|
|
125
|
+
<div class="chart-card">
|
|
126
|
+
<div class="chart-header">
|
|
127
|
+
<h3>Agent Workflow Efficiency</h3>
|
|
128
|
+
<p>Usage patterns and adoption rates across different agents</p>
|
|
129
|
+
</div>
|
|
130
|
+
<div class="chart-content">
|
|
131
|
+
<div class="efficiency-metrics" id="efficiency-metrics">
|
|
132
|
+
<div class="efficiency-loading">Loading efficiency data...</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
|
|
138
|
+
<!-- Detailed Agent Stats -->
|
|
139
|
+
<div class="agent-details-section">
|
|
140
|
+
<h3>Detailed Agent Statistics</h3>
|
|
141
|
+
<div class="agent-stats-grid" id="agent-stats-grid">
|
|
142
|
+
<div class="stats-loading">Loading agent statistics...</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<!-- Workflow Patterns -->
|
|
147
|
+
<div class="workflow-patterns-section" id="workflow-patterns-section" style="display: none;">
|
|
148
|
+
<h3>Agent Workflow Patterns</h3>
|
|
149
|
+
<p>Common sequences of agent usage within workflow sessions</p>
|
|
150
|
+
<div class="workflow-patterns" id="workflow-patterns">
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Load agent analytics data from API
|
|
159
|
+
*/
|
|
160
|
+
async loadAgentData() {
|
|
161
|
+
try {
|
|
162
|
+
const params = new URLSearchParams();
|
|
163
|
+
if (this.dateFilters.startDate) {
|
|
164
|
+
params.append('startDate', this.dateFilters.startDate);
|
|
165
|
+
}
|
|
166
|
+
if (this.dateFilters.endDate) {
|
|
167
|
+
params.append('endDate', this.dateFilters.endDate);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const url = `/api/agents${params.toString() ? '?' + params.toString() : ''}`;
|
|
171
|
+
this.agentData = await this.dataService.cachedFetch(url);
|
|
172
|
+
|
|
173
|
+
if (this.agentData) {
|
|
174
|
+
this.updateMetrics();
|
|
175
|
+
this.renderCharts();
|
|
176
|
+
this.renderAgentStats();
|
|
177
|
+
this.renderWorkflowPatterns();
|
|
178
|
+
} else {
|
|
179
|
+
this.renderNoData();
|
|
180
|
+
}
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.error('Error loading agent data:', error);
|
|
183
|
+
this.renderError(error);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Update summary metrics
|
|
189
|
+
*/
|
|
190
|
+
updateMetrics() {
|
|
191
|
+
const metricsGrid = this.container.querySelector('#metrics-grid');
|
|
192
|
+
if (!metricsGrid || !this.agentData) return;
|
|
193
|
+
|
|
194
|
+
const { summary, totalAgentInvocations, totalAgentTypes, efficiency } = this.agentData;
|
|
195
|
+
|
|
196
|
+
metricsGrid.innerHTML = `
|
|
197
|
+
<div class="metric-card primary">
|
|
198
|
+
<div class="metric-icon">🚀</div>
|
|
199
|
+
<div class="metric-content">
|
|
200
|
+
<div class="metric-value">${totalAgentInvocations}</div>
|
|
201
|
+
<div class="metric-label">Total Invocations</div>
|
|
202
|
+
</div>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div class="metric-card secondary">
|
|
206
|
+
<div class="metric-icon">🤖</div>
|
|
207
|
+
<div class="metric-content">
|
|
208
|
+
<div class="metric-value">${totalAgentTypes}</div>
|
|
209
|
+
<div class="metric-label">Agent Types Used</div>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
|
|
213
|
+
<div class="metric-card success">
|
|
214
|
+
<div class="metric-icon">⭐</div>
|
|
215
|
+
<div class="metric-content">
|
|
216
|
+
<div class="metric-value">${efficiency.adoptionRate}%</div>
|
|
217
|
+
<div class="metric-label">Adoption Rate</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<div class="metric-card info">
|
|
222
|
+
<div class="metric-icon">📊</div>
|
|
223
|
+
<div class="metric-content">
|
|
224
|
+
<div class="metric-value">${efficiency.averageInvocationsPerAgent}</div>
|
|
225
|
+
<div class="metric-label">Avg. per Agent</div>
|
|
226
|
+
</div>
|
|
227
|
+
</div>
|
|
228
|
+
`;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Render all charts
|
|
233
|
+
*/
|
|
234
|
+
renderCharts() {
|
|
235
|
+
if (!this.agentData) return;
|
|
236
|
+
|
|
237
|
+
this.renderAgentUsageChart();
|
|
238
|
+
this.renderTimelineChart();
|
|
239
|
+
this.renderHourlyUsageChart();
|
|
240
|
+
this.renderEfficiencyMetrics();
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Render agent usage distribution chart
|
|
245
|
+
*/
|
|
246
|
+
renderAgentUsageChart() {
|
|
247
|
+
const canvas = this.container.querySelector('#agent-usage-chart');
|
|
248
|
+
if (!canvas || !this.agentData.agentStats) return;
|
|
249
|
+
|
|
250
|
+
// Destroy existing chart
|
|
251
|
+
if (this.charts.usage) {
|
|
252
|
+
this.charts.usage.destroy();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const ctx = canvas.getContext('2d');
|
|
256
|
+
const agentStats = this.agentData.agentStats;
|
|
257
|
+
|
|
258
|
+
this.charts.usage = new Chart(ctx, {
|
|
259
|
+
type: 'doughnut',
|
|
260
|
+
data: {
|
|
261
|
+
labels: agentStats.map(agent => agent.name),
|
|
262
|
+
datasets: [{
|
|
263
|
+
data: agentStats.map(agent => agent.totalInvocations),
|
|
264
|
+
backgroundColor: agentStats.map(agent => agent.color),
|
|
265
|
+
borderColor: 'var(--bg-primary)',
|
|
266
|
+
borderWidth: 2,
|
|
267
|
+
hoverBorderWidth: 3
|
|
268
|
+
}]
|
|
269
|
+
},
|
|
270
|
+
options: {
|
|
271
|
+
responsive: true,
|
|
272
|
+
maintainAspectRatio: false,
|
|
273
|
+
plugins: {
|
|
274
|
+
legend: {
|
|
275
|
+
position: 'bottom',
|
|
276
|
+
labels: {
|
|
277
|
+
color: 'var(--text-primary)',
|
|
278
|
+
padding: 20,
|
|
279
|
+
usePointStyle: true,
|
|
280
|
+
font: {
|
|
281
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
tooltip: {
|
|
286
|
+
titleFont: {
|
|
287
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
288
|
+
},
|
|
289
|
+
bodyFont: {
|
|
290
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
291
|
+
},
|
|
292
|
+
callbacks: {
|
|
293
|
+
label: function(context) {
|
|
294
|
+
const agent = agentStats[context.dataIndex];
|
|
295
|
+
return `${agent.name}: ${context.parsed} invocations (${agent.uniqueConversations} conversations)`;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Render agent usage timeline chart
|
|
306
|
+
*/
|
|
307
|
+
renderTimelineChart() {
|
|
308
|
+
const canvas = this.container.querySelector('#agent-timeline-chart');
|
|
309
|
+
if (!canvas || !this.agentData.usageByDay) return;
|
|
310
|
+
|
|
311
|
+
// Destroy existing chart
|
|
312
|
+
if (this.charts.timeline) {
|
|
313
|
+
this.charts.timeline.destroy();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const ctx = canvas.getContext('2d');
|
|
317
|
+
const timelineData = this.agentData.usageByDay;
|
|
318
|
+
|
|
319
|
+
this.charts.timeline = new Chart(ctx, {
|
|
320
|
+
type: 'line',
|
|
321
|
+
data: {
|
|
322
|
+
labels: timelineData.map(d => new Date(d.date).toLocaleDateString()),
|
|
323
|
+
datasets: [{
|
|
324
|
+
label: 'Agent Invocations',
|
|
325
|
+
data: timelineData.map(d => d.count),
|
|
326
|
+
borderColor: '#3fb950',
|
|
327
|
+
backgroundColor: 'rgba(63, 185, 80, 0.1)',
|
|
328
|
+
borderWidth: 2,
|
|
329
|
+
fill: true,
|
|
330
|
+
tension: 0.3,
|
|
331
|
+
pointBackgroundColor: '#3fb950',
|
|
332
|
+
pointBorderColor: '#ffffff',
|
|
333
|
+
pointBorderWidth: 2,
|
|
334
|
+
pointRadius: 4,
|
|
335
|
+
pointHoverRadius: 6
|
|
336
|
+
}]
|
|
337
|
+
},
|
|
338
|
+
options: {
|
|
339
|
+
responsive: true,
|
|
340
|
+
maintainAspectRatio: false,
|
|
341
|
+
plugins: {
|
|
342
|
+
legend: {
|
|
343
|
+
labels: {
|
|
344
|
+
color: 'var(--text-primary)',
|
|
345
|
+
font: {
|
|
346
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
tooltip: {
|
|
351
|
+
titleFont: {
|
|
352
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
353
|
+
},
|
|
354
|
+
bodyFont: {
|
|
355
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
scales: {
|
|
360
|
+
x: {
|
|
361
|
+
ticks: {
|
|
362
|
+
color: 'var(--text-secondary)',
|
|
363
|
+
font: {
|
|
364
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
365
|
+
}
|
|
366
|
+
},
|
|
367
|
+
grid: {
|
|
368
|
+
color: 'var(--border-primary)'
|
|
369
|
+
}
|
|
370
|
+
},
|
|
371
|
+
y: {
|
|
372
|
+
beginAtZero: true,
|
|
373
|
+
ticks: {
|
|
374
|
+
color: 'var(--text-secondary)',
|
|
375
|
+
font: {
|
|
376
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
grid: {
|
|
380
|
+
color: 'var(--border-primary)'
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Render hourly usage pattern chart
|
|
390
|
+
*/
|
|
391
|
+
renderHourlyUsageChart() {
|
|
392
|
+
const canvas = this.container.querySelector('#hourly-usage-chart');
|
|
393
|
+
if (!canvas || !this.agentData.popularHours) return;
|
|
394
|
+
|
|
395
|
+
// Destroy existing chart
|
|
396
|
+
if (this.charts.hourly) {
|
|
397
|
+
this.charts.hourly.destroy();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const ctx = canvas.getContext('2d');
|
|
401
|
+
const hourlyData = this.agentData.popularHours;
|
|
402
|
+
|
|
403
|
+
this.charts.hourly = new Chart(ctx, {
|
|
404
|
+
type: 'bar',
|
|
405
|
+
data: {
|
|
406
|
+
labels: hourlyData.map(h => h.label),
|
|
407
|
+
datasets: [{
|
|
408
|
+
label: 'Agent Invocations',
|
|
409
|
+
data: hourlyData.map(h => h.count),
|
|
410
|
+
backgroundColor: 'rgba(217, 116, 85, 0.6)',
|
|
411
|
+
borderColor: '#d57455',
|
|
412
|
+
borderWidth: 1,
|
|
413
|
+
borderRadius: 4
|
|
414
|
+
}]
|
|
415
|
+
},
|
|
416
|
+
options: {
|
|
417
|
+
responsive: true,
|
|
418
|
+
maintainAspectRatio: false,
|
|
419
|
+
plugins: {
|
|
420
|
+
legend: {
|
|
421
|
+
labels: {
|
|
422
|
+
color: 'var(--text-primary)',
|
|
423
|
+
font: {
|
|
424
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
},
|
|
428
|
+
tooltip: {
|
|
429
|
+
titleFont: {
|
|
430
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
431
|
+
},
|
|
432
|
+
bodyFont: {
|
|
433
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
},
|
|
437
|
+
scales: {
|
|
438
|
+
x: {
|
|
439
|
+
ticks: {
|
|
440
|
+
color: 'var(--text-secondary)',
|
|
441
|
+
font: {
|
|
442
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
443
|
+
}
|
|
444
|
+
},
|
|
445
|
+
grid: {
|
|
446
|
+
color: 'var(--border-primary)'
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
y: {
|
|
450
|
+
beginAtZero: true,
|
|
451
|
+
ticks: {
|
|
452
|
+
color: 'var(--text-secondary)',
|
|
453
|
+
font: {
|
|
454
|
+
family: "'Monaco', 'Menlo', 'Ubuntu Mono', monospace"
|
|
455
|
+
}
|
|
456
|
+
},
|
|
457
|
+
grid: {
|
|
458
|
+
color: 'var(--border-primary)'
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Render efficiency metrics
|
|
468
|
+
*/
|
|
469
|
+
renderEfficiencyMetrics() {
|
|
470
|
+
const container = this.container.querySelector('#efficiency-metrics');
|
|
471
|
+
if (!container || !this.agentData.efficiency) return;
|
|
472
|
+
|
|
473
|
+
const { efficiency, agentStats } = this.agentData;
|
|
474
|
+
const mostUsedAgent = efficiency.mostUsedAgent;
|
|
475
|
+
|
|
476
|
+
container.innerHTML = `
|
|
477
|
+
<div class="efficiency-grid">
|
|
478
|
+
<div class="efficiency-card">
|
|
479
|
+
<div class="efficiency-icon">🎯</div>
|
|
480
|
+
<div class="efficiency-content">
|
|
481
|
+
<div class="efficiency-value">${efficiency.averageInvocationsPerAgent}</div>
|
|
482
|
+
<div class="efficiency-label">Avg. Invocations/Agent</div>
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
|
|
486
|
+
<div class="efficiency-card">
|
|
487
|
+
<div class="efficiency-icon">📈</div>
|
|
488
|
+
<div class="efficiency-content">
|
|
489
|
+
<div class="efficiency-value">${efficiency.adoptionRate}%</div>
|
|
490
|
+
<div class="efficiency-label">Adoption Rate</div>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
|
|
494
|
+
<div class="efficiency-card">
|
|
495
|
+
<div class="efficiency-icon">${mostUsedAgent ? mostUsedAgent.icon : '🤖'}</div>
|
|
496
|
+
<div class="efficiency-content">
|
|
497
|
+
<div class="efficiency-value">${mostUsedAgent ? mostUsedAgent.name : 'None'}</div>
|
|
498
|
+
<div class="efficiency-label">Most Used Agent</div>
|
|
499
|
+
</div>
|
|
500
|
+
</div>
|
|
501
|
+
|
|
502
|
+
<div class="efficiency-card">
|
|
503
|
+
<div class="efficiency-icon">🔧</div>
|
|
504
|
+
<div class="efficiency-content">
|
|
505
|
+
<div class="efficiency-value">${efficiency.agentDiversity}</div>
|
|
506
|
+
<div class="efficiency-label">Agent Diversity</div>
|
|
507
|
+
</div>
|
|
508
|
+
</div>
|
|
509
|
+
</div>
|
|
510
|
+
`;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Render detailed agent statistics
|
|
515
|
+
*/
|
|
516
|
+
renderAgentStats() {
|
|
517
|
+
const container = this.container.querySelector('#agent-stats-grid');
|
|
518
|
+
if (!container || !this.agentData.agentStats) return;
|
|
519
|
+
|
|
520
|
+
container.innerHTML = this.agentData.agentStats.map(agent => `
|
|
521
|
+
<div class="agent-stat-card">
|
|
522
|
+
<div class="agent-stat-header">
|
|
523
|
+
<div class="agent-stat-icon">${agent.icon}</div>
|
|
524
|
+
<div class="agent-stat-info">
|
|
525
|
+
<h4>${agent.name}</h4>
|
|
526
|
+
<p>${agent.description}</p>
|
|
527
|
+
</div>
|
|
528
|
+
<div class="agent-stat-badge" style="background-color: ${agent.color}20; color: ${agent.color};">
|
|
529
|
+
${agent.totalInvocations} uses
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
|
|
533
|
+
<div class="agent-stat-metrics">
|
|
534
|
+
<div class="stat-metric">
|
|
535
|
+
<span class="metric-label">Conversations:</span>
|
|
536
|
+
<span class="metric-value">${agent.uniqueConversations}</span>
|
|
537
|
+
</div>
|
|
538
|
+
<div class="stat-metric">
|
|
539
|
+
<span class="metric-label">Avg. per conversation:</span>
|
|
540
|
+
<span class="metric-value">${agent.averageUsagePerConversation}</span>
|
|
541
|
+
</div>
|
|
542
|
+
<div class="stat-metric">
|
|
543
|
+
<span class="metric-label">First used:</span>
|
|
544
|
+
<span class="metric-value">${new Date(agent.firstUsed).toLocaleDateString()}</span>
|
|
545
|
+
</div>
|
|
546
|
+
<div class="stat-metric">
|
|
547
|
+
<span class="metric-label">Last used:</span>
|
|
548
|
+
<span class="metric-value">${new Date(agent.lastUsed).toLocaleDateString()}</span>
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
`).join('');
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Render workflow patterns
|
|
557
|
+
*/
|
|
558
|
+
renderWorkflowPatterns() {
|
|
559
|
+
const section = this.container.querySelector('#workflow-patterns-section');
|
|
560
|
+
const container = this.container.querySelector('#workflow-patterns');
|
|
561
|
+
|
|
562
|
+
if (!container || !this.agentData.workflowPatterns) return;
|
|
563
|
+
|
|
564
|
+
if (this.agentData.workflowPatterns.length === 0) {
|
|
565
|
+
section.style.display = 'none';
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
section.style.display = 'block';
|
|
570
|
+
container.innerHTML = this.agentData.workflowPatterns.map(pattern => `
|
|
571
|
+
<div class="workflow-pattern">
|
|
572
|
+
<div class="pattern-flow">${pattern.pattern}</div>
|
|
573
|
+
<div class="pattern-count">${pattern.count} times</div>
|
|
574
|
+
</div>
|
|
575
|
+
`).join('');
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Render no data state
|
|
580
|
+
*/
|
|
581
|
+
renderNoData() {
|
|
582
|
+
this.container.innerHTML = `
|
|
583
|
+
<div class="no-agent-data">
|
|
584
|
+
<div class="no-data-content">
|
|
585
|
+
<div class="no-data-icon">🤖</div>
|
|
586
|
+
<h3>No Agent Usage Data</h3>
|
|
587
|
+
<p>No specialized Claude Code agents have been used yet.</p>
|
|
588
|
+
<div class="agent-types">
|
|
589
|
+
<h4>Available Agent Types:</h4>
|
|
590
|
+
<ul>
|
|
591
|
+
<li><strong>general-purpose:</strong> Multi-step tasks and research</li>
|
|
592
|
+
<li><strong>claude-code-best-practices:</strong> Workflow optimization</li>
|
|
593
|
+
<li><strong>docusaurus-expert:</strong> Documentation management</li>
|
|
594
|
+
</ul>
|
|
595
|
+
</div>
|
|
596
|
+
<button class="refresh-btn" onclick="this.loadAgentData()">
|
|
597
|
+
<span class="btn-icon">🔄</span>
|
|
598
|
+
Refresh Data
|
|
599
|
+
</button>
|
|
600
|
+
</div>
|
|
601
|
+
</div>
|
|
602
|
+
`;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
/**
|
|
606
|
+
* Render error state
|
|
607
|
+
*/
|
|
608
|
+
renderError(error) {
|
|
609
|
+
this.container.innerHTML = `
|
|
610
|
+
<div class="agent-analytics-error">
|
|
611
|
+
<div class="error-content">
|
|
612
|
+
<div class="error-icon">⚠️</div>
|
|
613
|
+
<h3>Error Loading Agent Data</h3>
|
|
614
|
+
<p>${error.message || 'Failed to load agent analytics data'}</p>
|
|
615
|
+
<button class="refresh-btn" onclick="this.loadAgentData()">
|
|
616
|
+
<span class="btn-icon">🔄</span>
|
|
617
|
+
Try Again
|
|
618
|
+
</button>
|
|
619
|
+
</div>
|
|
620
|
+
</div>
|
|
621
|
+
`;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Setup event listeners
|
|
626
|
+
*/
|
|
627
|
+
setupEventListeners() {
|
|
628
|
+
// Date filter change handlers
|
|
629
|
+
const startDateInput = this.container.querySelector('#start-date');
|
|
630
|
+
const endDateInput = this.container.querySelector('#end-date');
|
|
631
|
+
const refreshBtn = this.container.querySelector('#refresh-analytics');
|
|
632
|
+
|
|
633
|
+
if (startDateInput) {
|
|
634
|
+
startDateInput.addEventListener('change', (e) => {
|
|
635
|
+
this.dateFilters.startDate = e.target.value;
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
if (endDateInput) {
|
|
640
|
+
endDateInput.addEventListener('change', (e) => {
|
|
641
|
+
this.dateFilters.endDate = e.target.value;
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
if (refreshBtn) {
|
|
646
|
+
refreshBtn.addEventListener('click', () => {
|
|
647
|
+
this.refreshData();
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Refresh analytics data
|
|
654
|
+
*/
|
|
655
|
+
async refreshData() {
|
|
656
|
+
try {
|
|
657
|
+
const refreshBtn = this.container.querySelector('#refresh-analytics');
|
|
658
|
+
if (refreshBtn) {
|
|
659
|
+
refreshBtn.disabled = true;
|
|
660
|
+
const icon = refreshBtn.querySelector('.btn-icon');
|
|
661
|
+
if (icon) icon.style.animation = 'spin 1s linear infinite';
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
await this.loadAgentData();
|
|
665
|
+
} catch (error) {
|
|
666
|
+
console.error('Error refreshing agent data:', error);
|
|
667
|
+
} finally {
|
|
668
|
+
const refreshBtn = this.container.querySelector('#refresh-analytics');
|
|
669
|
+
if (refreshBtn) {
|
|
670
|
+
refreshBtn.disabled = false;
|
|
671
|
+
const icon = refreshBtn.querySelector('.btn-icon');
|
|
672
|
+
if (icon) icon.style.animation = '';
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
/**
|
|
678
|
+
* Handle data refresh events
|
|
679
|
+
*/
|
|
680
|
+
handleDataRefresh(data, source) {
|
|
681
|
+
if (source === 'agents' || source === 'all') {
|
|
682
|
+
this.loadAgentData();
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/**
|
|
687
|
+
* Destroy the component and cleanup
|
|
688
|
+
*/
|
|
689
|
+
destroy() {
|
|
690
|
+
// Destroy charts
|
|
691
|
+
Object.values(this.charts).forEach(chart => {
|
|
692
|
+
if (chart && typeof chart.destroy === 'function') {
|
|
693
|
+
chart.destroy();
|
|
694
|
+
}
|
|
695
|
+
});
|
|
696
|
+
this.charts = {};
|
|
697
|
+
|
|
698
|
+
// Clear container
|
|
699
|
+
if (this.container) {
|
|
700
|
+
this.container.innerHTML = '';
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
this.isInitialized = false;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Export for use in other modules
|
|
708
|
+
if (typeof module !== 'undefined' && module.exports) {
|
|
709
|
+
module.exports = AgentAnalytics;
|
|
710
|
+
}
|