Created
June 7, 2026 14:29
-
-
Save Deepti0512/372b8e4e1a0779d3a0cac664f4301614 to your computer and use it in GitHub Desktop.
Claude Code Token Usage Dashboard — one-command setup for your team. Run: curl -fsSL <raw-url> | bash
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| set -euo pipefail | |
| # ============================================================ | |
| # Claude Code Token Usage Dashboard — One-Command Setup | |
| # ============================================================ | |
| # Run with: curl -fsSL <your-gist-raw-url> | bash | |
| # | |
| # What this does: | |
| # 1. Checks Claude Code is installed | |
| # 2. Installs the token-optimizer plugin (if not already) | |
| # 3. Generates a token usage dashboard (7-day + 30-day metrics) | |
| # 4. Opens it in your browser | |
| # | |
| # Safe to re-run — idempotent. | |
| # ============================================================ | |
| BOLD='\033[1m' | |
| GREEN='\033[0;32m' | |
| YELLOW='\033[0;33m' | |
| RED='\033[0;31m' | |
| CYAN='\033[0;36m' | |
| NC='\033[0m' | |
| info() { echo -e "${CYAN}[info]${NC} $*"; } | |
| success() { echo -e "${GREEN}[done]${NC} $*"; } | |
| warn() { echo -e "${YELLOW}[warn]${NC} $*"; } | |
| fail() { echo -e "${RED}[error]${NC} $*"; exit 1; } | |
| echo "" | |
| echo -e "${BOLD}╔══════════════════════════════════════════════════╗${NC}" | |
| echo -e "${BOLD}║ Claude Code — Token Usage Dashboard Setup ║${NC}" | |
| echo -e "${BOLD}╚══════════════════════════════════════════════════╝${NC}" | |
| echo "" | |
| # ----------------------------------------------------------- | |
| # Step 1: Check prerequisites | |
| # ----------------------------------------------------------- | |
| info "Checking prerequisites..." | |
| if ! command -v claude &>/dev/null; then | |
| fail "Claude Code CLI not found. Install it first: https://docs.anthropic.com/en/docs/claude-code/overview" | |
| fi | |
| success "Claude Code CLI found" | |
| if ! command -v python3 &>/dev/null; then | |
| fail "Python 3 is required but not found." | |
| fi | |
| success "Python 3 found" | |
| # ----------------------------------------------------------- | |
| # Step 2: Install token-optimizer plugin (if needed) | |
| # ----------------------------------------------------------- | |
| MEASURE_PY="" | |
| for f in "$HOME/.claude/skills/token-optimizer/scripts/measure.py" \ | |
| "$HOME/.claude/plugins/cache"/*/token-optimizer/*/skills/token-optimizer/scripts/measure.py; do | |
| [ -f "$f" ] && MEASURE_PY="$f" && break | |
| done | |
| if [ -z "$MEASURE_PY" ]; then | |
| info "Token Optimizer plugin not found. Installing..." | |
| # Add marketplace if not already added | |
| SETTINGS="$HOME/.claude/settings.json" | |
| MARKETPLACE_URL="https://raw.githubusercontent.com/AuracleTech/token-optimizer/refs/heads/main/marketplace.json" | |
| if [ -f "$SETTINGS" ]; then | |
| if ! grep -q "token-optimizer" "$SETTINGS" 2>/dev/null; then | |
| # Backup settings | |
| cp "$SETTINGS" "$SETTINGS.bak.$(date +%s)" | |
| if command -v jq &>/dev/null; then | |
| jq --arg url "$MARKETPLACE_URL" \ | |
| '.extraKnownMarketplaces = ((.extraKnownMarketplaces // []) + [$url] | unique)' \ | |
| "$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS" | |
| else | |
| warn "jq not found — please install token-optimizer manually:" | |
| echo " In Claude Code, run: /install-plugin alexgreensh-token-optimizer" | |
| echo " Then re-run this script." | |
| exit 1 | |
| fi | |
| fi | |
| fi | |
| # Try to install via Claude CLI | |
| info "Attempting plugin installation via Claude Code..." | |
| echo "Please run the following in Claude Code to complete plugin setup:" | |
| echo "" | |
| echo -e " ${BOLD}/install-plugin alexgreensh-token-optimizer${NC}" | |
| echo "" | |
| echo "Then re-run this script." | |
| echo "" | |
| # Check again after potential manual install | |
| for f in "$HOME/.claude/plugins/cache"/*/token-optimizer/*/skills/token-optimizer/scripts/measure.py; do | |
| [ -f "$f" ] && MEASURE_PY="$f" && break | |
| done | |
| if [ -z "$MEASURE_PY" ]; then | |
| warn "Plugin not yet installed. Proceeding with basic dashboard (no trends data)..." | |
| NO_PLUGIN=true | |
| fi | |
| else | |
| success "Token Optimizer plugin found" | |
| NO_PLUGIN=false | |
| fi | |
| # ----------------------------------------------------------- | |
| # Step 3: Set up SessionEnd hook (for future tracking) | |
| # ----------------------------------------------------------- | |
| if [ "$NO_PLUGIN" = false ] && [ -n "$MEASURE_PY" ]; then | |
| HOOK_STATUS=$(python3 "$MEASURE_PY" check-hook 2>/dev/null && echo "installed" || echo "missing") | |
| if [ "$HOOK_STATUS" = "missing" ]; then | |
| info "Setting up session tracking hook..." | |
| python3 "$MEASURE_PY" setup-hook 2>/dev/null && success "Session tracking hook installed" || warn "Could not install hook automatically" | |
| else | |
| success "Session tracking hook already active" | |
| fi | |
| fi | |
| # ----------------------------------------------------------- | |
| # Step 4: Generate the dashboard | |
| # ----------------------------------------------------------- | |
| info "Generating token usage dashboard..." | |
| OUTPUT="$HOME/.claude/_backups/token-optimizer/token-usage.html" | |
| mkdir -p "$(dirname "$OUTPUT")" | |
| GENERATED=$(date '+%Y-%m-%d %H:%M:%S') | |
| USER_EMAIL=$(git config --global user.email 2>/dev/null || echo "unknown") | |
| if [ "$NO_PLUGIN" = false ] && [ -n "$MEASURE_PY" ]; then | |
| # Full dashboard with trends data | |
| TMPDIR_DATA=$(mktemp -d /tmp/token-usage-XXXXXXXXXX) | |
| python3 "$MEASURE_PY" trends --json --days 7 > "$TMPDIR_DATA/d7.json" 2>/dev/null || echo '{}' > "$TMPDIR_DATA/d7.json" | |
| python3 "$MEASURE_PY" trends --json --days 30 > "$TMPDIR_DATA/d30.json" 2>/dev/null || echo '{}' > "$TMPDIR_DATA/d30.json" | |
| D7_FILE="$TMPDIR_DATA/d7.json" | |
| D30_FILE="$TMPDIR_DATA/d30.json" | |
| else | |
| # Empty data — dashboard will show "no data" state | |
| TMPDIR_DATA=$(mktemp -d /tmp/token-usage-XXXXXXXXXX) | |
| echo '{"period_days":7,"session_count":0,"total_input_tokens":0,"total_output_tokens":0,"total_fresh_input":0,"total_cache_read":0,"total_cache_create":0,"total_tokens":0,"total_tokens_raw":0,"total_messages":0,"avg_duration_minutes":0,"avg_input_tokens":0,"avg_output_tokens":0,"model_mix":{},"tool_calls":{},"daily":[]}' > "$TMPDIR_DATA/d7.json" | |
| echo '{"period_days":30,"session_count":0,"total_input_tokens":0,"total_output_tokens":0,"total_fresh_input":0,"total_cache_read":0,"total_cache_create":0,"total_tokens":0,"total_tokens_raw":0,"total_messages":0,"avg_duration_minutes":0,"avg_input_tokens":0,"avg_output_tokens":0,"model_mix":{},"tool_calls":{},"daily":[]}' > "$TMPDIR_DATA/d30.json" | |
| D7_FILE="$TMPDIR_DATA/d7.json" | |
| D30_FILE="$TMPDIR_DATA/d30.json" | |
| fi | |
| python3 - "$D7_FILE" "$D30_FILE" "$OUTPUT" "$GENERATED" "$USER_EMAIL" <<'PYEOF' | |
| import sys, json | |
| with open(sys.argv[1]) as f: | |
| d7 = json.load(f) | |
| with open(sys.argv[2]) as f: | |
| d30 = json.load(f) | |
| output_path = sys.argv[3] | |
| generated = sys.argv[4] | |
| user_email = sys.argv[5] | |
| no_data = d7.get("session_count", 0) == 0 and d30.get("session_count", 0) == 0 | |
| no_data_banner = "" | |
| if no_data: | |
| no_data_banner = """ | |
| <div style="background:#2d1b00;border:1px solid #d29922;border-radius:8px;padding:16px;margin-bottom:24px;max-width:1100px;margin-left:auto;margin-right:auto;text-align:center;"> | |
| <div style="font-size:16px;font-weight:600;color:#d29922;">No session data yet</div> | |
| <div style="font-size:13px;color:#8b949e;margin-top:8px;"> | |
| Use Claude Code normally for a few sessions. Token usage data is collected automatically<br> | |
| via the SessionEnd hook. Re-run this script after a few sessions to see your metrics. | |
| </div> | |
| </div>""" | |
| html = r'''<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Claude Code — Token Usage Report</title> | |
| <style> | |
| * { margin: 0; padding: 0; box-sizing: border-box; } | |
| body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #0f1117; color: #e1e4e8; padding: 24px; min-height: 100vh; } | |
| .header { text-align: center; margin-bottom: 32px; } | |
| .header h1 { font-size: 28px; font-weight: 700; color: #fff; margin-bottom: 4px; } | |
| .header .subtitle { color: #8b949e; font-size: 14px; } | |
| .header .generated { color: #6e7681; font-size: 12px; margin-top: 8px; } | |
| .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; max-width: 1100px; margin: 0 auto; } | |
| .card { background: #161b22; border: 1px solid #30363d; border-radius: 12px; padding: 24px; } | |
| .card h2 { font-size: 18px; font-weight: 600; color: #fff; margin-bottom: 16px; display: flex; align-items: center; gap: 8px; } | |
| .badge { font-size: 11px; background: #238636; color: #fff; padding: 2px 8px; border-radius: 10px; font-weight: 500; } | |
| .badge.blue { background: #1f6feb; } | |
| table { width: 100%; border-collapse: collapse; } | |
| th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid #21262d; } | |
| th { color: #8b949e; font-size: 12px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px; } | |
| td { font-size: 14px; } | |
| td.num { text-align: right; font-variant-numeric: tabular-nums; font-family: 'SF Mono', 'Fira Code', monospace; } | |
| .highlight { color: #58a6ff; font-weight: 600; } | |
| .cost { color: #3fb950; font-weight: 600; } | |
| .full-width { grid-column: 1 / -1; } | |
| .model-bar { display: flex; height: 32px; border-radius: 6px; overflow: hidden; margin-top: 8px; margin-bottom: 12px; } | |
| .seg { display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 600; color: #fff; } | |
| .seg-opus { background: #8957e5; } | |
| .seg-sonnet { background: #1f6feb; } | |
| .seg-haiku { background: #238636; } | |
| .legend { display: flex; gap: 16px; justify-content: center; margin-top: 8px; } | |
| .legend-item { display: flex; align-items: center; gap: 6px; font-size: 12px; color: #8b949e; } | |
| .legend-dot { width: 10px; height: 10px; border-radius: 50%; } | |
| .daily-row:nth-child(even) td { background: #1c2128; } | |
| .summary-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-bottom: 16px; } | |
| .summary-stat { text-align: center; padding: 16px; background: #1c2128; border-radius: 8px; } | |
| .summary-stat .value { font-size: 24px; font-weight: 700; color: #fff; font-variant-numeric: tabular-nums; } | |
| .summary-stat .label { font-size: 11px; color: #8b949e; text-transform: uppercase; letter-spacing: 0.5px; margin-top: 4px; } | |
| .cache-bar { background: #21262d; height: 8px; border-radius: 4px; overflow: hidden; margin-top: 6px; } | |
| .cache-fill { height: 100%; background: linear-gradient(90deg, #238636, #3fb950); border-radius: 4px; } | |
| .refresh-note { text-align: center; color: #6e7681; font-size: 11px; margin-top: 24px; padding-bottom: 24px; } | |
| .refresh-note code { background: #21262d; padding: 2px 6px; border-radius: 4px; font-size: 11px; } | |
| .why-box { max-width: 1100px; margin: 0 auto 24px; background: #161b22; border: 1px solid #30363d; border-radius: 12px; padding: 20px; } | |
| .why-box h3 { color: #fff; font-size: 15px; margin-bottom: 8px; } | |
| .why-box p { color: #8b949e; font-size: 13px; line-height: 1.6; } | |
| .why-box code { background: #21262d; padding: 1px 5px; border-radius: 3px; font-size: 12px; color: #e1e4e8; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h1>Claude Code Token Usage</h1> | |
| <div class="subtitle">__USER__</div> | |
| <div class="generated">Generated: __GENTIME__</div> | |
| </div> | |
| __NODATA__ | |
| <div class="why-box"> | |
| <h3>Why this dashboard?</h3> | |
| <p> | |
| The built-in <code>/stats</code> command only shows the <strong>current session's</strong> token count — not historical totals. | |
| This dashboard tracks <strong>all sessions</strong> over 7 and 30 days, including cache efficiency, model mix, | |
| and estimated cost. Run the setup script again anytime to refresh with the latest data. | |
| </p> | |
| </div> | |
| <div class="grid" id="root"></div> | |
| <div class="refresh-note"> | |
| Refresh: <code>bash ~/.claude/token-usage-setup.sh</code> | |
| </div> | |
| <script> | |
| var D7 = __D7__; | |
| var D30 = __D30__; | |
| function fmt(n) { | |
| if (n >= 1e9) return (n/1e9).toFixed(1) + 'B'; | |
| if (n >= 1e6) return (n/1e6).toFixed(1) + 'M'; | |
| if (n >= 1e3) return (n/1e3).toFixed(1) + 'K'; | |
| return n.toLocaleString(); | |
| } | |
| function fmtFull(n) { return n.toLocaleString(); } | |
| function estCost(d) { | |
| return (d.total_fresh_input||0)*3/1e6 + (d.total_cache_read||0)*0.3/1e6 | |
| + (d.total_cache_create||0)*3.75/1e6 + (d.total_output_tokens||0)*15/1e6; | |
| } | |
| function summaryCard(d, label, badgeCls) { | |
| var cost = estCost(d); | |
| var cacheRate = d.total_input_tokens ? ((d.total_cache_read||0)/d.total_input_tokens*100) : 0; | |
| return '<div class="card">' | |
| + '<h2>' + label + ' <span class="badge ' + badgeCls + '">' + d.period_days + 'D</span></h2>' | |
| + '<div class="summary-grid">' | |
| + '<div class="summary-stat"><div class="value">' + d.session_count + '</div><div class="label">Sessions</div></div>' | |
| + '<div class="summary-stat"><div class="value">' + fmtFull(d.total_messages||0) + '</div><div class="label">Messages</div></div>' | |
| + '<div class="summary-stat"><div class="value cost">$' + cost.toFixed(2) + '</div><div class="label">Est. Cost</div></div>' | |
| + '</div>' | |
| + '<table><tr><th>Metric</th><th style="text-align:right">Value</th></tr>' | |
| + '<tr><td>Total Input (raw)</td><td class="num">' + fmt(d.total_input_tokens||0) + '</td></tr>' | |
| + '<tr><td>Fresh Input</td><td class="num">' + fmt(d.total_fresh_input||0) + '</td></tr>' | |
| + '<tr><td>Cache Read</td><td class="num">' + fmt(d.total_cache_read||0) + '</td></tr>' | |
| + '<tr><td>Cache Create</td><td class="num">' + fmt(d.total_cache_create||0) + '</td></tr>' | |
| + '<tr><td>Total Output</td><td class="num">' + fmt(d.total_output_tokens||0) + '</td></tr>' | |
| + '<tr><td>Effective (billed)</td><td class="num highlight">' + fmt(d.total_tokens||0) + '</td></tr>' | |
| + '<tr><td>Avg Duration</td><td class="num">' + Math.round(d.avg_duration_minutes||0) + ' min</td></tr>' | |
| + '<tr><td>Avg Input/Session</td><td class="num">' + fmt(d.avg_input_tokens||0) + '</td></tr>' | |
| + '</table>' | |
| + '<div style="margin-top:16px;font-size:13px;color:#8b949e;">Cache Hit Rate</div>' | |
| + '<div class="cache-bar"><div class="cache-fill" style="width:' + cacheRate + '%"></div></div>' | |
| + '<div style="font-size:12px;color:#3fb950;margin-top:4px;">' + cacheRate.toFixed(1) + '% cache hit rate</div>' | |
| + '</div>'; | |
| } | |
| function modelCard(d, label) { | |
| var mix = d.model_mix || {}; | |
| var total = Object.values(mix).reduce(function(a,b){return a+b;},0) || 1; | |
| var models = [{k:'opus',c:'seg-opus',l:'Opus'},{k:'sonnet',c:'seg-sonnet',l:'Sonnet'},{k:'haiku',c:'seg-haiku',l:'Haiku'}]; | |
| var bars = models.filter(function(m){return mix[m.k];}).map(function(m){ | |
| var p = (mix[m.k]/total)*100; | |
| return '<div class="seg ' + m.c + '" style="width:' + p + '%">' + (p>=5 ? Math.round(p)+'%' : '') + '</div>'; | |
| }).join(''); | |
| var rows = models.map(function(m){ | |
| return '<tr><td>' + m.l + '</td><td class="num">' + fmt(mix[m.k]||0) + '</td><td class="num">' + ((mix[m.k]||0)/total*100).toFixed(1) + '%</td></tr>'; | |
| }).join(''); | |
| return '<div class="card">' | |
| + '<h2>Model Mix (' + label + ')</h2>' | |
| + '<div class="model-bar">' + bars + '</div>' | |
| + '<div class="legend">' | |
| + '<div class="legend-item"><div class="legend-dot" style="background:#8957e5"></div>Opus</div>' | |
| + '<div class="legend-item"><div class="legend-dot" style="background:#1f6feb"></div>Sonnet</div>' | |
| + '<div class="legend-item"><div class="legend-dot" style="background:#238636"></div>Haiku</div>' | |
| + '</div>' | |
| + '<table style="margin-top:12px"><tr><th>Model</th><th style="text-align:right">Tokens</th><th style="text-align:right">%</th></tr>' + rows + '</table>' | |
| + '</div>'; | |
| } | |
| function dailyCard(d) { | |
| var days = (d.daily||[]).slice(0,7); | |
| if (days.length === 0) return ''; | |
| var rows = days.map(function(day){ | |
| var c = (day.total_input||0)*1.5/1e6 + (day.total_output||0)*15/1e6; | |
| return '<tr class="daily-row"><td>' + day.date + '</td><td class="num">' + day.sessions + '</td><td class="num">' + fmt(day.total_input||0) + '</td><td class="num">' + fmt(day.total_output||0) + '</td><td class="num cost">$' + c.toFixed(2) + '</td></tr>'; | |
| }).join(''); | |
| return '<div class="card full-width">' | |
| + '<h2>Daily Breakdown (Last 7 Days)</h2>' | |
| + '<table><tr><th>Date</th><th style="text-align:right">Sessions</th><th style="text-align:right">Input</th><th style="text-align:right">Output</th><th style="text-align:right">Est. Cost</th></tr>' + rows + '</table>' | |
| + '</div>'; | |
| } | |
| function toolsCard(d) { | |
| var tools = Object.entries(d.tool_calls||{}).sort(function(a,b){return b[1]-a[1];}).slice(0,10); | |
| if (tools.length === 0) return ''; | |
| var rows = tools.map(function(t){ return '<tr><td>' + t[0] + '</td><td class="num">' + t[1] + '</td></tr>'; }).join(''); | |
| return '<div class="card full-width">' | |
| + '<h2>Top Tool Usage (7 Days)</h2>' | |
| + '<table><tr><th>Tool</th><th style="text-align:right">Calls</th></tr>' + rows + '</table>' | |
| + '</div>'; | |
| } | |
| document.getElementById('root').innerHTML = | |
| summaryCard(D7, 'Last 7 Days', '') + | |
| summaryCard(D30, 'Last 30 Days', 'blue') + | |
| modelCard(D7, '7 Days') + | |
| modelCard(D30, '30 Days') + | |
| dailyCard(D7) + | |
| toolsCard(D7); | |
| </script> | |
| </body> | |
| </html>''' | |
| html = html.replace('__GENTIME__', generated) | |
| html = html.replace('__USER__', user_email) | |
| html = html.replace('__NODATA__', no_data_banner) | |
| html = html.replace('__D7__', json.dumps(d7)) | |
| html = html.replace('__D30__', json.dumps(d30)) | |
| with open(output_path, 'w') as f: | |
| f.write(html) | |
| print("Dashboard written to: " + output_path) | |
| PYEOF | |
| rm -rf "$TMPDIR_DATA" | |
| # ----------------------------------------------------------- | |
| # Step 5: Install the refresh script | |
| # ----------------------------------------------------------- | |
| REFRESH_SCRIPT="$HOME/.claude/token-usage-dashboard.sh" | |
| cat > "$REFRESH_SCRIPT" <<'REFRESH' | |
| #!/bin/bash | |
| # Quick refresh — regenerates token usage dashboard with latest data | |
| MEASURE_PY="" | |
| for f in "$HOME/.claude/skills/token-optimizer/scripts/measure.py" \ | |
| "$HOME/.claude/plugins/cache"/*/token-optimizer/*/skills/token-optimizer/scripts/measure.py; do | |
| [ -f "$f" ] && MEASURE_PY="$f" && break | |
| done | |
| [ -z "$MEASURE_PY" ] && { echo "[Error] token-optimizer not found. Run setup again."; exit 1; } | |
| TMPDIR_DATA=$(mktemp -d /tmp/token-usage-XXXXXXXXXX) | |
| python3 "$MEASURE_PY" trends --json --days 7 > "$TMPDIR_DATA/d7.json" 2>/dev/null || echo '{}' > "$TMPDIR_DATA/d7.json" | |
| python3 "$MEASURE_PY" trends --json --days 30 > "$TMPDIR_DATA/d30.json" 2>/dev/null || echo '{}' > "$TMPDIR_DATA/d30.json" | |
| # Re-run the full setup to regenerate | |
| bash "$HOME/.claude/token-usage-setup.sh" | |
| rm -rf "$TMPDIR_DATA" | |
| REFRESH | |
| chmod +x "$REFRESH_SCRIPT" 2>/dev/null || true | |
| # ----------------------------------------------------------- | |
| # Step 6: Add shell alias | |
| # ----------------------------------------------------------- | |
| SHELL_RC="$HOME/.zshrc" | |
| [ -f "$HOME/.bashrc" ] && [ ! -f "$HOME/.zshrc" ] && SHELL_RC="$HOME/.bashrc" | |
| if ! grep -q "alias tokens=" "$SHELL_RC" 2>/dev/null; then | |
| echo "" >> "$SHELL_RC" | |
| echo "# Claude Code token usage dashboard" >> "$SHELL_RC" | |
| echo "alias tokens='bash ~/.claude/token-usage-setup.sh'" >> "$SHELL_RC" | |
| success "Added 'tokens' alias to $SHELL_RC" | |
| else | |
| success "'tokens' alias already exists in $SHELL_RC" | |
| fi | |
| # ----------------------------------------------------------- | |
| # Step 7: Open the dashboard | |
| # ----------------------------------------------------------- | |
| if [ -f "$OUTPUT" ]; then | |
| if [[ "$OSTYPE" == "darwin"* ]]; then | |
| open "$OUTPUT" | |
| elif command -v xdg-open &>/dev/null; then | |
| xdg-open "$OUTPUT" | |
| fi | |
| success "Dashboard opened in browser" | |
| else | |
| fail "Dashboard generation failed" | |
| fi | |
| # ----------------------------------------------------------- | |
| # Summary | |
| # ----------------------------------------------------------- | |
| echo "" | |
| echo -e "${BOLD}╔══════════════════════════════════════════════════╗${NC}" | |
| echo -e "${BOLD}║ Setup Complete! ║${NC}" | |
| echo -e "${BOLD}╚══════════════════════════════════════════════════╝${NC}" | |
| echo "" | |
| echo -e " ${GREEN}Dashboard${NC}: $OUTPUT" | |
| echo -e " ${GREEN}Refresh${NC}: Type ${BOLD}tokens${NC} in a new terminal" | |
| echo -e " (or run: bash ~/.claude/token-usage-setup.sh)" | |
| echo "" | |
| echo -e " ${YELLOW}Note${NC}: If this is your first time, you'll see empty data." | |
| echo -e " Use Claude Code for a few sessions, then run ${BOLD}tokens${NC} again." | |
| echo "" | |
| echo -e " ${CYAN}Why not /stats?${NC}" | |
| echo -e " /stats only shows the current session's tokens." | |
| echo -e " This dashboard tracks ALL sessions over 7 and 30 days," | |
| echo -e " including cache efficiency, model mix, and estimated cost." | |
| echo "" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment