claude-code-templates 1.20.3 → 1.21.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/bin/create-claude-config.js +5 -1
- package/package.json +1 -1
- package/src/analytics-web/components/ActivityHeatmap.js +50 -6
- package/src/analytics-web/components/DashboardPage.js +4 -0
- package/src/analytics-web/services/DataService.js +7 -0
- package/src/analytics.js +67 -20
- package/src/index.js +443 -6
- package/src/sandbox-server.js +555 -0
- package/src/test-activity-data.json +1094 -0
|
@@ -67,11 +67,15 @@ program
|
|
|
67
67
|
.option('--setting <setting>', 'install specific setting component (supports comma-separated values)')
|
|
68
68
|
.option('--hook <hook>', 'install specific hook component (supports comma-separated values)')
|
|
69
69
|
.option('--workflow <workflow>', 'install workflow from hash (#hash) OR workflow YAML (base64 encoded) when used with --agent/--command/--mcp')
|
|
70
|
-
.option('--prompt <prompt>', 'execute the provided prompt in Claude Code after installation')
|
|
70
|
+
.option('--prompt <prompt>', 'execute the provided prompt in Claude Code after installation or in sandbox')
|
|
71
71
|
.option('--create-agent <agent>', 'create a global agent accessible from anywhere (e.g., customer-support)')
|
|
72
72
|
.option('--list-agents', 'list all installed global agents')
|
|
73
73
|
.option('--remove-agent <agent>', 'remove a global agent')
|
|
74
74
|
.option('--update-agent <agent>', 'update a global agent to the latest version')
|
|
75
|
+
.option('--studio', 'launch Claude Code Studio interface for local and cloud execution')
|
|
76
|
+
.option('--sandbox <provider>', 'execute Claude Code in isolated sandbox environment (e.g., e2b)')
|
|
77
|
+
.option('--e2b-api-key <key>', 'E2B API key for sandbox execution (alternative to environment variable)')
|
|
78
|
+
.option('--anthropic-api-key <key>', 'Anthropic API key for Claude Code (alternative to environment variable)')
|
|
75
79
|
.action(async (options) => {
|
|
76
80
|
try {
|
|
77
81
|
// Only show banner for non-agent-list commands
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.21.0",
|
|
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": {
|
|
@@ -353,6 +353,9 @@ class ActivityHeatmap {
|
|
|
353
353
|
*/
|
|
354
354
|
generateCalendarData(dailyActivity) {
|
|
355
355
|
const today = new Date();
|
|
356
|
+
const todayEnd = new Date(today);
|
|
357
|
+
todayEnd.setHours(23, 59, 59, 999); // End of today
|
|
358
|
+
|
|
356
359
|
const oneYearAgo = new Date(today);
|
|
357
360
|
oneYearAgo.setFullYear(today.getFullYear() - 1);
|
|
358
361
|
oneYearAgo.setDate(today.getDate() + 1);
|
|
@@ -365,13 +368,14 @@ class ActivityHeatmap {
|
|
|
365
368
|
const months = [];
|
|
366
369
|
const current = new Date(startDate);
|
|
367
370
|
|
|
368
|
-
// Generate weeks first
|
|
369
|
-
while (current <=
|
|
371
|
+
// Generate weeks first - include today completely
|
|
372
|
+
while (current <= todayEnd) {
|
|
370
373
|
const week = [];
|
|
371
374
|
|
|
372
375
|
for (let day = 0; day < 7; day++) {
|
|
373
|
-
if (current <=
|
|
374
|
-
|
|
376
|
+
if (current <= todayEnd) {
|
|
377
|
+
const dayDate = new Date(current);
|
|
378
|
+
week.push(dayDate);
|
|
375
379
|
} else {
|
|
376
380
|
week.push(null);
|
|
377
381
|
}
|
|
@@ -421,6 +425,7 @@ class ActivityHeatmap {
|
|
|
421
425
|
const level = this.getActivityLevel(activity);
|
|
422
426
|
const modeClass = this.currentMetric === 'tools' ? 'tools-mode' : '';
|
|
423
427
|
|
|
428
|
+
|
|
424
429
|
return `
|
|
425
430
|
<div class="heatmap-day level-${level} ${modeClass}"
|
|
426
431
|
data-date="${dateKey}"
|
|
@@ -606,7 +611,9 @@ class ActivityHeatmap {
|
|
|
606
611
|
|
|
607
612
|
if (!date) return;
|
|
608
613
|
|
|
609
|
-
|
|
614
|
+
// Fix timezone issue: parse date as local instead of UTC
|
|
615
|
+
const [year, month, dayNum] = date.split('-').map(Number);
|
|
616
|
+
const dateObj = new Date(year, month - 1, dayNum); // month is 0-indexed
|
|
610
617
|
const formattedDate = dateObj.toLocaleDateString('en-US', {
|
|
611
618
|
weekday: 'short',
|
|
612
619
|
month: 'short',
|
|
@@ -677,7 +684,16 @@ class ActivityHeatmap {
|
|
|
677
684
|
const titleElement = document.getElementById('activity-total');
|
|
678
685
|
|
|
679
686
|
if (titleElement) {
|
|
680
|
-
|
|
687
|
+
// Ensure totalActivity is a number
|
|
688
|
+
const activityCount = totalActivity || 0;
|
|
689
|
+
|
|
690
|
+
if (this.currentMetric === 'messages') {
|
|
691
|
+
titleElement.innerHTML = `${this.formatNumber(activityCount)} <span style="color: #ff7f50;">Claude Code</span> ${this.currentMetric} in the last year`;
|
|
692
|
+
} else if (this.currentMetric === 'tools') {
|
|
693
|
+
titleElement.innerHTML = `${this.formatNumber(activityCount)} <span style="color: #ff7f50;">Claude Code</span> ${this.currentMetric} in the last year`;
|
|
694
|
+
} else {
|
|
695
|
+
titleElement.innerHTML = `${this.formatNumber(activityCount)} ${this.currentMetric} in the last year`;
|
|
696
|
+
}
|
|
681
697
|
}
|
|
682
698
|
}
|
|
683
699
|
|
|
@@ -685,6 +701,11 @@ class ActivityHeatmap {
|
|
|
685
701
|
* Format large numbers with commas
|
|
686
702
|
*/
|
|
687
703
|
formatNumber(num) {
|
|
704
|
+
// Handle undefined, null, or non-numeric values
|
|
705
|
+
if (num == null || typeof num !== 'number' || isNaN(num)) {
|
|
706
|
+
return '0';
|
|
707
|
+
}
|
|
708
|
+
|
|
688
709
|
if (num >= 1000) {
|
|
689
710
|
return (num / 1000).toFixed(1) + 'k';
|
|
690
711
|
}
|
|
@@ -705,6 +726,29 @@ class ActivityHeatmap {
|
|
|
705
726
|
`;
|
|
706
727
|
}
|
|
707
728
|
|
|
729
|
+
/**
|
|
730
|
+
* Clear cache and refresh the heatmap data
|
|
731
|
+
*/
|
|
732
|
+
async clearCacheAndRefresh() {
|
|
733
|
+
try {
|
|
734
|
+
console.log('🔥 Clearing cache and refreshing heatmap data...');
|
|
735
|
+
|
|
736
|
+
// Clear frontend cache
|
|
737
|
+
this.dataService.clearCache();
|
|
738
|
+
|
|
739
|
+
// Clear backend cache
|
|
740
|
+
await fetch('/api/clear-cache', { method: 'POST' });
|
|
741
|
+
|
|
742
|
+
// Force reload activity data
|
|
743
|
+
await this.loadActivityData();
|
|
744
|
+
this.positionMonthLabels();
|
|
745
|
+
|
|
746
|
+
console.log('✅ Cache cleared and data refreshed');
|
|
747
|
+
} catch (error) {
|
|
748
|
+
console.error('❌ Error clearing cache:', error);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
708
752
|
/**
|
|
709
753
|
* Refresh the heatmap data
|
|
710
754
|
*/
|
|
@@ -447,6 +447,10 @@ class DashboardPage {
|
|
|
447
447
|
activityHeatmapContainer,
|
|
448
448
|
this.dataService
|
|
449
449
|
);
|
|
450
|
+
|
|
451
|
+
// Make globally accessible for debugging
|
|
452
|
+
window.activityHeatmap = this.components.activityHeatmap;
|
|
453
|
+
|
|
450
454
|
await this.components.activityHeatmap.initialize();
|
|
451
455
|
} catch (error) {
|
|
452
456
|
console.warn('ActivityHeatmap initialization failed:', error);
|
package/src/analytics.js
CHANGED
|
@@ -1191,11 +1191,74 @@ class ClaudeAnalytics {
|
|
|
1191
1191
|
}
|
|
1192
1192
|
});
|
|
1193
1193
|
|
|
1194
|
+
// Clear cache endpoint
|
|
1195
|
+
this.app.post('/api/clear-cache', async (req, res) => {
|
|
1196
|
+
try {
|
|
1197
|
+
console.log('🔥 Clear cache request received');
|
|
1198
|
+
|
|
1199
|
+
// Clear DataCache
|
|
1200
|
+
if (this.dataCache && typeof this.dataCache.clear === 'function') {
|
|
1201
|
+
this.dataCache.clear();
|
|
1202
|
+
console.log('🔥 Server DataCache cleared');
|
|
1203
|
+
} else {
|
|
1204
|
+
console.log('⚠️ DataCache not available or no clear method');
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// Also clear ConversationAnalyzer cache if available
|
|
1208
|
+
if (this.conversationAnalyzer && typeof this.conversationAnalyzer.clearCache === 'function') {
|
|
1209
|
+
this.conversationAnalyzer.clearCache();
|
|
1210
|
+
console.log('🔥 ConversationAnalyzer cache cleared');
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
res.json({
|
|
1214
|
+
success: true,
|
|
1215
|
+
message: 'Cache cleared successfully',
|
|
1216
|
+
timestamp: new Date().toISOString()
|
|
1217
|
+
});
|
|
1218
|
+
} catch (error) {
|
|
1219
|
+
console.error('❌ Error clearing cache:', error);
|
|
1220
|
+
res.status(500).json({
|
|
1221
|
+
error: 'Failed to clear cache',
|
|
1222
|
+
details: error.message
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
});
|
|
1226
|
+
|
|
1194
1227
|
// Activity heatmap data endpoint - needs full conversation history
|
|
1195
1228
|
this.app.get('/api/activity', async (req, res) => {
|
|
1196
1229
|
try {
|
|
1230
|
+
// TEMPORARY: Use test data for demo/screenshots
|
|
1231
|
+
console.log(`🔥 /api/activity called - using test data for demo...`);
|
|
1232
|
+
const fs = require('fs');
|
|
1233
|
+
const path = require('path');
|
|
1234
|
+
const testDataPath = path.join(__dirname, 'test-activity-data.json');
|
|
1235
|
+
|
|
1236
|
+
if (fs.existsSync(testDataPath)) {
|
|
1237
|
+
const testData = JSON.parse(fs.readFileSync(testDataPath, 'utf8'));
|
|
1238
|
+
|
|
1239
|
+
// Calculate totals
|
|
1240
|
+
const totalContributions = testData.reduce((sum, day) => sum + day.conversations, 0);
|
|
1241
|
+
const totalTools = testData.reduce((sum, day) => sum + day.tools, 0);
|
|
1242
|
+
const totalMessages = testData.reduce((sum, day) => sum + day.messages, 0);
|
|
1243
|
+
const totalTokens = testData.reduce((sum, day) => sum + day.tokens, 0);
|
|
1244
|
+
|
|
1245
|
+
const activityData = {
|
|
1246
|
+
dailyActivity: testData,
|
|
1247
|
+
totalContributions,
|
|
1248
|
+
activeDays: testData.length,
|
|
1249
|
+
longestStreak: 7, // Sample streak
|
|
1250
|
+
currentStreak: 3, // Sample current streak
|
|
1251
|
+
totalTools,
|
|
1252
|
+
totalMessages,
|
|
1253
|
+
totalTokens,
|
|
1254
|
+
timestamp: new Date().toISOString()
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
return res.json(activityData);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
// Fallback to real data if test file doesn't exist
|
|
1197
1261
|
console.log(`🔥 /api/activity called - loading all conversations...`);
|
|
1198
|
-
// Get all conversations without the 150 limit for accurate heatmap data
|
|
1199
1262
|
const allConversations = await this.conversationAnalyzer.loadConversations(this.stateCalculator);
|
|
1200
1263
|
console.log(`🔥 Loaded ${allConversations.length} conversations from server`);
|
|
1201
1264
|
|
|
@@ -2066,33 +2129,17 @@ class ClaudeAnalytics {
|
|
|
2066
2129
|
oneYearAgo.setHours(0, 0, 0, 0);
|
|
2067
2130
|
|
|
2068
2131
|
const today = new Date();
|
|
2069
|
-
|
|
2132
|
+
const todayEnd = new Date();
|
|
2133
|
+
todayEnd.setHours(23, 59, 59, 999);
|
|
2070
2134
|
|
|
2071
2135
|
console.log(`🔥 Generating activity data for ${conversations.length} conversations (FULL DATASET)...`);
|
|
2072
|
-
|
|
2073
|
-
// Show date range of conversations
|
|
2074
|
-
if (conversations.length > 0) {
|
|
2075
|
-
const dates = conversations.map(c => c.lastModified ? new Date(c.lastModified) : null).filter(Boolean);
|
|
2076
|
-
dates.sort((a, b) => a - b);
|
|
2077
|
-
console.log(`🔥 Server conversation date range: ${dates[0]?.toLocaleDateString()} to ${dates[dates.length - 1]?.toLocaleDateString()}`);
|
|
2078
|
-
|
|
2079
|
-
// Show some sample conversations with dates
|
|
2080
|
-
console.log(`🔥 First 3 conversations by date:`);
|
|
2081
|
-
const sortedConversations = conversations
|
|
2082
|
-
.filter(c => c.lastModified)
|
|
2083
|
-
.sort((a, b) => new Date(a.lastModified) - new Date(b.lastModified))
|
|
2084
|
-
.slice(0, 3);
|
|
2085
|
-
sortedConversations.forEach((conv, i) => {
|
|
2086
|
-
console.log(` ${i+1}: ${conv.filename} - ${new Date(conv.lastModified).toLocaleDateString()}`);
|
|
2087
|
-
});
|
|
2088
|
-
}
|
|
2089
2136
|
|
|
2090
2137
|
// Process conversations for daily activity
|
|
2091
2138
|
conversations.forEach(conversation => {
|
|
2092
2139
|
if (!conversation.lastModified) return;
|
|
2093
2140
|
|
|
2094
2141
|
const date = new Date(conversation.lastModified);
|
|
2095
|
-
if (date < oneYearAgo || date >
|
|
2142
|
+
if (date < oneYearAgo || date > todayEnd) return;
|
|
2096
2143
|
|
|
2097
2144
|
const dateKey = date.toISOString().split('T')[0]; // YYYY-MM-DD
|
|
2098
2145
|
|