Files
claude-code/skills/usage/scripts/usage_report.py
OpenCode Test d9be8145f8 Refactor remaining skills with resources pattern and allowed-tools
- k8s-quick-status: Add scripts/quick-status.sh, allowed-tools
- sysadmin-health: Add scripts/health-check.sh, allowed-tools
- usage: Add scripts/usage_report.py, simplify SKILL.md
- programmer-add-project: Add allowed-tools

All skills now:
- Have executable scripts for main operations
- Use allowed-tools to restrict capabilities
- Have improved descriptions with trigger phrases
- Follow the "Skill with Bundled Resources" pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 02:38:58 -08:00

110 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Generate usage statistics from session history."""
import json
import sys
from datetime import datetime, timedelta
from pathlib import Path
from zoneinfo import ZoneInfo
LOCAL_TZ = ZoneInfo('America/Los_Angeles')
HISTORY_DIR = Path.home() / ".claude/state/personal-assistant/history"
CONFIG_PATH = Path.home() / ".claude/state/usage/config.json"
def load_sessions():
"""Load sessions from history index."""
index_path = HISTORY_DIR / "index.json"
if not index_path.exists():
return []
with open(index_path) as f:
data = json.load(f)
return data.get("sessions", [])
def filter_sessions(sessions, range_type="week"):
"""Filter sessions by time range."""
now = datetime.now(LOCAL_TZ)
if range_type == "today":
cutoff = now.replace(hour=0, minute=0, second=0, microsecond=0)
elif range_type == "week":
cutoff = now - timedelta(days=7)
elif range_type == "month":
cutoff = now - timedelta(days=30)
else: # all
return sessions
filtered = []
for s in sessions:
try:
started = datetime.fromisoformat(s["started"])
if started.tzinfo is None:
started = started.replace(tzinfo=LOCAL_TZ)
if started >= cutoff:
filtered.append(s)
except (KeyError, ValueError):
continue
return filtered
def estimate_duration(sessions):
"""Estimate session duration from consecutive start times."""
if not sessions:
return []
sorted_sessions = sorted(sessions, key=lambda s: s["started"])
for i, session in enumerate(sorted_sessions):
if i + 1 < len(sorted_sessions):
start = datetime.fromisoformat(session["started"])
next_start = datetime.fromisoformat(sorted_sessions[i + 1]["started"])
duration = (next_start - start).total_seconds() / 60
# Cap at 2 hours (likely session gap)
session["duration_mins"] = min(duration, 120)
else:
# Current/last session: estimate 30 mins
session["duration_mins"] = 30
return sorted_sessions
def generate_report(sessions, range_type="week"):
"""Generate usage report."""
sessions = estimate_duration(sessions)
total_mins = sum(s.get("duration_mins", 0) for s in sessions)
hours = int(total_mins // 60)
mins = int(total_mins % 60)
# Group by date
by_date = {}
for s in sessions:
date = s["started"][:10]
by_date.setdefault(date, []).append(s)
report = f"""📊 Usage Summary — {range_type.title()}
Sessions: {len(sessions)}
Total time: {hours}h {mins}m
Days active: {len(by_date)}
Model: opus (primary)
"""
if by_date:
report += "\n📅 Sessions by Date:\n"
for date in sorted(by_date.keys(), reverse=True)[:7]:
count = len(by_date[date])
day_mins = sum(s.get("duration_mins", 0) for s in by_date[date])
report += f" {date}: {count} sessions ({int(day_mins)}m)\n"
return report
def main():
range_type = sys.argv[1] if len(sys.argv) > 1 else "week"
sessions = load_sessions()
filtered = filter_sessions(sessions, range_type)
report = generate_report(filtered, range_type)
print(report)
if __name__ == "__main__":
main()