agy-cli-usage
v0.4.5
Published
Headless usage/quota monitor for the Antigravity CLI (agy) — reads Cloud Code quota directly, with a PTY fallback. No IDE required.
Downloads
1,759
Maintainers
Readme
agy-cli-usage
Headless usage & quota monitor for the Antigravity CLI (agy).
Reads agy's /usage panel — per–model-group weekly & 5-hour limits, remaining percentage, and refresh times — headlessly. No IDE required; works on macOS · Linux · Windows · headless servers.
English · 한국어
Inspired by skainguyen1412/antigravity-usage — which targets the Antigravity IDE; this targets the CLI (agy).
Models & Quota
Account: [email protected]
GEMINI MODELS
Weekly Limit
[██████████████████████████████████████████████░░░░] 91.72%
92% remaining · Refreshes in 73h 23m
Five Hour Limit
[███████████████████████████████████████████████░░░] 94.63%
95% remaining · Refreshes in 2h 2m
CLAUDE AND GPT MODELS
Weekly Limit
[█████████████████████████████████████████████████░] 97.78%
98% remaining · Refreshes in 26h 17m
Five Hour Limit
[██████████████████████████████████████████████████] Quota availableFor Human
What it is
agy-cli-usage shows the same usage/quota information as agy's interactive /usage slash command, but from a plain shell — one-shot, watch mode, or machine-readable JSON. Use it to keep an eye on your remaining quota, drive a status bar, or feed a dashboard.
Why
agy -p "<prompt>" (headless mode) is a prompt-only path: it does not render TUI slash commands like /usage, so usage can't be polled or automated. This tool fills that gap by reading the quota directly (and falling back to driving agy in a pseudo-terminal when needed).
Quick start
# Run once, no install
npx agy-cli-usage
# Install globally → `agy-cli-usage` (alias `agy-usage`) anywhere
npm install -g agy-cli-usage
agy-cli-usagePrerequisites:
agyis logged in on the same machine, and Node.js >= 18.
Usage
agy-cli-usage # the /usage panel (one-shot)
agy-cli-usage --json # machine-readable JSON
agy-cli-usage --watch 60 # auto-refresh every 60s (via the 5-min cache)
agy-cli-usage update [--check] # self-update (--check: report only)
agy-cli-usage --version # print version| Flag | Description |
|------|-------------|
| --json | Normalized JSON output (for scripts/dashboards) |
| --watch [secs] | Refresh every N seconds (default 60) |
| --source <auto\|api\|pty> | Data source (default auto: API → PTY on failure) |
| --channel <auto\|daily\|prod> | Cloud Code host |
| --no-cache / --refresh | Bypass the 5-minute cache |
| -h, --help | Show help |
| -v, --version | Show version |
How it works
- Direct API (default · fast). Reads
agy's OAuth token from the OS and calls the same internal Cloud Code API thatagycalls on startup:POST /v1internal:loadCodeAssist→ obtainscloudaicompanionProjectPOST /v1internal:retrieveUserQuotaSummary {project}→ the quota- Refreshes the OAuth token automatically when expired.
- PTY fallback (safety net). If the token can't be read or the internal API changes, it launches
agyin a pseudo-terminal, sends/usage, reconstructs the screen with@xterm/headless, and parses it.
Cross-platform credentials
The token is read only from wherever agy stored it. Handled per platform automatically:
| OS / environment | Storage | How it's read |
|------------------|---------|---------------|
| macOS | Keychain | @napi-rs/keyring (fallback security) |
| Linux desktop | Secret Service | @napi-rs/keyring (fallback secret-tool) |
| Windows | Credential Manager | Win32 CredRead via built-in powershell.exe |
| Headless Linux | token file | ~/.gemini/antigravity-cli/antigravity-oauth-token |
Read order: keyring → OS CLI → Windows credman → token file → PTY. Override the file path with AGY_OAUTH_TOKEN_FILE.
HTTP endpoint (optional)
PORT=3007 npm run serve # GET /quota → normalized JSON (5-min cache), GET /healthzConsume GET /quota from an external dashboard/script, or call agy-cli-usage --json as a subprocess.
Development & Release
Written in TypeScript (strict, ESM) and compiled to dist/ with tsc.
npm run build # tsc → dist/ (compiled JS + .d.ts)
npm run check # tsc --noEmit (type-check)
npm test # build, then node --test (no credentials/network; pure logic)- CI: every push/PR runs the test suite on Ubuntu (Node 18/20/22) + macOS/Windows (Node 22).
- Release: release-please — fully automated from Conventional Commits. Merged commits keep a Release PR (version bump + CHANGELOG) up to date; merging that PR creates the tag + GitHub Release and runs
npm publish --provenance.
Caveats
v1internal:retrieveUserQuotaSummaryis a private, undocumented endpoint. Its schema/host may change without notice; the PTY fallback is the safety net. Use it only to check your own account's usage.accountisnullvia the API path for top-tier subscribers. The API path derives the account email from theEmail=param oncurrentTier.upgradeSubscriptionUriin theloadCodeAssistresponse — accounts already on the top tier have no "upgrade" URL, so there's nothing to extract from. This is a known limitation of the undocumented endpoint, not a bug you can work around via flags other than--source pty, which readsAccount: …straight off agy's own rendered/usagepanel and isn't affected.- Credentials are read-only from the OS store; the refresh token is never written back, so it never conflicts with
agy's own session. - The OAuth client_id/secret embedded in the code are
agy's installed-app (public) values — per Google's docs these are not treated as secret. Per-user identity comes from your keyring token, not the client_id.
License
MIT © abruption
For Agent (AI)
Machine-oriented spec for programmatic use. Stable contract: the
--jsonsnapshot and theGET /quotapayload share the same shape (Snapshot).
TL;DR
- Binary:
agy-cli-usage(aliasagy-usage). Node >= 18. Requiresagylogged in on the same host. - Get structured data:
agy-cli-usage --json(stdout) orGET http://127.0.0.1:3007/quota. - Source order in
auto: direct API first, PTY fallback second. Results cached 5 minutes.
Commands
| Invocation | Behavior |
|------------|----------|
| agy-cli-usage | Render the panel to stdout (human format). |
| agy-cli-usage --json | Print the Snapshot JSON to stdout, then exit. |
| agy-cli-usage --watch [secs] | Clear screen and re-render every secs (min 5, default 60). Runs forever. |
| agy-cli-usage --source <auto\|api\|pty> | api: API only (throws on failure). pty: PTY only (ignores cache). auto: API→PTY. |
| agy-cli-usage --channel <auto\|daily\|prod> | Cloud Code host selection. auto tries daily then prod. |
| agy-cli-usage --no-cache / --refresh | Force a fresh fetch (skip the 5-min cache). |
| agy-cli-usage update [--check] | Self-update via npm i -g. --check reports only. |
| agy-cli-usage --version / -v | Print version string to stdout. |
JSON output (--json) — schema
{
"account": "[email protected] | null",
"tier": "string | null",
"fetchedAt": "ISO-8601 timestamp",
"source": "api | pty",
"host": "cloud code host | null",
"note": "string | null",
"groups": [
{
"name": "GEMINI MODELS",
"models": "comma-separated model list (may be empty)",
"buckets": [
{
"kind": "weekly | 5h | <other>",
"label": "Weekly Limit",
"remainingFraction": 0.9172, // 0..1, or null if unknown
"usedFraction": 0.0828, // 1 - remainingFraction, or null
"resetAt": "ISO-8601 | null",
"resetsInSeconds": 264180, // integer seconds, or null
"available": false, // true iff remainingFraction === 1
"description": "string | null"
}
]
}
]
}Notes for parsing:
- Prefer
remainingFraction(fraction remaining, 0–1). Whenavailableistrue, treat as full quota (the panel shows "Quota available"). resetsInSecondsis relative tofetchedAt;resetAtis absolute. Either may benull.kindis normalized toweekly/5hwhere recognized, otherwise the raw window/label string.accountmay benulleven on a successful"source": "api"response — see the Caveats section above (top-tier subscribers have no email source in the API path). Use--source pty/ a PTY-sourced snapshot if you need the account email reliably.
HTTP API (npm run serve / dist/src/server.js)
| Route | Response |
|-------|----------|
| GET /quota | 200 Snapshot JSON (same shape as --json). ?refresh=1 bypasses cache. 502 {"error":...} on failure. Headers: Cache-Control: public, max-age=300, Access-Control-Allow-Origin: *. |
| GET /healthz | 200 {"ok":true} |
| (other) | 404 {"error":"not found"} |
Binds HOST (default 127.0.0.1) : PORT (default 3007).
Environment variables
| Variable | Effect |
|----------|--------|
| AGY_OAUTH_TOKEN_FILE | Override the token file path (headless fallback). |
| AGY_BIN | Path to the agy binary (PTY source). Else resolved from PATH, then ~/.local/bin. |
| XDG_CACHE_HOME | Cache base dir (cache lives at <base>/agy-usage/quota.json; default ~/.cache). |
| NO_COLOR | Disable ANSI color in the rendered panel. |
| PORT / HOST | HTTP server bind (server mode only). |
Exit codes & errors
0— success.1— any error (e.g.CredentialErrorwhen no token is readable and PTY is unavailable). Error text goes to stderr; structured output goes to stdout, so--jsonstdout is safe to parse even when stderr carries warnings (e.g. the[api failed: …] falling back to PTYnotice inautomode).updatereturns the underlyingnpmexit status.
Data sources & cache
- Cache:
<XDG_CACHE_HOME|~/.cache>/agy-usage/quota.json, TTL 5 minutes. Avoids hammering the upstream API on--watch/polling. Bypassed whensource === 'pty'or the cache is disabled (--no-cache/--refresh, or?refresh=1on the HTTP route). - API path reads the token (keyring/file), then calls
loadCodeAssist→retrieveUserQuotaSummary. PTY path drivesagy(python3 ptyon POSIX,node-ptyon Windows) and needsagyrunnable in the environment.
Integration notes
- For automation, call
--json(subprocess) orGET /quota(long-running service). Both go through the same cache, so high-frequency polling is safe. - Do not parse the human panel; it contains ANSI escapes and is layout-oriented. The
SnapshotJSON is the stable contract. - The tool only reads credentials; it never mutates
agy's session or writes tokens back.
