claude-code-templates 1.8.1 → 1.8.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-templates",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
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": {
@@ -31,7 +31,7 @@
31
31
  "dev:link": "npm link",
32
32
  "dev:unlink": "npm unlink -g claude-code-templates",
33
33
  "pretest:commands": "npm run dev:link",
34
- "prepublishOnly": "echo 'Skipping tests for emergency publish'",
34
+ "prepublishOnly": "echo 'Skipping tests for emergency hotfix'",
35
35
  "analytics:start": "node src/analytics.js",
36
36
  "analytics:test": "npm run test:analytics"
37
37
  },
@@ -125,7 +125,7 @@ class ConversationAnalyzer {
125
125
  status: stateCalculator.determineConversationStatus(parsedMessages, stats.mtime),
126
126
  conversationState: stateCalculator.determineConversationState(parsedMessages, stats.mtime),
127
127
  statusSquares: await this.getCachedStatusSquares(filePath, parsedMessages),
128
- parsedMessages: parsedMessages, // Include parsed messages for session analysis
128
+ // parsedMessages removed to prevent memory leak - available via cache when needed
129
129
  };
130
130
 
131
131
  conversations.push(conversation);
@@ -96,20 +96,20 @@ class FileWatcher {
96
96
  * Setup periodic refresh intervals
97
97
  */
98
98
  setupPeriodicRefresh() {
99
- // Periodic refresh to catch any missed changes
99
+ // Periodic refresh to catch any missed changes (reduced frequency)
100
100
  const dataRefreshInterval = setInterval(async () => {
101
101
  console.log(chalk.blue('⏱️ Periodic data refresh...'));
102
102
  await this.triggerDataRefresh();
103
- }, 30000); // Every 30 seconds
103
+ }, 120000); // Every 2 minutes (reduced from 30 seconds)
104
104
 
105
105
  this.intervals.push(dataRefreshInterval);
106
106
 
107
- // More frequent updates for active processes (every 10 seconds)
107
+ // Process updates for active processes (reduced frequency)
108
108
  const processRefreshInterval = setInterval(async () => {
109
109
  if (this.processRefreshCallback) {
110
110
  await this.processRefreshCallback();
111
111
  }
112
- }, 10000);
112
+ }, 30000); // Every 30 seconds (reduced from 10 seconds)
113
113
 
114
114
  this.intervals.push(processRefreshInterval);
115
115
  }
@@ -127,6 +127,38 @@ class SessionAnalyzer {
127
127
  };
128
128
  }
129
129
 
130
+ /**
131
+ * Generate estimated messages for session analysis when parsedMessages is not available
132
+ * @param {Object} conversation - Conversation object
133
+ * @returns {Array} Array of estimated message objects
134
+ */
135
+ generateEstimatedMessages(conversation) {
136
+ const messages = [];
137
+ const messageCount = conversation.messageCount || 0;
138
+ const created = new Date(conversation.created);
139
+ const lastModified = new Date(conversation.lastModified);
140
+
141
+ if (messageCount === 0) return messages;
142
+
143
+ // Estimate message distribution over time
144
+ const timeDiff = lastModified - created;
145
+ const timePerMessage = timeDiff / messageCount;
146
+
147
+ // Generate alternating user/assistant messages
148
+ for (let i = 0; i < messageCount; i++) {
149
+ const timestamp = new Date(created.getTime() + (i * timePerMessage));
150
+ const role = i % 2 === 0 ? 'user' : 'assistant';
151
+
152
+ messages.push({
153
+ timestamp: timestamp,
154
+ role: role,
155
+ usage: conversation.tokenUsage || null
156
+ });
157
+ }
158
+
159
+ return messages;
160
+ }
161
+
130
162
  /**
131
163
  * Extract 5-hour sliding window sessions from conversations
132
164
  * @param {Array} conversations - Array of conversation objects
@@ -137,15 +169,16 @@ class SessionAnalyzer {
137
169
  const allMessages = [];
138
170
 
139
171
  conversations.forEach(conversation => {
140
- if (!conversation.parsedMessages || conversation.parsedMessages.length === 0) {
172
+ // Skip conversations without message count or with zero messages
173
+ if (!conversation.messageCount || conversation.messageCount === 0) {
141
174
  return;
142
175
  }
143
176
 
144
- const sortedMessages = conversation.parsedMessages.sort((a, b) =>
145
- new Date(a.timestamp) - new Date(b.timestamp)
146
- );
177
+ // Generate estimated messages based on token usage and timestamps
178
+ // This is a fallback when parsedMessages is not available
179
+ const estimatedMessages = this.generateEstimatedMessages(conversation);
147
180
 
148
- sortedMessages.forEach(message => {
181
+ estimatedMessages.forEach(message => {
149
182
  allMessages.push({
150
183
  timestamp: message.timestamp,
151
184
  role: message.role,
@@ -268,15 +301,16 @@ class SessionAnalyzer {
268
301
  const allMessages = [];
269
302
 
270
303
  conversations.forEach(conversation => {
271
- if (!conversation.parsedMessages || conversation.parsedMessages.length === 0) {
304
+ // Skip conversations without message count or with zero messages
305
+ if (!conversation.messageCount || conversation.messageCount === 0) {
272
306
  return;
273
307
  }
274
308
 
275
- const sortedMessages = conversation.parsedMessages.sort((a, b) =>
276
- new Date(a.timestamp) - new Date(b.timestamp)
277
- );
309
+ // Generate estimated messages based on token usage and timestamps
310
+ // This is a fallback when parsedMessages is not available
311
+ const estimatedMessages = this.generateEstimatedMessages(conversation);
278
312
 
279
- sortedMessages.forEach(message => {
313
+ estimatedMessages.forEach(message => {
280
314
  allMessages.push({
281
315
  timestamp: message.timestamp,
282
316
  role: message.role,
@@ -32,14 +32,14 @@ class DataCache {
32
32
  projectStats: new Map(), // projectPath -> { data, timestamp }
33
33
  };
34
34
 
35
- // Cache configuration
35
+ // Cache configuration (reduced TTL for aggressive memory management)
36
36
  this.config = {
37
- fileContentTTL: 60000, // 1 minute for file content
38
- parsedDataTTL: 30000, // 30 seconds for parsed data
39
- computationTTL: 20000, // 20 seconds for expensive computations
40
- metadataTTL: 10000, // 10 seconds for metadata
37
+ fileContentTTL: 30000, // 30 seconds for file content (reduced from 60s)
38
+ parsedDataTTL: 15000, // 15 seconds for parsed data (reduced from 30s)
39
+ computationTTL: 10000, // 10 seconds for expensive computations (reduced from 20s)
40
+ metadataTTL: 5000, // 5 seconds for metadata (reduced from 10s)
41
41
  processTTL: 500, // 500ms for process data
42
- maxCacheSize: 100, // Reduced from 1000 to 100 to prevent memory buildup
42
+ maxCacheSize: 25, // Aggressively reduced to 25 to prevent memory buildup
43
43
  };
44
44
 
45
45
  // Dependency tracking for smart invalidation
@@ -55,11 +55,11 @@ class DataCache {
55
55
  evictions: 0
56
56
  };
57
57
 
58
- // Start automatic cleanup interval
58
+ // Start automatic cleanup interval (more aggressive)
59
59
  this.cleanupInterval = setInterval(() => {
60
60
  this.evictOldEntries();
61
61
  this.enforceSizeLimits();
62
- }, 30000); // Every 30 seconds
62
+ }, 15000); // Every 15 seconds (reduced from 30 seconds)
63
63
  }
64
64
 
65
65
  /**
package/src/analytics.js CHANGED
@@ -530,6 +530,14 @@ class ClaudeAnalytics {
530
530
  // Calculate detailed token usage
531
531
  const detailedTokenUsage = this.calculateDetailedTokenUsage();
532
532
 
533
+ // Memory cleanup: limit conversation history to prevent memory buildup
534
+ if (this.data.conversations && this.data.conversations.length > 150) {
535
+ console.log(chalk.yellow(`🧹 Cleaning up conversation history: ${this.data.conversations.length} -> 150`));
536
+ this.data.conversations = this.data.conversations
537
+ .sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified))
538
+ .slice(0, 150);
539
+ }
540
+
533
541
  // Add timestamp to verify data freshness
534
542
  const dataWithTimestamp = {
535
543
  ...this.data,
@@ -798,6 +806,19 @@ class ClaudeAnalytics {
798
806
  }
799
807
  }
800
808
 
809
+ // Memory cleanup: limit conversation history to prevent memory buildup
810
+ if (this.data.conversations.length > 100) {
811
+ console.log(chalk.yellow(`🧹 Cleaning up conversation history: ${this.data.conversations.length} -> 100`));
812
+ this.data.conversations = this.data.conversations
813
+ .sort((a, b) => new Date(b.lastModified) - new Date(a.lastModified))
814
+ .slice(0, 100);
815
+ }
816
+
817
+ // Force garbage collection hint
818
+ if (global.gc) {
819
+ global.gc();
820
+ }
821
+
801
822
  const dataWithTimestamp = {
802
823
  conversations: this.data.conversations,
803
824
  summary: this.data.summary,