ClaudeUsage.psm1
|
# ============================================ # ClaudeUsage PowerShell Module # Query Claude Code usage programmatically # ============================================ function Get-ClaudeUsage { <# .SYNOPSIS Query Claude Code usage information .DESCRIPTION Gets information about current usage windows: - Five-hour window: resets_at, utilization - Seven-day window (if applicable) - Opus limits (if applicable) Automatically reads the token from ~/.claude/.credentials.json .PARAMETER Raw Returns the raw JSON response without formatting .PARAMETER Token OAuth authentication token (optional, read automatically if not provided) .PARAMETER ShowAll Show all available limit windows (5-hour, 7-day, Opus, etc.) .PARAMETER Brief Show minimal one-line output: usage percentage and time remaining .EXAMPLE Get-ClaudeUsage Shows current usage formatted .EXAMPLE Get-ClaudeUsage -ShowAll Shows all available usage limits .EXAMPLE Get-ClaudeUsage -Brief 54% | 3h 16m remaining .EXAMPLE Get-ClaudeUsage -Raw Returns the complete JSON object .EXAMPLE clau Short alias for Get-ClaudeUsage .LINK https://github.com/backmind/ClaudeUsage .NOTES Version: 1.1.0 Author: Yass Fuentes Note: seven_day, seven_day_oauth_apps, and seven_day_opus limits are only available for Claude Max subscribers or enterprise accounts. #> [CmdletBinding(DefaultParameterSetName='Default')] param( [Parameter(ParameterSetName='Raw')] [switch]$Raw, [Parameter(ParameterSetName='Default')] [switch]$ShowAll, [Parameter(ParameterSetName='Brief')] [switch]$Brief, [Parameter()] [string]$Token = $null ) # If no token provided, try to read from config files if (-not $Token) { # Read token from Claude credentials file $credentialsPath = "$env:USERPROFILE\.claude\.credentials.json" if (Test-Path $credentialsPath) { try { $credentials = Get-Content $credentialsPath | ConvertFrom-Json if ($credentials.claudeAiOauth.accessToken) { $Token = $credentials.claudeAiOauth.accessToken # Check if token has expired $expiresAt = $credentials.claudeAiOauth.expiresAt if ($expiresAt) { $expiryDate = [DateTimeOffset]::FromUnixTimeMilliseconds($expiresAt).LocalDateTime if ((Get-Date) -gt $expiryDate) { Write-Host "Warning: Token has expired. Please run:" -ForegroundColor Yellow Write-Host " claude setup-token" -ForegroundColor Cyan Write-Host " to renew your authentication." -ForegroundColor Yellow return } } } } catch { Write-Host "Error reading credentials file:" -ForegroundColor Red Write-Host $_.Exception.Message -ForegroundColor Red } } # If token not found if (-not $Token) { Write-Host "Credentials file not found." -ForegroundColor Yellow Write-Host "Please run:" -ForegroundColor Yellow Write-Host " claude setup-token" -ForegroundColor Cyan Write-Host " to configure your authentication." -ForegroundColor Yellow return } } # API endpoint and headers $uri = "https://api.anthropic.com/api/oauth/usage" $headers = @{ "Accept" = "application/json, text/plain, */*" "Content-Type" = "application/json" "User-Agent" = "claude-code/2.0.15" "Authorization" = "Bearer $Token" "anthropic-beta" = "oauth-2025-04-20" } try { # Make API request $response = Invoke-RestMethod -Uri $uri -Headers $headers -Method Get if ($Raw) { return $response } # Brief mode: one-liner output if ($Brief) { if ($response.five_hour) { $utilization = $response.five_hour.utilization # Handle both string and DateTime objects if ($response.five_hour.resets_at -is [DateTime]) { $resetsAt = $response.five_hour.resets_at.ToLocalTime() } else { try { $resetsAt = [DateTime]::ParseExact($response.five_hour.resets_at, "yyyy-MM-ddTHH:mm:ss.ffffffK", [System.Globalization.CultureInfo]::InvariantCulture).ToLocalTime() } catch { # Fallback to generic parse if format doesn't match $resetsAt = ([DateTime]$response.five_hour.resets_at).ToLocalTime() } } $timeRemaining = $resetsAt - (Get-Date) $color = if ($utilization -lt 50) { "Green" } elseif ($utilization -lt 80) { "Yellow" } else { "Red" } Write-Host "$utilization% " -NoNewline -ForegroundColor $color Write-Host "| " -NoNewline -ForegroundColor Gray Write-Host "$([Math]::Floor($timeRemaining.TotalHours))h $($timeRemaining.Minutes)m remaining" -ForegroundColor Cyan return } else { Write-Host "No usage data available" -ForegroundColor Yellow return } } # Helper function to display a usage window function Show-UsageWindow { param($WindowData, $WindowName) if (-not $WindowData) { return $null } # Handle both string and DateTime objects if ($WindowData.resets_at -is [DateTime]) { $resetsAt = $WindowData.resets_at.ToLocalTime() } else { try { $resetsAt = [DateTime]::ParseExact($WindowData.resets_at, "yyyy-MM-ddTHH:mm:ss.ffffffK", [System.Globalization.CultureInfo]::InvariantCulture).ToLocalTime() } catch { # Fallback to generic parse if format doesn't match $resetsAt = ([DateTime]$WindowData.resets_at).ToLocalTime() } } $utilization = $WindowData.utilization $timeRemaining = $resetsAt - (Get-Date) Write-Host " $WindowName Window:" -ForegroundColor White Write-Host " Utilization: " -NoNewline -ForegroundColor Gray if ($utilization -lt 50) { Write-Host "$utilization%" -ForegroundColor Green } elseif ($utilization -lt 80) { Write-Host "$utilization%" -ForegroundColor Yellow } else { Write-Host "$utilization%" -ForegroundColor Red } Write-Host " Next reset: " -NoNewline -ForegroundColor Gray Write-Host $resetsAt.ToString("yyyy-MM-dd HH:mm:ss") -ForegroundColor Cyan Write-Host " Time remaining: " -NoNewline -ForegroundColor Gray Write-Host "$([Math]::Floor($timeRemaining.TotalHours))h $($timeRemaining.Minutes)m" -ForegroundColor Magenta Write-Host "" } # Display header Write-Host "`n============================================" -ForegroundColor Cyan Write-Host " Claude Code - Usage Status" -ForegroundColor Cyan Write-Host "============================================`n" -ForegroundColor Cyan $results = @() # Always show 5-hour window (primary limit) if ($response.five_hour) { Show-UsageWindow -WindowData $response.five_hour -WindowName "5-Hour" | Out-Null } else { Write-Host " No 5-hour window information available" -ForegroundColor Yellow } # Show additional windows if -ShowAll or if they have data if ($ShowAll -or $response.seven_day) { if ($response.seven_day) { Show-UsageWindow -WindowData $response.seven_day -WindowName "7-Day" | Out-Null } elseif ($ShowAll) { Write-Host " 7-Day Window: Not available (requires Claude Max)" -ForegroundColor DarkGray Write-Host "" } } if ($ShowAll -or $response.seven_day_oauth_apps) { if ($response.seven_day_oauth_apps) { Show-UsageWindow -WindowData $response.seven_day_oauth_apps -WindowName "7-Day OAuth Apps" | Out-Null } elseif ($ShowAll) { Write-Host " 7-Day OAuth Apps: Not available" -ForegroundColor DarkGray Write-Host "" } } if ($ShowAll -or $response.seven_day_opus) { if ($response.seven_day_opus) { Show-UsageWindow -WindowData $response.seven_day_opus -WindowName "7-Day Opus" | Out-Null } elseif ($ShowAll) { Write-Host " 7-Day Opus: Not available (requires Claude Max)" -ForegroundColor DarkGray Write-Host "" } } } catch { Write-Host "Error querying Claude usage:" -ForegroundColor Red Write-Host $_.Exception.Message -ForegroundColor Red if ($_.Exception.Response.StatusCode -eq 401) { Write-Host "`nToken appears to be invalid. Please verify it's correct." -ForegroundColor Yellow } } } # Export function Export-ModuleMember -Function Get-ClaudeUsage |