claude-code-wrapped 0.1.10 → 0.1.11

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.
@@ -3,7 +3,8 @@
3
3
  "allow": [
4
4
  "WebFetch(domain:api.github.com)",
5
5
  "WebFetch(domain:github.com)",
6
- "WebFetch(domain:raw.githubusercontent.com)"
6
+ "WebFetch(domain:raw.githubusercontent.com)",
7
+ "Bash(uv run:*)"
7
8
  ]
8
9
  }
9
10
  }
@@ -1,3 +1,3 @@
1
1
  """Claude Code Wrapped - Your year with Claude Code, Spotify Wrapped style."""
2
2
 
3
- __version__ = "0.1.10"
3
+ __version__ = "0.1.11"
@@ -80,6 +80,7 @@ Examples:
80
80
  "total_input_tokens": stats.total_input_tokens,
81
81
  "total_output_tokens": stats.total_output_tokens,
82
82
  "active_days": stats.active_days,
83
+ "late_night_days": stats.late_night_days,
83
84
  "streak_longest": stats.streak_longest,
84
85
  "streak_current": stats.streak_current,
85
86
  "most_active_hour": stats.most_active_hour,
@@ -73,6 +73,9 @@ class WrappedStats:
73
73
  # Day of week distribution (0=Monday, 6=Sunday)
74
74
  weekday_distribution: list[int] = field(default_factory=lambda: [0] * 7)
75
75
 
76
+ # Late night coding days (unique dates with activity between midnight and 5am)
77
+ late_night_days: int = 0
78
+
76
79
  # Fun stats
77
80
  longest_conversation_tokens: int = 0
78
81
  avg_tokens_per_message: float = 0.0
@@ -205,6 +208,9 @@ def aggregate_stats(messages: list[Message], year: int) -> WrappedStats:
205
208
  session_tokens: dict[str, int] = Counter()
206
209
  session_first_time: dict[str, datetime] = {}
207
210
 
211
+ # Track late night coding dates (midnight to 5am)
212
+ late_night_dates: set[str] = set()
213
+
208
214
  # Process each message
209
215
  for msg in messages:
210
216
  stats.total_messages += 1
@@ -305,6 +311,10 @@ def aggregate_stats(messages: list[Message], year: int) -> WrappedStats:
305
311
  # Hourly distribution
306
312
  stats.hourly_distribution[msg.timestamp.hour] += 1
307
313
 
314
+ # Track late night days (midnight to 5am)
315
+ if 0 <= msg.timestamp.hour < 5:
316
+ late_night_dates.add(msg.timestamp.strftime("%Y-%m-%d"))
317
+
308
318
  # Weekday distribution
309
319
  stats.weekday_distribution[msg.timestamp.weekday()] += 1
310
320
 
@@ -339,6 +349,9 @@ def aggregate_stats(messages: list[Message], year: int) -> WrappedStats:
339
349
  if any(stats.hourly_distribution):
340
350
  stats.most_active_hour = stats.hourly_distribution.index(max(stats.hourly_distribution))
341
351
 
352
+ # Late night days count
353
+ stats.late_night_days = len(late_night_dates)
354
+
342
355
  # Top tools
343
356
  stats.top_tools = stats.tool_calls.most_common(10)
344
357
 
@@ -378,26 +391,21 @@ def aggregate_stats(messages: list[Message], year: int) -> WrappedStats:
378
391
  if longest_session[0] in session_first_time:
379
392
  stats.longest_conversation_date = session_first_time[longest_session[0]]
380
393
 
381
- # Calculate time periods for averages
382
- today = datetime.now()
383
- if year == today.year:
384
- total_days = (today - datetime(year, 1, 1)).days + 1
385
- else:
386
- total_days = 366 if year % 4 == 0 else 365
387
- total_weeks = max(1, total_days / 7)
388
- total_months = max(1, total_days / 30.44) # Average days per month
389
-
390
- # Message averages (over total time period, not just active days)
391
- if total_days > 0:
392
- stats.avg_messages_per_day = stats.total_messages / total_days
393
- stats.avg_messages_per_week = stats.total_messages / total_weeks
394
- stats.avg_messages_per_month = stats.total_messages / total_months
395
-
396
- # Cost averages
397
- if stats.estimated_cost is not None and total_days > 0:
398
- stats.avg_cost_per_day = stats.estimated_cost / total_days
399
- stats.avg_cost_per_week = stats.estimated_cost / total_weeks
400
- stats.avg_cost_per_month = stats.estimated_cost / total_months
394
+ # Calculate averages based on ACTIVE days (like ccusage)
395
+ active_days = stats.active_days if stats.active_days > 0 else 1
396
+ active_weeks = max(1, active_days / 7)
397
+ active_months = max(1, active_days / 30.44)
398
+
399
+ # Message averages (per active day)
400
+ stats.avg_messages_per_day = stats.total_messages / active_days
401
+ stats.avg_messages_per_week = stats.total_messages / active_weeks
402
+ stats.avg_messages_per_month = stats.total_messages / active_months
403
+
404
+ # Cost averages (per active day)
405
+ if stats.estimated_cost is not None:
406
+ stats.avg_cost_per_day = stats.estimated_cost / active_days
407
+ stats.avg_cost_per_week = stats.estimated_cost / active_weeks
408
+ stats.avg_cost_per_month = stats.estimated_cost / active_months
401
409
 
402
410
  # Token averages
403
411
  if stats.total_assistant_messages > 0:
@@ -407,9 +415,9 @@ def aggregate_stats(messages: list[Message], year: int) -> WrappedStats:
407
415
  stats.total_edits = stats.tool_calls.get("Edit", 0)
408
416
  stats.total_writes = stats.tool_calls.get("Write", 0)
409
417
  total_code_changes = stats.total_edits + stats.total_writes
410
- if total_days > 0:
411
- stats.avg_edits_per_day = total_code_changes / total_days
412
- stats.avg_edits_per_week = total_code_changes / total_weeks
418
+ if active_days > 0:
419
+ stats.avg_edits_per_day = total_code_changes / active_days
420
+ stats.avg_edits_per_week = total_code_changes / active_weeks
413
421
 
414
422
  return stats
415
423
 
@@ -268,10 +268,9 @@ def get_fun_facts(stats: WrappedStats) -> list[tuple[str, str]]:
268
268
  """Generate fun facts / bloopers based on stats - only 3 key facts."""
269
269
  facts = []
270
270
 
271
- # Late night coding (midnight to 5am)
272
- late_night = sum(stats.hourly_distribution[0:5])
273
- if late_night > 0:
274
- facts.append(("🌙", f"You coded after midnight {late_night:,} times. Sleep is overrated."))
271
+ # Late night coding days (midnight to 5am)
272
+ if stats.late_night_days > 0:
273
+ facts.append(("🌙", f"You coded after midnight on {stats.late_night_days} days. Sleep is overrated."))
275
274
 
276
275
  # Most active day insight
277
276
  if stats.most_active_day:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-wrapped",
3
- "version": "0.1.10",
3
+ "version": "0.1.11",
4
4
  "description": "Your year with Claude Code - Spotify Wrapped style terminal experience",
5
5
  "bin": {
6
6
  "claude-code-wrapped": "./bin/cli.js"
package/pyproject.toml CHANGED
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "claude-code-wrapped"
3
- version = "0.1.10"
3
+ version = "0.1.11"
4
4
  description = "Your year with Claude Code - Spotify Wrapped style terminal experience"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
package/uv.lock CHANGED
@@ -4,7 +4,7 @@ requires-python = ">=3.12"
4
4
 
5
5
  [[package]]
6
6
  name = "claude-code-wrapped"
7
- version = "0.1.7"
7
+ version = "0.1.10"
8
8
  source = { editable = "." }
9
9
  dependencies = [
10
10
  { name = "rich" },