claude-code-templates 1.5.8 → 1.5.9
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 +154 -2
package/package.json
CHANGED
package/src/analytics.js
CHANGED
|
@@ -138,7 +138,8 @@ class ClaudeAnalytics {
|
|
|
138
138
|
tokens: this.estimateTokens(content),
|
|
139
139
|
project: projectFromPath || this.extractProjectFromConversation(parsedMessages),
|
|
140
140
|
status: this.determineConversationStatus(parsedMessages, stats.mtime),
|
|
141
|
-
conversationState: this.determineConversationState(parsedMessages, stats.mtime)
|
|
141
|
+
conversationState: this.determineConversationState(parsedMessages, stats.mtime),
|
|
142
|
+
statusSquares: this.generateStatusSquares(parsedMessages)
|
|
142
143
|
};
|
|
143
144
|
|
|
144
145
|
conversations.push(conversation);
|
|
@@ -303,6 +304,78 @@ class ClaudeAnalytics {
|
|
|
303
304
|
return 'Inactive';
|
|
304
305
|
}
|
|
305
306
|
|
|
307
|
+
generateStatusSquares(messages) {
|
|
308
|
+
if (!messages || messages.length === 0) {
|
|
309
|
+
return [];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Sort messages by timestamp and take last 10 for status squares
|
|
313
|
+
const sortedMessages = messages.sort((a, b) => new Date(a.timestamp) - new Date(b.timestamp));
|
|
314
|
+
const recentMessages = sortedMessages.slice(-10);
|
|
315
|
+
|
|
316
|
+
return recentMessages.map((message, index) => {
|
|
317
|
+
const messageNum = sortedMessages.length - recentMessages.length + index + 1;
|
|
318
|
+
|
|
319
|
+
// Determine status based on message content and role
|
|
320
|
+
if (message.role === 'user') {
|
|
321
|
+
return {
|
|
322
|
+
type: 'pending',
|
|
323
|
+
tooltip: `Message #${messageNum}: User input`
|
|
324
|
+
};
|
|
325
|
+
} else if (message.role === 'assistant') {
|
|
326
|
+
// Check if the message contains tool usage or errors
|
|
327
|
+
const content = message.content || '';
|
|
328
|
+
|
|
329
|
+
if (typeof content === 'string') {
|
|
330
|
+
if (content.includes('[Tool:') || content.includes('tool_use')) {
|
|
331
|
+
return {
|
|
332
|
+
type: 'tool',
|
|
333
|
+
tooltip: `Message #${messageNum}: Tool execution`
|
|
334
|
+
};
|
|
335
|
+
} else if (content.includes('error') || content.includes('Error') || content.includes('failed')) {
|
|
336
|
+
return {
|
|
337
|
+
type: 'error',
|
|
338
|
+
tooltip: `Message #${messageNum}: Error in response`
|
|
339
|
+
};
|
|
340
|
+
} else {
|
|
341
|
+
return {
|
|
342
|
+
type: 'success',
|
|
343
|
+
tooltip: `Message #${messageNum}: Successful response`
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
} else if (Array.isArray(content)) {
|
|
347
|
+
// Check for tool_use blocks in array content
|
|
348
|
+
const hasToolUse = content.some(block => block.type === 'tool_use');
|
|
349
|
+
const hasError = content.some(block =>
|
|
350
|
+
block.type === 'text' && (block.text?.includes('error') || block.text?.includes('Error'))
|
|
351
|
+
);
|
|
352
|
+
|
|
353
|
+
if (hasError) {
|
|
354
|
+
return {
|
|
355
|
+
type: 'error',
|
|
356
|
+
tooltip: `Message #${messageNum}: Error in response`
|
|
357
|
+
};
|
|
358
|
+
} else if (hasToolUse) {
|
|
359
|
+
return {
|
|
360
|
+
type: 'tool',
|
|
361
|
+
tooltip: `Message #${messageNum}: Tool execution`
|
|
362
|
+
};
|
|
363
|
+
} else {
|
|
364
|
+
return {
|
|
365
|
+
type: 'success',
|
|
366
|
+
tooltip: `Message #${messageNum}: Successful response`
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
type: 'pending',
|
|
374
|
+
tooltip: `Message #${messageNum}: Unknown status`
|
|
375
|
+
};
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
|
|
306
379
|
determineProjectStatus(lastActivity) {
|
|
307
380
|
const now = new Date();
|
|
308
381
|
const timeDiff = now - lastActivity;
|
|
@@ -731,6 +804,10 @@ async function createWebDashboard() {
|
|
|
731
804
|
.session-id {
|
|
732
805
|
color: #d57455;
|
|
733
806
|
font-family: monospace;
|
|
807
|
+
display: flex;
|
|
808
|
+
align-items: center;
|
|
809
|
+
flex-wrap: wrap;
|
|
810
|
+
gap: 4px;
|
|
734
811
|
}
|
|
735
812
|
|
|
736
813
|
.session-project {
|
|
@@ -787,6 +864,66 @@ async function createWebDashboard() {
|
|
|
787
864
|
50% { opacity: 0.6; }
|
|
788
865
|
}
|
|
789
866
|
|
|
867
|
+
.status-squares {
|
|
868
|
+
display: flex;
|
|
869
|
+
gap: 2px;
|
|
870
|
+
align-items: center;
|
|
871
|
+
margin-left: 4px;
|
|
872
|
+
flex-wrap: wrap;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.status-square {
|
|
876
|
+
width: 8px;
|
|
877
|
+
height: 8px;
|
|
878
|
+
border-radius: 1px;
|
|
879
|
+
cursor: help;
|
|
880
|
+
position: relative;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.status-square.success {
|
|
884
|
+
background: #d57455;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.status-square.tool {
|
|
888
|
+
background: #f97316;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
.status-square.error {
|
|
892
|
+
background: #dc2626;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.status-square.pending {
|
|
896
|
+
background: #6b7280;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
.status-square:hover::after {
|
|
900
|
+
content: attr(data-tooltip);
|
|
901
|
+
position: absolute;
|
|
902
|
+
bottom: 100%;
|
|
903
|
+
left: 50%;
|
|
904
|
+
transform: translateX(-50%);
|
|
905
|
+
background: #1c1c1c;
|
|
906
|
+
color: #fff;
|
|
907
|
+
padding: 4px 8px;
|
|
908
|
+
border-radius: 4px;
|
|
909
|
+
font-size: 0.75rem;
|
|
910
|
+
white-space: nowrap;
|
|
911
|
+
z-index: 1000;
|
|
912
|
+
margin-bottom: 4px;
|
|
913
|
+
border: 1px solid #30363d;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.status-square:hover::before {
|
|
917
|
+
content: '';
|
|
918
|
+
position: absolute;
|
|
919
|
+
bottom: 100%;
|
|
920
|
+
left: 50%;
|
|
921
|
+
transform: translateX(-50%);
|
|
922
|
+
border: 4px solid transparent;
|
|
923
|
+
border-top-color: #30363d;
|
|
924
|
+
z-index: 1000;
|
|
925
|
+
}
|
|
926
|
+
|
|
790
927
|
.loading, .error {
|
|
791
928
|
text-align: center;
|
|
792
929
|
padding: 40px;
|
|
@@ -1138,7 +1275,12 @@ async function createWebDashboard() {
|
|
|
1138
1275
|
|
|
1139
1276
|
tableBody.innerHTML = filteredConversations.map(conv => \`
|
|
1140
1277
|
<tr onclick="showSessionDetail('\${conv.id}')" style="cursor: pointer;">
|
|
1141
|
-
<td class="session-id"
|
|
1278
|
+
<td class="session-id">
|
|
1279
|
+
\${conv.id.substring(0, 8)}...
|
|
1280
|
+
<div class="status-squares">
|
|
1281
|
+
\${generateStatusSquaresHTML(conv.statusSquares || [])}
|
|
1282
|
+
</div>
|
|
1283
|
+
</td>
|
|
1142
1284
|
<td class="session-project">\${conv.project}</td>
|
|
1143
1285
|
<td class="session-messages">\${conv.messageCount}</td>
|
|
1144
1286
|
<td class="session-tokens">\${conv.tokens.toLocaleString()}</td>
|
|
@@ -1182,6 +1324,16 @@ async function createWebDashboard() {
|
|
|
1182
1324
|
return '';
|
|
1183
1325
|
}
|
|
1184
1326
|
|
|
1327
|
+
function generateStatusSquaresHTML(statusSquares) {
|
|
1328
|
+
if (!statusSquares || statusSquares.length === 0) {
|
|
1329
|
+
return '';
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
return statusSquares.map(square =>
|
|
1333
|
+
\`<div class="status-square \${square.type}" data-tooltip="\${square.tooltip}"></div>\`
|
|
1334
|
+
).join('');
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1185
1337
|
// Filter button handlers
|
|
1186
1338
|
document.addEventListener('DOMContentLoaded', function() {
|
|
1187
1339
|
const filterButtons = document.querySelectorAll('.filter-btn');
|