Skip to content

Instantly share code, notes, and snippets.

@withakay
Last active March 13, 2026 09:10
Show Gist options
  • Select an option

  • Save withakay/cd0a5972657fbb234f9cf04a1c1b8a29 to your computer and use it in GitHub Desktop.

Select an option

Save withakay/cd0a5972657fbb234f9cf04a1c1b8a29 to your computer and use it in GitHub Desktop.
Github Copilot Usage CLI
#!/usr/bin/env python3
"""Show Copilot premium interaction quota usage."""
import argparse
import json
import os
import shutil
import subprocess
import sys
import time
import uuid
from datetime import datetime, timezone
from typing import Any, Optional
API_PATH = "/copilot_internal/user"
# ── Helpers ──
def gh_api_json(hostname: Optional[str], timeout: int) -> dict:
cmd = ["gh", "api", API_PATH, "-H", "Accept: application/json"]
if hostname:
cmd += ["--hostname", hostname]
try:
p = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout,
)
except FileNotFoundError as e:
raise RuntimeError("gh is not installed (or not on PATH).") from e
except subprocess.TimeoutExpired as e:
raise RuntimeError(f"Timed out after {timeout}s.") from e
if p.returncode != 0:
msg = (p.stderr or p.stdout or "").strip()
raise RuntimeError(msg or f"`gh api` failed (exit {p.returncode}).")
try:
return json.loads(p.stdout)
except json.JSONDecodeError as e:
raise RuntimeError("Failed to parse JSON returned by `gh api`.") from e
def _as_int_if_close(v: float):
if abs(v - round(v)) < 1e-9:
return int(round(v))
return v
def parse_snapshot(snapshot: Any):
"""Returns {used, total, remaining}, 'unlimited', or None."""
if not isinstance(snapshot, dict) or not snapshot:
return None
if snapshot.get("unlimited"):
return "unlimited"
total = snapshot.get("entitlement")
remaining = snapshot.get("remaining")
if remaining is None:
remaining = snapshot.get("quota_remaining")
if total is None or remaining is None:
return None
try:
total_f = float(total)
remaining_f = float(remaining)
except (TypeError, ValueError):
return None
used_f = max(total_f - remaining_f, 0.0)
return {
"used": _as_int_if_close(used_f),
"total": _as_int_if_close(total_f),
"remaining": _as_int_if_close(remaining_f),
}
def snapshot_metrics(parsed) -> dict:
if parsed == "unlimited":
return {"status": "unlimited"}
if not parsed:
return {"status": "unknown"}
used, total, remaining = parsed["used"], parsed["total"], parsed["remaining"]
try:
pct = int(100 * float(used) / float(total)) if float(total) else 0
except (TypeError, ValueError, ZeroDivisionError):
pct = 0
return {"used": used, "total": total, "remaining": remaining, "pct": pct}
def format_metrics(metrics: dict) -> str:
status = metrics.get("status")
if status == "unlimited":
return "unlimited"
if status == "unknown":
return "unknown"
return f"{metrics['used']}/{metrics['total']} - {metrics['pct']}%"
def format_reset_date(data: dict) -> Optional[str]:
s = data.get("quota_reset_date")
if isinstance(s, str) and s:
try:
return datetime.strptime(s, "%Y-%m-%d").strftime("%d/%m/%y")
except ValueError:
pass
s = data.get("quota_reset_date_utc")
if isinstance(s, str) and s:
try:
return datetime.fromisoformat(s.replace("Z", "+00:00")).strftime("%d/%m/%y")
except ValueError:
pass
return None
def collect_snapshots(data: dict) -> dict:
raw = data.get("quota_snapshots")
if not isinstance(raw, dict):
return {}
return {k: snapshot_metrics(parse_snapshot(v)) for k, v in raw.items()}
def snap(snapshots: dict, key: str) -> dict:
return snapshots.get(key) or {"status": "unknown"}
def get_premium_used(snapshots: dict) -> Optional[float]:
s = snap(snapshots, "premium_interactions")
used = s.get("used")
return float(used) if used is not None else None
def build_watch_record(
snapshots: dict,
reset: Optional[str],
*,
detailed: bool,
all_: bool,
) -> dict:
record: dict = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"reset_date": reset,
}
if all_:
record["snapshots"] = dict(sorted(snapshots.items()))
elif detailed:
record["premium"] = snap(snapshots, "premium_interactions")
record["chat"] = snap(snapshots, "chat")
record["completions"] = snap(snapshots, "completions")
else:
record["premium"] = snap(snapshots, "premium_interactions")
return record
# ── Keyboard input (cross-platform) ──
def _can_read_keys() -> bool:
"""Return True if we can do non-blocking single-key reads from stdin."""
if not sys.stdin.isatty():
return False
if sys.platform == "win32":
try:
import msvcrt # noqa: F401
return True
except ImportError:
return False
else:
try:
import select # noqa: F401
import termios # noqa: F401
import tty # noqa: F401
return True
except ImportError:
return False
def _check_for_quit() -> bool:
"""Non-blocking check: return True if 'q' was pressed."""
if sys.platform == "win32":
import msvcrt
if msvcrt.kbhit():
ch = msvcrt.getwch()
if ch.lower() == "q":
return True
else:
import select
import termios
import tty
old = termios.tcgetattr(sys.stdin)
try:
tty.setcbreak(sys.stdin.fileno())
rlist, _, _ = select.select([sys.stdin], [], [], 0)
if rlist:
ch = sys.stdin.read(1)
if ch.lower() == "q":
return True
finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old)
return False
def _terminal_width() -> int:
return shutil.get_terminal_size((80, 24)).columns
# ── Watch mode ──
def watch_loop(args) -> int:
log_file = args.log_file
if not log_file:
sid = uuid.uuid4().hex[-5:]
log_file = f"ghcp-usage-{sid}.jsonl"
log_path = os.path.abspath(log_file)
can_keys = _can_read_keys()
quit_hint = " Press 'q' to stop." if can_keys else " Send SIGINT to stop."
print(
f"Monitoring Copilot usage every {args.interval} seconds.{quit_hint}",
file=sys.stderr,
)
print(f"Logging JSONL to: {log_path}", file=sys.stderr)
print("", file=sys.stderr)
session_start = datetime.now()
start_used: Optional[float] = None
latest_used: Optional[float] = None
poll_count = 0
quit_requested = False
width = _terminal_width()
try:
while not quit_requested:
poll_count += 1
# ── Poll ──
data = None
try:
data = gh_api_json(args.hostname, args.timeout)
except Exception as exc:
err_record = {
"timestamp": datetime.now(timezone.utc).isoformat(),
"error": str(exc),
}
with open(log_path, "a", encoding="utf-8") as f:
f.write(json.dumps(err_record, sort_keys=True) + "\n")
line = f"[{datetime.now():%H:%M:%S}] Error: {exc}"
sys.stderr.write(f"\r{line:<{width - 1}}")
sys.stderr.flush()
if data is not None:
reset = format_reset_date(data)
snapshots = collect_snapshots(data)
record = build_watch_record(
snapshots, reset, detailed=args.detailed, all_=args.all
)
with open(log_path, "a", encoding="utf-8") as f:
f.write(json.dumps(record, sort_keys=True) + "\n")
current_used = get_premium_used(snapshots)
if current_used is not None:
if start_used is None:
start_used = current_used
latest_used = current_used
premium_display = format_metrics(
snap(snapshots, "premium_interactions")
)
delta = ""
if start_used is not None and latest_used is not None:
d = max(latest_used - start_used, 0)
d = _as_int_if_close(d)
delta = f" | session: +{d}"
line = f"[{datetime.now():%H:%M:%S}] {premium_display}{delta}"
sys.stderr.write(f"\r{line:<{width - 1}}")
sys.stderr.flush()
# ── Interruptible sleep ──
deadline = time.monotonic() + args.interval
while time.monotonic() < deadline:
if can_keys:
try:
if _check_for_quit():
quit_requested = True
break
except Exception:
pass
remaining = deadline - time.monotonic()
time.sleep(min(0.25, max(0.001, remaining)))
except KeyboardInterrupt:
pass
# ── Session summary ──
session_end = datetime.now()
duration = session_end - session_start
total_secs = int(duration.total_seconds())
hours, rem = divmod(total_secs, 3600)
mins, secs = divmod(rem, 60)
print("", file=sys.stderr)
print("", file=sys.stderr)
print("\033[36m── Session Summary ──\033[0m", file=sys.stderr)
print(f" Start: {session_start:%Y-%m-%d %H:%M:%S}", file=sys.stderr)
print(f" End: {session_end:%Y-%m-%d %H:%M:%S}", file=sys.stderr)
print(f" Duration: {hours}h {mins}m {secs}s", file=sys.stderr)
print(f" Polls: {poll_count}", file=sys.stderr)
if start_used is not None and latest_used is not None:
session_delta = _as_int_if_close(max(latest_used - start_used, 0))
print(
f" Premium requests used this session: {session_delta} ({_as_int_if_close(start_used)} -> {_as_int_if_close(latest_used)})",
file=sys.stderr,
)
else:
print(
" Premium requests used this session: unknown (could not read usage)",
file=sys.stderr,
)
print(f" Log file: {log_path}", file=sys.stderr)
return 0
# ── One-shot mode ──
def one_shot(args) -> int:
try:
data = gh_api_json(args.hostname, args.timeout)
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
return 1
reset = format_reset_date(data)
reset_suffix = f" - {reset}" if reset else ""
snapshots = collect_snapshots(data)
selected_mode = "default"
if args.all:
selected_mode = "all"
elif args.detailed:
selected_mode = "detailed"
if args.json:
if selected_mode == "default":
payload = {
"mode": "default",
"reset_date": reset,
"premium": snap(snapshots, "premium_interactions"),
}
elif selected_mode == "detailed":
payload = {
"mode": "detailed",
"reset_date": reset,
"premium": snap(snapshots, "premium_interactions"),
"chat": snap(snapshots, "chat"),
"completions": snap(snapshots, "completions"),
}
else:
payload = {
"mode": "all",
"reset_date": reset,
"snapshots": dict(sorted(snapshots.items())),
}
print(json.dumps(payload, indent=2, sort_keys=True))
return 0
if args.detailed:
print(f"premium: {format_metrics(snap(snapshots, 'premium_interactions'))}")
print(f"chat: {format_metrics(snap(snapshots, 'chat'))}")
print(f"completions: {format_metrics(snap(snapshots, 'completions'))}")
print(f"reset date: {reset or 'unknown'}")
return 0
if args.all:
for k in sorted(snapshots.keys()):
print(f"{k}: {format_metrics(snapshots[k])}")
print(f"reset date: {reset or 'unknown'}")
return 0
premium_value = format_metrics(snap(snapshots, "premium_interactions"))
print(f"{premium_value}{reset_suffix}")
return 0
# ── CLI ──
def main() -> int:
ap = argparse.ArgumentParser(
prog="ghcp-usage",
description="Show Copilot premium interaction quota usage.",
)
ap.add_argument(
"--json",
action="store_true",
help="Print JSON for the selected output mode.",
)
mode = ap.add_mutually_exclusive_group()
mode.add_argument(
"--detailed",
action="store_true",
help="Show premium/chat/completions plus reset date.",
)
mode.add_argument(
"--all",
action="store_true",
help="Show all quota snapshot values plus reset date.",
)
ap.add_argument(
"--watch",
action="store_true",
help="Continuously poll and log usage as JSONL. Press 'q' to stop.",
)
ap.add_argument(
"--interval",
type=int,
default=300,
help="Polling interval in seconds for --watch mode (default: 300).",
)
ap.add_argument(
"--log-file",
help="Path to the JSONL log file for --watch mode (default: ghcp-usage-<id>.jsonl).",
)
ap.add_argument(
"--hostname",
help="GitHub hostname (for GHES); defaults to github.com via gh config.",
)
ap.add_argument(
"--timeout",
type=int,
default=15,
help="Timeout seconds per API call (default: 15).",
)
args = ap.parse_args()
if args.interval < 1:
ap.error("--interval must be at least 1 second.")
if args.timeout < 1:
ap.error("--timeout must be at least 1 second.")
if args.watch:
return watch_loop(args)
return one_shot(args)
if __name__ == "__main__":
raise SystemExit(main())
<#
.SYNOPSIS
Show Copilot premium interaction quota usage.
.DESCRIPTION
Queries the GitHub Copilot API via `gh` and displays quota usage information.
With -Watch, polls at an interval and logs JSONL to a file. Press 'q' to stop
and print a session summary showing requests used during the monitoring period.
.PARAMETER Json
Print JSON for the selected output mode.
.PARAMETER Detailed
Show premium/chat/completions plus reset date.
.PARAMETER All
Show all quota snapshot values plus reset date.
.PARAMETER Watch
Continuously poll and log usage as JSONL. Press 'q' to stop gracefully.
.PARAMETER Interval
Polling interval in seconds for -Watch mode (default: 300 = 5 minutes).
.PARAMETER LogFile
Path to the JSONL log file for -Watch mode (default: ghcp-usage-<id>.jsonl).
.PARAMETER Hostname
GitHub hostname (for GHES); defaults to github.com via gh config.
.PARAMETER Timeout
Timeout seconds per API call (default: 15).
#>
[CmdletBinding()]
param(
[switch]$Json,
[switch]$Detailed,
[switch]$All,
[switch]$Watch,
[ValidateRange(1, [int]::MaxValue)]
[int]$Interval = 300,
[string]$LogFile,
[string]$Hostname,
[ValidateRange(1, [int]::MaxValue)]
[int]$Timeout = 15,
[Alias('help')]
[switch]$H
)
$ErrorActionPreference = 'Stop'
if ($H) {
Get-Help $PSCommandPath -Detailed
exit 0
}
if ($Detailed -and $All) {
[Console]::Error.WriteLine('-Detailed and -All cannot be used together.')
exit 1
}
$ApiPath = '/copilot_internal/user'
# ── Helpers ──
function Invoke-GhApiJson {
param(
[string]$ApiPath,
[string]$Hostname,
[int]$Timeout
)
$ghExe = Get-Command 'gh' -CommandType Application -ErrorAction SilentlyContinue
if (-not $ghExe) {
throw 'gh is not installed (or not on PATH).'
}
$args_ = @('api', $ApiPath, '-H', 'Accept: application/json')
if ($Hostname) {
$args_ += '--hostname'
$args_ += $Hostname
}
$pinfo = [System.Diagnostics.ProcessStartInfo]::new()
$pinfo.FileName = $ghExe.Source
$pinfo.Arguments = ($args_ | ForEach-Object {
if ($_ -match '\s') { "`"$_`"" } else { $_ }
}) -join ' '
$pinfo.RedirectStandardOutput = $true
$pinfo.RedirectStandardError = $true
$pinfo.UseShellExecute = $false
$pinfo.CreateNoWindow = $true
$proc = [System.Diagnostics.Process]::Start($pinfo)
$stdoutTask = $proc.StandardOutput.ReadToEndAsync()
$stderrTask = $proc.StandardError.ReadToEndAsync()
if (-not $proc.WaitForExit($Timeout * 1000)) {
try { $proc.Kill() } catch {}
throw "Timed out after ${Timeout}s."
}
$proc.WaitForExit()
$stdout = $stdoutTask.GetAwaiter().GetResult()
$stderr = $stderrTask.GetAwaiter().GetResult()
if ($proc.ExitCode -ne 0) {
$msg = ($stderr, $stdout | Where-Object { $_ }) | Select-Object -First 1
$msg = if ($msg) { $msg.Trim() } else { "``gh api`` failed (exit $($proc.ExitCode))." }
throw $msg
}
try {
return $stdout | ConvertFrom-Json
}
catch {
throw 'Failed to parse JSON returned by `gh api`.'
}
}
function ConvertTo-IntIfClose {
param([double]$Value)
if ([Math]::Abs($Value - [Math]::Round($Value)) -lt 1e-9) {
return [int][Math]::Round($Value)
}
return $Value
}
function Get-ParsedSnapshot {
param($Snapshot)
if ($null -eq $Snapshot) { return $null }
$props = $Snapshot.PSObject.Properties
if ($props['unlimited'] -and $Snapshot.unlimited) {
return 'unlimited'
}
$total = if ($props['entitlement']) { $props['entitlement'].Value } else { $null }
$remaining = if ($props['remaining']) { $props['remaining'].Value }
elseif ($props['quota_remaining']) { $props['quota_remaining'].Value }
else { $null }
if ($null -eq $total -or $null -eq $remaining) { return $null }
try {
$totalF = [double]$total
$remainingF = [double]$remaining
}
catch { return $null }
return @{
Used = ConvertTo-IntIfClose ([Math]::Max($totalF - $remainingF, 0.0))
Total = ConvertTo-IntIfClose $totalF
Remaining = ConvertTo-IntIfClose $remainingF
}
}
function Get-SnapshotMetrics {
param($Parsed)
if ($Parsed -eq 'unlimited') { return @{ status = 'unlimited' } }
if ($null -eq $Parsed) { return @{ status = 'unknown' } }
$used = $Parsed.Used
$total = $Parsed.Total
$pct = if ([double]$total -ne 0) { [int](100 * [double]$used / [double]$total) } else { 0 }
return @{
used = $used
total = $total
remaining = $Parsed.Remaining
pct = $pct
}
}
function Format-MetricsValue {
param([hashtable]$Metrics)
if ($Metrics.status -eq 'unlimited') { return 'unlimited' }
if ($Metrics.status -eq 'unknown') { return 'unknown' }
return "$($Metrics.used)/$($Metrics.total) - $($Metrics.pct)%"
}
function Format-ResetDateDdMmYy {
param($Data)
$props = $Data.PSObject.Properties
$s = if ($props['quota_reset_date']) { $props['quota_reset_date'].Value } else { $null }
if ($s -is [string] -and $s) {
try {
return ([datetime]::ParseExact($s, 'yyyy-MM-dd', [System.Globalization.CultureInfo]::InvariantCulture)).ToString('dd/MM/yy')
}
catch {}
}
$s = if ($props['quota_reset_date_utc']) { $props['quota_reset_date_utc'].Value } else { $null }
if ($s -is [string] -and $s) {
try {
return ([datetimeoffset]::Parse($s.Replace('Z', '+00:00'))).ToString('dd/MM/yy')
}
catch {}
}
return $null
}
function Get-AllSnapshotMetrics {
param($Data)
$prop = $Data.PSObject.Properties['quota_snapshots']
if (-not $prop) { return @{} }
$snapshots = $prop.Value
if ($null -eq $snapshots) { return @{} }
$out = @{}
foreach ($p in $snapshots.PSObject.Properties) {
$out[$p.Name] = Get-SnapshotMetrics (Get-ParsedSnapshot $p.Value)
}
return $out
}
function Get-Snap {
param([hashtable]$Snapshots, [string]$Key)
if ($Snapshots.ContainsKey($Key)) { return $Snapshots[$Key] }
return @{ status = 'unknown' }
}
function Build-WatchRecord {
param(
[hashtable]$Snapshots,
[string]$Reset,
[switch]$Detailed,
[switch]$All
)
$record = [ordered]@{
timestamp = (Get-Date).ToUniversalTime().ToString('o')
reset_date = $Reset
}
if ($All) {
$record.snapshots = [ordered]@{}
foreach ($k in ($Snapshots.Keys | Sort-Object)) {
$record.snapshots[$k] = $Snapshots[$k]
}
}
elseif ($Detailed) {
$record.premium = Get-Snap $Snapshots 'premium_interactions'
$record.chat = Get-Snap $Snapshots 'chat'
$record.completions = Get-Snap $Snapshots 'completions'
}
else {
$record.premium = Get-Snap $Snapshots 'premium_interactions'
}
return $record
}
function Get-PremiumUsed {
param([hashtable]$Snapshots)
$s = Get-Snap $Snapshots 'premium_interactions'
if ($null -ne $s.used) { return [double]$s.used }
return $null
}
# ── Main ──
# ── Watch mode ──
if ($Watch) {
if (-not $LogFile) {
$sid = [guid]::NewGuid().ToString('N').Substring(27)
$LogFile = "ghcp-usage-$sid.jsonl"
}
$logPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($LogFile)
$sessionStart = Get-Date
$startUsed = $null
$latestUsed = $null
$pollCount = 0
# detect whether we can read keystrokes (false when stdin is redirected / no console)
$canReadKeys = $false
try { $canReadKeys = -not [Console]::IsInputRedirected } catch {}
$quitHint = if ($canReadKeys) { " Press 'q' to stop." } else { ' Send SIGINT to stop.' }
Write-Host "Monitoring Copilot usage every $Interval seconds.$quitHint"
Write-Host "Logging JSONL to: $logPath"
Write-Host ''
try {
while ($true) {
$pollCount++
# ── Poll ──
try {
$data = Invoke-GhApiJson -ApiPath $ApiPath -Hostname $Hostname -Timeout $Timeout
}
catch {
$errLine = [ordered]@{
timestamp = (Get-Date).ToUniversalTime().ToString('o')
error = "$_"
}
$errLine | ConvertTo-Json -Depth 10 -Compress | Out-File -Append -Encoding utf8 -FilePath $logPath
$line = "[$(Get-Date -Format 'HH:mm:ss')] Error: $_"
Write-Host "`r$($line.PadRight([Console]::WindowWidth - 1))" -ForegroundColor Red -NoNewline
$data = $null
}
if ($null -ne $data) {
$reset = Format-ResetDateDdMmYy $data
$snapshots = Get-AllSnapshotMetrics $data
$record = Build-WatchRecord -Snapshots $snapshots -Reset $reset -Detailed:$Detailed -All:$All
# Append JSONL
$record | ConvertTo-Json -Depth 10 -Compress | Out-File -Append -Encoding utf8 -FilePath $logPath
# Track session usage
$currentUsed = Get-PremiumUsed $snapshots
if ($null -ne $currentUsed) {
if ($null -eq $startUsed) { $startUsed = $currentUsed }
$latestUsed = $currentUsed
}
$premiumDisplay = Format-MetricsValue (Get-Snap $snapshots 'premium_interactions')
$delta = if ($null -ne $startUsed -and $null -ne $latestUsed) {
$d = [Math]::Max($latestUsed - $startUsed, 0)
" | session: +$d"
} else { '' }
$line = "[$(Get-Date -Format 'HH:mm:ss')] $premiumDisplay$delta"
Write-Host "`r$($line.PadRight([Console]::WindowWidth - 1))" -NoNewline
}
# ── Interruptible sleep: check for 'q' every 250ms ──
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
while ($elapsed.Elapsed.TotalSeconds -lt $Interval) {
if ($canReadKeys -and [Console]::KeyAvailable) {
$key = [Console]::ReadKey($true)
if ($key.KeyChar -in 'q', 'Q') {
throw '__quit__'
}
}
$remainingMs = [Math]::Max(1, [int](($Interval - $elapsed.Elapsed.TotalSeconds) * 1000))
Start-Sleep -Milliseconds ([Math]::Min(250, $remainingMs))
}
}
}
catch {
if ($_.Exception.Message -ne '__quit__') {
throw
}
}
# ── Session summary ──
$sessionEnd = Get-Date
$duration = $sessionEnd - $sessionStart
Write-Host ''
Write-Host ''
Write-Host '── Session Summary ──' -ForegroundColor Cyan
Write-Host " Start: $($sessionStart.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Host " End: $($sessionEnd.ToString('yyyy-MM-dd HH:mm:ss'))"
Write-Host " Duration: $([math]::Floor($duration.TotalHours))h $($duration.Minutes)m $($duration.Seconds)s"
Write-Host " Polls: $pollCount"
if ($null -ne $startUsed -and $null -ne $latestUsed) {
$sessionDelta = [Math]::Max($latestUsed - $startUsed, 0)
Write-Host " Premium requests used this session: $sessionDelta ($startUsed -> $latestUsed)"
}
else {
Write-Host ' Premium requests used this session: unknown (could not read usage)'
}
Write-Host " Log file: $logPath"
exit 0
}
# ── One-shot mode ──
try {
$data = Invoke-GhApiJson -ApiPath $ApiPath -Hostname $Hostname -Timeout $Timeout
}
catch {
[Console]::Error.WriteLine("Error: $($_.Exception.Message)")
exit 1
}
$reset = Format-ResetDateDdMmYy $data
$resetSuffix = if ($reset) { " - $reset" } else { '' }
$snapshots = Get-AllSnapshotMetrics $data
if ($Json) {
if ($All) {
$payload = [ordered]@{
mode = 'all'
reset_date = $reset
snapshots = [ordered]@{}
}
foreach ($k in ($snapshots.Keys | Sort-Object)) {
$payload.snapshots[$k] = $snapshots[$k]
}
}
elseif ($Detailed) {
$payload = [ordered]@{
mode = 'detailed'
reset_date = $reset
premium = Get-Snap $snapshots 'premium_interactions'
chat = Get-Snap $snapshots 'chat'
completions = Get-Snap $snapshots 'completions'
}
}
else {
$payload = [ordered]@{
mode = 'default'
reset_date = $reset
premium = Get-Snap $snapshots 'premium_interactions'
}
}
$payload | ConvertTo-Json -Depth 10
exit 0
}
if ($Detailed) {
Write-Output "premium: $(Format-MetricsValue (Get-Snap $snapshots 'premium_interactions'))"
Write-Output "chat: $(Format-MetricsValue (Get-Snap $snapshots 'chat'))"
Write-Output "completions: $(Format-MetricsValue (Get-Snap $snapshots 'completions'))"
Write-Output "reset date: $(if ($reset) { $reset } else { 'unknown' })"
exit 0
}
if ($All) {
foreach ($k in ($snapshots.Keys | Sort-Object)) {
Write-Output "${k}: $(Format-MetricsValue $snapshots[$k])"
}
Write-Output "reset date: $(if ($reset) { $reset } else { 'unknown' })"
exit 0
}
$premiumValue = Format-MetricsValue (Get-Snap $snapshots 'premium_interactions')
Write-Output "${premiumValue}${resetSuffix}"
exit 0

ghcp-usage

View your Github Copilot usage from the CLI

Requirements

  • Python3 - should work with just about any Python sunce 3.6
  • gh cli installed and authed - we use the gh cli auth token to fetch the usage data

Install

copy to somewhere in your $PATH and make it executable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment