claude-code-templates 1.28.4 → 1.28.6

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.28.4",
3
+ "version": "1.28.6",
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": {
@@ -348,23 +348,41 @@ class YearInReview2025 {
348
348
  * @returns {Array} Heatmap data by week
349
349
  */
350
350
  generateActivityHeatmap(conversations) {
351
+ console.log(`\nšŸ”„šŸ”„šŸ”„ GENERATING HEATMAP for ${conversations.length} conversations\n`);
352
+
351
353
  // Create map of day -> activity count, tools, and models
352
354
  const dailyActivity = new Map();
353
355
 
354
- conversations.forEach(conv => {
356
+ conversations.forEach((conv, idx) => {
355
357
  if (conv.lastModified) {
356
358
  const date = new Date(conv.lastModified);
357
359
  const dayKey = date.toISOString().split('T')[0];
358
360
 
361
+ if (idx < 3) {
362
+ console.log(` šŸ“ Conv ${idx}: id=${conv.id}, tokens=${conv.tokens}, tokenUsage.total=${conv.tokenUsage?.total}`);
363
+ }
364
+
359
365
  const current = dailyActivity.get(dayKey) || {
360
366
  count: 0,
361
367
  tools: [],
362
368
  models: [],
363
369
  modelCounts: {},
364
- toolCounts: {}
370
+ toolCounts: {},
371
+ tokens: 0
365
372
  };
366
373
  current.count += 1;
367
374
 
375
+ // Add tokens from this conversation
376
+ if (conv.tokenUsage && conv.tokenUsage.total) {
377
+ current.tokens += conv.tokenUsage.total;
378
+ if (idx < 3) console.log(` šŸ’Ž Added ${conv.tokenUsage.total} tokens from conv ${conv.id} to ${dayKey}`);
379
+ } else if (conv.tokens) {
380
+ current.tokens += conv.tokens;
381
+ if (idx < 3) console.log(` šŸ’Ž Added ${conv.tokens} tokens (fallback) from conv ${conv.id} to ${dayKey}`);
382
+ } else {
383
+ if (idx < 3) console.log(` āš ļø Conv ${conv.id} has NO token data`);
384
+ }
385
+
368
386
  // Count tool usage with actual numbers from toolStats
369
387
  if (conv.toolUsage && conv.toolUsage.toolStats) {
370
388
  Object.entries(conv.toolUsage.toolStats).forEach(([tool, count]) => {
@@ -411,7 +429,8 @@ class YearInReview2025 {
411
429
  tools: [],
412
430
  models: [],
413
431
  toolCounts: {},
414
- modelCounts: {}
432
+ modelCounts: {},
433
+ tokens: 0
415
434
  };
416
435
 
417
436
  // Determine intensity level (0-4 like GitHub)
@@ -428,6 +447,7 @@ class YearInReview2025 {
428
447
  models: dayData.models,
429
448
  toolCounts: dayData.toolCounts,
430
449
  modelCounts: dayData.modelCounts,
450
+ tokens: dayData.tokens,
431
451
  level,
432
452
  day: currentDate.getDay()
433
453
  });
@@ -904,19 +924,54 @@ class YearInReview2025 {
904
924
  }
905
925
 
906
926
  const subagents = Array.from(agentData.values());
907
- const subagentEvents = subagents
908
- .filter(agent => agent.timestamp && agent.timestamp.getFullYear() === 2025)
909
- .map(agent => ({
910
- name: `${agent.type}-${agent.id.substring(0, 4)}`, // e.g., "Plan-a68a" or "Explore-a1e4"
911
- timestamp: agent.timestamp,
912
- type: agent.type
913
- }))
914
- .sort((a, b) => a.timestamp - b.timestamp);
927
+
928
+ // Group subagents by type for cleaner visualization
929
+ const groupedByType = {};
930
+ subagents.forEach(agent => {
931
+ const type = agent.type || 'Unknown';
932
+ if (!groupedByType[type]) {
933
+ groupedByType[type] = { count: 0, timestamps: [] };
934
+ }
935
+ groupedByType[type].count++;
936
+ if (agent.timestamp && agent.timestamp.getFullYear() === 2025) {
937
+ groupedByType[type].timestamps.push(agent.timestamp);
938
+ }
939
+ });
940
+
941
+ // Create events grouped by type (one event per type per day)
942
+ const subagentEvents = [];
943
+ Object.entries(groupedByType).forEach(([type, data]) => {
944
+ // Group timestamps by day to avoid too many events
945
+ const dayMap = new Map();
946
+ data.timestamps.forEach(ts => {
947
+ const dayKey = ts.toISOString().split('T')[0];
948
+ if (!dayMap.has(dayKey)) {
949
+ dayMap.set(dayKey, { count: 0, timestamp: ts });
950
+ }
951
+ dayMap.get(dayKey).count++;
952
+ });
953
+
954
+ // Create one event per day per type
955
+ dayMap.forEach((dayData, dayKey) => {
956
+ subagentEvents.push({
957
+ name: type, // Just "Plan" or "Explore", not "Plan-a68a"
958
+ timestamp: dayData.timestamp,
959
+ type: type,
960
+ count: dayData.count // How many times used that day
961
+ });
962
+ });
963
+ });
964
+
965
+ subagentEvents.sort((a, b) => a.timestamp - b.timestamp);
915
966
 
916
967
  return {
917
- subagents: subagents.map(a => ({ id: a.id, type: a.type })),
968
+ subagents: Object.entries(groupedByType).map(([type, data]) => ({
969
+ type,
970
+ count: data.count
971
+ })),
918
972
  total: subagents.length,
919
- events: subagentEvents
973
+ events: subagentEvents,
974
+ grouped: groupedByType // Include grouped data for display
920
975
  };
921
976
  } catch (error) {
922
977
  console.warn('Could not analyze subagents:', error.message);
@@ -60,10 +60,7 @@
60
60
  }
61
61
 
62
62
  .current-date {
63
- font-size: 32px;
64
- font-weight: 700;
65
- color: var(--text-accent);
66
- margin-bottom: 15px;
63
+ display: none;
67
64
  }
68
65
 
69
66
  .stat-line {
@@ -134,13 +131,7 @@
134
131
  }
135
132
 
136
133
  .timeline {
137
- position: absolute;
138
- bottom: 30px;
139
- left: 50%;
140
- transform: translateX(-50%);
141
- width: 80%;
142
- max-width: 1000px;
143
- pointer-events: auto;
134
+ display: none;
144
135
  }
145
136
 
146
137
  .timeline-bar {
@@ -1637,19 +1628,20 @@
1637
1628
  }
1638
1629
 
1639
1630
  if (data.subagents && data.subagents.events) {
1640
- console.log(`šŸ¤– Adding ${data.subagents.events.length} subagent events to timeline`);
1631
+ console.log(`šŸ¤– Adding ${data.subagents.events.length} subagent events to timeline (grouped by type)`);
1641
1632
  data.subagents.events.forEach((event, index) => {
1642
1633
  const eventDate = new Date(event.timestamp);
1643
1634
  const eventDayOfYear = getDayOfYear(eventDate);
1644
1635
  timeline.push({
1645
1636
  type: 'component-layer2',
1646
1637
  componentType: 'subagent',
1647
- name: event.name,
1638
+ name: event.name, // Now just "Plan" or "Explore", not "Plan-a68a"
1648
1639
  date: eventDate,
1649
- dayOfYear: eventDayOfYear
1640
+ dayOfYear: eventDayOfYear,
1641
+ count: event.count || 1 // How many times used that day
1650
1642
  });
1651
1643
  if (index === 0) {
1652
- console.log(` - First subagent "${event.name}": date=${eventDate.toLocaleDateString()}, dayOfYear=${eventDayOfYear.toFixed(3)}`);
1644
+ console.log(` - First subagent "${event.name}": date=${eventDate.toLocaleDateString()}, dayOfYear=${eventDayOfYear.toFixed(3)}, count=${event.count || 1}`);
1653
1645
  }
1654
1646
  });
1655
1647
  }
@@ -1717,9 +1709,57 @@
1717
1709
  animate();
1718
1710
  }
1719
1711
 
1712
+ // Frame counter for periodic recalculations
1713
+ let frameCount = 0;
1714
+
1720
1715
  // Animation loop
1716
+ // Collision detection and resolution
1717
+ function resolveCollisions() {
1718
+ const allNodes = [];
1719
+
1720
+ // Collect all nodes
1721
+ toolNodes.forEach(node => allNodes.push(node));
1722
+ componentNodes.forEach(node => allNodes.push(node));
1723
+ modelNodes.forEach(node => allNodes.push(node));
1724
+
1725
+ // Check each pair for collision
1726
+ for (let i = 0; i < allNodes.length; i++) {
1727
+ for (let j = i + 1; j < allNodes.length; j++) {
1728
+ const nodeA = allNodes[i];
1729
+ const nodeB = allNodes[j];
1730
+
1731
+ const dx = nodeB.x - nodeA.x;
1732
+ const dy = nodeB.y - nodeA.y;
1733
+ const distance = Math.sqrt(dx * dx + dy * dy);
1734
+ const minDistance = nodeA.size + nodeB.size + 10; // 10px padding
1735
+
1736
+ if (distance < minDistance && distance > 0) {
1737
+ // Nodes are overlapping, push them apart
1738
+ const overlap = minDistance - distance;
1739
+ const angle = Math.atan2(dy, dx);
1740
+
1741
+ // Move each node half the overlap distance
1742
+ const moveX = Math.cos(angle) * overlap * 0.5;
1743
+ const moveY = Math.sin(angle) * overlap * 0.5;
1744
+
1745
+ nodeA.x -= moveX;
1746
+ nodeA.y -= moveY;
1747
+ nodeB.x += moveX;
1748
+ nodeB.y += moveY;
1749
+
1750
+ // Also update target positions to prevent snapping back
1751
+ nodeA.targetX -= moveX * 0.1;
1752
+ nodeA.targetY -= moveY * 0.1;
1753
+ nodeB.targetX += moveX * 0.1;
1754
+ nodeB.targetY += moveY * 0.1;
1755
+ }
1756
+ }
1757
+ }
1758
+ }
1759
+
1721
1760
  function animate() {
1722
1761
  requestAnimationFrame(animate);
1762
+ frameCount++;
1723
1763
 
1724
1764
  // Clear canvas (before transform)
1725
1765
  ctx.fillStyle = '#0a0a0f';
@@ -1729,6 +1769,13 @@
1729
1769
  updateAnimationState();
1730
1770
  }
1731
1771
 
1772
+ // Recalculate percentages periodically (every 30 frames ~0.5s)
1773
+ if (frameCount % 30 === 0) {
1774
+ recalculateToolPercentages();
1775
+ recalculateComponentPercentages();
1776
+ recalculateModelPercentages();
1777
+ }
1778
+
1732
1779
  // Apply zoom and pan transformations
1733
1780
  ctx.save();
1734
1781
  ctx.translate(panX, panY);
@@ -1785,6 +1832,9 @@
1785
1832
  node.draw(ctx);
1786
1833
  });
1787
1834
 
1835
+ // Resolve collisions between all nodes
1836
+ resolveCollisions();
1837
+
1788
1838
  // Update and draw all nodes
1789
1839
  Object.values(branches).forEach(branch => {
1790
1840
  branch.nodes.forEach(node => {
@@ -1843,15 +1893,13 @@
1843
1893
 
1844
1894
  currentDayIndex = rangeStart + Math.floor(progress * rangeDuration);
1845
1895
 
1846
- document.getElementById('timelineProgress').style.width = `${progress * 100}%`;
1847
-
1848
- // Use startDate from data
1849
- const date = new Date(animationData.startDate);
1850
- const dayOffset = currentDayIndex - rangeStart;
1851
- date.setDate(date.getDate() + dayOffset);
1852
-
1853
- const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
1854
- document.getElementById('currentDate').textContent = `${monthNames[date.getMonth()]} ${date.getDate()}`;
1896
+ // Timeline and date display removed - no need to update
1897
+ // document.getElementById('timelineProgress').style.width = `${progress * 100}%`;
1898
+ // const date = new Date(animationData.startDate);
1899
+ // const dayOffset = currentDayIndex - rangeStart;
1900
+ // date.setDate(date.getDate() + dayOffset);
1901
+ // const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
1902
+ // document.getElementById('currentDate').textContent = `${monthNames[date.getMonth()]} ${date.getDate()}`;
1855
1903
 
1856
1904
  // Process events
1857
1905
  let eventsThisFrame = 0;
@@ -1870,20 +1918,41 @@
1870
1918
  stats.conversations += event.count;
1871
1919
  stats.tools += actualToolCount;
1872
1920
 
1873
- // Add tool beams using actual counts
1921
+ // Add tool counts directly (optimized - no individual beams)
1874
1922
  if (event.toolCounts) {
1875
1923
  Object.entries(event.toolCounts).forEach(([tool, count]) => {
1876
- console.log(` šŸ”§ Adding ${count} beams for tool: ${tool}`);
1877
- // Create multiple beams based on actual usage count
1924
+ // Get or create tool node and update count directly
1925
+ const toolColors = {
1926
+ 'Read': '#60a5fa', 'Write': '#34d399', 'Edit': '#fbbf24',
1927
+ 'Bash': '#f87171', 'TodoWrite': '#a78bfa', 'Task': '#fb923c',
1928
+ 'Glob': '#2dd4bf', 'Grep': '#c084fc', 'WebFetch': '#f472b6',
1929
+ 'WebSearch': '#818cf8', 'KillShell': '#ef4444', 'TaskOutput': '#06b6d4'
1930
+ };
1931
+ const color = toolColors[tool] || '#3b82f6';
1932
+ const node = getOrCreateToolNode(tool, color);
1933
+
1934
+ // Add all uses at once (much faster than creating beams)
1878
1935
  for (let i = 0; i < count; i++) {
1879
- setTimeout(() => addToolBeam(tool), Math.random() * 1000 + i * 50);
1936
+ node.addUse();
1880
1937
  }
1938
+
1939
+ // Create only ONE visual beam per tool (not per use)
1940
+ setTimeout(() => addToolBeam(tool), Math.random() * 300);
1941
+
1942
+ console.log(` šŸ”§ Tool ${tool}: +${count} uses (total: ${node.count})`);
1881
1943
  });
1882
1944
  } else {
1883
1945
  // Fallback to old method if toolCounts not available
1884
1946
  event.tools.forEach(tool => {
1885
- console.log(` šŸ”§ Adding tool beam: ${tool}`);
1886
- setTimeout(() => addToolBeam(tool), Math.random() * 500);
1947
+ const toolColors = {
1948
+ 'Read': '#60a5fa', 'Write': '#34d399', 'Edit': '#fbbf24',
1949
+ 'Bash': '#f87171', 'TodoWrite': '#a78bfa', 'Task': '#fb923c',
1950
+ 'Glob': '#2dd4bf', 'Grep': '#c084fc'
1951
+ };
1952
+ const color = toolColors[tool] || '#3b82f6';
1953
+ const node = getOrCreateToolNode(tool, color);
1954
+ node.addUse();
1955
+ setTimeout(() => addToolBeam(tool), Math.random() * 300);
1887
1956
  });
1888
1957
  }
1889
1958
 
@@ -1922,13 +1991,18 @@
1922
1991
  // showEvent(`Installed: ${event.name}`); // Disabled - notifications removed
1923
1992
  } else if (event.type === 'component-layer2') {
1924
1993
  const node = getOrCreateComponentNode(event.name, event.componentType);
1925
- node.addUse();
1994
+
1995
+ // Add uses based on event count (for grouped subagents)
1996
+ const useCount = event.count || 1;
1997
+ for (let j = 0; j < useCount; j++) {
1998
+ node.addUse();
1999
+ }
1926
2000
 
1927
2001
  // Create beam to this component node
1928
2002
  const beam = new Beam(node, event.name);
1929
2003
  beams.push(beam);
1930
2004
 
1931
- console.log(`šŸ”· ${event.componentType}: ${event.name} at ${event.date?.toLocaleDateString()} (count: ${node.count}, size: ${node.targetSize.toFixed(1)})`);
2005
+ console.log(`šŸ”· ${event.componentType}: ${event.name} at ${event.date?.toLocaleDateString()} (added: ${useCount}, total: ${node.count}, size: ${node.targetSize.toFixed(1)})`);
1932
2006
  }
1933
2007
  }
1934
2008
  });
@@ -2001,7 +2075,6 @@
2001
2075
  item.innerHTML = `
2002
2076
  <div class="legend-dot" style="background: ${model.color};"></div>
2003
2077
  <span>${model.name}</span>
2004
- <span style="margin-left: auto; color: rgba(255,255,255,0.5); font-size: 11px;">${model.count}</span>
2005
2078
  `;
2006
2079
  modelsList.appendChild(item);
2007
2080
  });
@@ -2031,7 +2104,6 @@
2031
2104
  item.innerHTML = `
2032
2105
  <div class="legend-dot" style="background: ${tool.color};"></div>
2033
2106
  <span>${tool.name}</span>
2034
- <span style="margin-left: auto; color: rgba(255,255,255,0.5); font-size: 11px;">${tool.count}</span>
2035
2107
  `;
2036
2108
  toolsList.appendChild(item);
2037
2109
  });
@@ -2068,7 +2140,6 @@
2068
2140
  item.innerHTML = `
2069
2141
  <div class="legend-dot" style="background: ${component.color};"></div>
2070
2142
  <span>${component.name}</span>
2071
- <span style="margin-left: auto; color: rgba(255,255,255,0.5); font-size: 11px;">${component.count}</span>
2072
2143
  `;
2073
2144
  componentsList.appendChild(item);
2074
2145
  });
@@ -2081,6 +2152,7 @@
2081
2152
  shownMilestones.clear();
2082
2153
  currentDayIndex = 0;
2083
2154
  beams = [];
2155
+ permanentConnections.clear(); // Clear permanent connection beams
2084
2156
  toolNodes.clear(); // Clear tool nodes
2085
2157
  uniqueTools.clear(); // Clear unique tools
2086
2158
  modelNodes.clear(); // Clear model nodes