diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c950e88..ae8cc73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -220,10 +220,10 @@ jobs: with: persist-credentials: false - - name: Install dependencies (jq, curl) + - name: Install dependencies (jq, curl, sqlite3) run: | sudo apt-get update -qq - sudo apt-get install -y --no-install-recommends jq curl + sudo apt-get install -y --no-install-recommends jq curl sqlite3 - name: Smoke test — get-claude-usage (no credentials) run: | @@ -263,6 +263,38 @@ jobs: } echo "get-provider-usage smoke: OK — provider=${PROVIDER}" + - name: Integration test — Antigravity quota fixture + run: | + OUT="$(ANTIGRAVITY_RESPONSE_FILE=tests/fixtures/antigravity-valid.json \ + ANTIGRAVITY_ACCOUNT_EMAIL=test@example.invalid \ + providers/get-provider-usage "antigravity" "")" + echo "$OUT" | jq -e ' + length == 1 + and .[0].provider == "antigravity" + and .[0].usage.primary.resetDescription == "Claude Opus 4.6" + and .[0].usage.primary.usedPercent == 75 + and .[0].usage.secondary.resetDescription == "Gemini 3.5 Flash" + and .[0].usage.secondary.usedPercent == 50 + and .[0].usage.tertiary.resetDescription == "GPT-OSS 120B" + and .[0].usage.tertiary.usedPercent == 40 + ' >/dev/null + + AUTH_ERROR="$(ANTIGRAVITY_RESPONSE_FILE=tests/fixtures/antigravity-valid.json \ + ANTIGRAVITY_HTTP_STATUS=401 providers/get-provider-usage "antigravity" "")" + echo "$AUTH_ERROR" | jq -e '.[0].error.code == 401' >/dev/null + + RATE_ERROR="$(ANTIGRAVITY_RESPONSE_FILE=tests/fixtures/antigravity-valid.json \ + ANTIGRAVITY_HTTP_STATUS=429 providers/get-provider-usage "antigravity" "")" + echo "$RATE_ERROR" | jq -e '.[0].error.code == 429' >/dev/null + + MISSING_SESSION="$(ANTIGRAVITY_STATE_DB=/does/not/exist \ + providers/get-provider-usage "antigravity" "")" + echo "$MISSING_SESSION" | jq -e '.[0].error.code == 2' >/dev/null + + SCHEMA_ERROR="$(ANTIGRAVITY_RESPONSE_FILE=tests/fixtures/antigravity-schema-changed.json \ + providers/get-provider-usage "antigravity" "")" + echo "$SCHEMA_ERROR" | jq -e '.[0].error.message | contains("schema changed")' >/dev/null + - name: Smoke test — all stubs delegate correctly (structure check) run: | FAIL=0 diff --git a/AiOverviewControlSettings.qml b/AiOverviewControlSettings.qml index a3e11dd..256c3b2 100644 --- a/AiOverviewControlSettings.qml +++ b/AiOverviewControlSettings.qml @@ -60,6 +60,7 @@ PluginSettings { { id:"codex", name:"Codex", icon:"terminal", mode:"telemetry", requirement:"codex CLI", envVar:"", note:"Official app-server rate limits" }, { id:"claude", name:"Claude", icon:"psychology", mode:"telemetry", requirement:"claude CLI or ~/.claude", envVar:"", note:"Local analytics and authenticated usage" }, { id:"copilot", name:"Copilot", icon:"code", mode:"telemetry", requirement:"gh CLI or GitHub token", envVar:"COPILOT_GITHUB_TOKEN", note:"Authenticated Copilot quota from the GitHub session" }, + { id:"antigravity", name:"Antigravity", icon:"rocket_launch", mode:"telemetry", requirement:"Antigravity CLI keyring or IDE session", envVar:"", note:"Per-model quota and reset times from the internal read-only endpoint" }, { id:"gemini", name:"Gemini", icon:"star", mode:"telemetry", requirement:"gemini CLI or API key", envVar:"GEMINI_API_KEY", note:"Authentication status; quota remains in AI Studio" }, { id:"9router", name:"9Router", icon:"share", mode:"telemetry", requirement:"local 9Router database", envVar:"", note:"Local requests, tokens and cost" }, { id:"openrouter", name:"OpenRouter", icon:"route", mode:"telemetry", requirement:"API key or 9Router data", envVar:"OPENROUTER_API_KEY", note:"Official key usage and limits" }, diff --git a/AiOverviewControlWidget.qml b/AiOverviewControlWidget.qml index 6019615..9fcde5f 100644 --- a/AiOverviewControlWidget.qml +++ b/AiOverviewControlWidget.qml @@ -134,6 +134,7 @@ PluginComponent { "codex", "claude", "copilot", + "antigravity", "gemini", "9router", "openrouter", @@ -526,6 +527,7 @@ PluginComponent { codex: "Codex", claude: "Claude", copilot: "Copilot", + antigravity: "Antigravity", cursor: "Cursor", gemini: "Gemini", openrouter: "OpenRouter", @@ -722,6 +724,7 @@ PluginComponent { if (providerId === "codex") return "data_object"; if (providerId === "claude") return "psychology"; if (providerId === "copilot") return "hub"; + if (providerId === "antigravity") return "rocket_launch"; if (providerId === "gemini") return "auto_awesome"; if (providerId === "openrouter") return "route"; if (providerId === "9router") return "share"; @@ -758,6 +761,7 @@ PluginComponent { if (providerId === "claude") return Theme.warning; if (providerId === "codex") return Theme.success; if (providerId === "copilot") return Theme.primary; + if (providerId === "antigravity") return Theme.primary; if (providerId === "gemini") return Theme.secondary; if (providerId === "openrouter") return Theme.primary; if (providerId === "9router") return Theme.secondary; @@ -816,6 +820,10 @@ PluginComponent { const windowData = primaryUsageWindow(provider); if (windowData && windowData.displayValue && String(windowData.displayValue).length > 0) { const label = windowData.resetDescription || t("status.usage", "usage"); + const reset = provider.provider === "antigravity" ? formatTimeUntil(windowData.resetsAt) : ""; + if (reset && reset !== "—") { + return `${source} · ${label} · ${windowData.displayValue} · ${t("status.reset", "reset")} ${reset}`; + } return `${source} · ${label} · ${windowData.displayValue}`; } const reset = providerReset(provider); @@ -973,6 +981,7 @@ PluginComponent { claude: "https://claude.ai/settings/usage", codex: "https://chatgpt.com/codex/settings/usage", copilot: "https://github.com/settings/copilot/features", + antigravity: "", gemini: "https://aistudio.google.com/usage", openrouter: "https://openrouter.ai/activity", deepseek: "https://platform.deepseek.com/usage", diff --git a/CHANGELOG.md b/CHANGELOG.md index 260ae57..5c59bb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ ## [Unreleased] +## 1.5.0 - 2026-06-28 + +### Providers +- **Antigravity provider added (Quota coverage).** Surfaces real per-model quota and reset windows from the Google Cloud Code Assist endpoint (`v1internal:fetchAvailableModels` on `cloudcode-pa.googleapis.com`) — the same protocol used by Antigravity IDE and the official `gemini-cli`. Quotas are grouped into current model families: Claude Opus 4.6, Claude Sonnet 4.6, Gemini 3.5 Flash, Gemini 3.1 Pro, and GPT-OSS 120B. +- **Dual credential discovery.** Authentication prefers the signed-in `agy` CLI profile via Linux Secret Service (`secret-tool`), then falls back to the IDE's `globalStorage/state.vscdb` (`antigravityAuthStatus`) for desktop builds. The OAuth bearer token is supplied to `curl` via stdin and never appears in process arguments, stdout, or logs. +- **Health probe.** `get-provider-health` now recognizes `antigravity` and reports ready/missing based on the keyring or SQLite state availability. + +### Fixed +- **Antigravity Authorization header.** The bearer token was not interpolated into the `curl` config line (missing `%s`), so the live path always failed authentication while fixture tests passed. Token interpolation now works and the live path returns real quota data. + +### Notes +- Provider count: 33 → 34. +- Antigravity additionally requires `sqlite3` on the system for the IDE-state fallback path. + ## 1.4.12 - 2026-06-26 ### Providers diff --git a/README.md b/README.md index 535ccfd..82cb655 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ billing, authentication, and local usage telemetry — right in your DankBar. [](https://github.com/bernardopg/AiOverviewControl/actions/workflows/ci.yml) [](https://github.com/bernardopg/AiOverviewControl/releases/latest) [](./LICENSE) -[](./docs/providers.md) +[](./docs/providers.md) [](./docs/i18n-crowdin.md) [Install](#installation) · [Screenshots](#screenshots) · [Providers](./docs/providers.md) · @@ -48,7 +48,7 @@ it does not. No dashboard scraping. No fabricated percentages. Ever. | | | | --- | --- | -| 📊 **Unified dashboard** | 33 AI providers and developer tools in one place. | +| 📊 **Unified dashboard** | 34 AI providers and developer tools in one place. | | 🛰️ **Fleet overview** | Cross-provider rollup in the hero — quota-only average load, hottest provider, how many are near their cap, and the soonest reset. | | ⏱️ **Official Codex windows** | Rate-limit windows straight from `codex app-server`. | | 🤖 **Deep Claude analytics** | Quota plus local token, session, model, project, and cost analytics. | @@ -84,7 +84,7 @@ Provider cards use one of these honest coverage levels: | Coverage | Meaning | | --- | --- | -| **Quota** | Returns real rate-limit/spend windows and used percentage (Codex, Copilot, OpenRouter, Z.ai, GLM). | +| **Quota** | Returns real rate-limit/spend windows and used percentage (Codex, Copilot, Antigravity, OpenRouter, Z.ai, GLM). | | **Balance** | Returns remaining prepaid balance or credits in real currency (Kimi, DeepSeek, Together). | | **Analytics** | Reads consumption counters or provider-owned local data (Cloudflare GraphQL, 9Router, Claude, Ollama). | | **Authentication** | Verifies credentials via a read-only endpoint without stable quota data (Gemini, Mistral, NVIDIA, MiniMax, Qwen, xAI, and more). | @@ -97,6 +97,7 @@ Notable integrations: | Codex | Official `codex app-server` account and rate-limit methods. | | Claude Code | OAuth quota plus local `~/.claude/projects` analytics. | | GitHub Copilot | Authenticated GitHub/Copilot quota snapshot. | +| Antigravity | Per-model quota and reset times from the Cloud Code Assist endpoint used by Antigravity IDE and gemini-cli. | | 9Router | Local SQLite or JSON usage data, including routed-model telemetry. | | OpenRouter | Key limits, spend, balance, and 30-day model activity. | | Kimi (Moonshot) | `GET /v1/users/me/balance` — available, voucher, and cash balance (USD/CNY). | @@ -114,7 +115,7 @@ The full matrix, credentials, and upstream references are documented in - DankMaterialShell running on Quickshell. - `bash`, `jq`, and `curl`. -- Provider-specific CLIs or credentials only for providers you enable. +- Provider-specific CLIs or credentials only for providers you enable; Antigravity additionally requires `sqlite3`. Recommended baseline for the default provider set: diff --git a/docs/README.pt-BR.md b/docs/README.pt-BR.md index f71cf05..e713eac 100644 --- a/docs/README.pt-BR.md +++ b/docs/README.pt-BR.md @@ -12,7 +12,7 @@ billing, autenticação e telemetria local de uso de IA — direto na sua DankBa [](https://github.com/bernardopg/AiOverviewControl/actions/workflows/ci.yml) [](https://github.com/bernardopg/AiOverviewControl/releases/latest) [](../LICENSE) -[](./providers.md) +[](./providers.md) [](./i18n-crowdin.md) [Instalação](#instalação) · [Screenshots](#screenshots) · [Provedores](./providers.md) · @@ -97,6 +97,7 @@ Integrações medidas notáveis: | Codex | Métodos oficiais de conta e rate-limit do `codex app-server`. | | Claude Code | Cota OAuth mais analytics local de `~/.claude/projects`. | | GitHub Copilot | Snapshot autenticado de cota GitHub/Copilot. | +| Antigravity | Cotas por modelo e horários de reset via endpoint Cloud Code Assist, usado pela IDE Antigravity e pelo gemini-cli. | | 9Router | Dados locais de uso em SQLite ou JSON, incluindo telemetria por modelo roteado. | | OpenRouter | Limites de chave, gasto, saldo e atividade de modelos em 30 dias. | | DeepSeek, Kimi, Together | APIs de saldo ou crédito do provedor. | @@ -112,7 +113,7 @@ A matriz completa, credenciais e referências upstream estão documentadas em - DankMaterialShell rodando sobre Quickshell. - `bash`, `jq` e `curl`. -- CLIs ou credenciais específicas apenas para os provedores habilitados. +- CLIs ou credenciais específicas apenas para os provedores habilitados; Antigravity também requer `sqlite3`. Linha de base recomendada para o conjunto padrão de provedores: diff --git a/docs/architecture.md b/docs/architecture.md index dfe3de4..b75500c 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -11,6 +11,7 @@ providers/get-provider-health Prerequisite checks for settings providers/get-codex-usage Codex app-server protocol bridge providers/get-claude-usage Claude local analytics and quota bridge providers/get-copilot-usage Authenticated GitHub Copilot quota bridge +providers/get-antigravity-usage Local Antigravity session quota bridge providers/get-provider-wrapper Single-provider wrapper providers/get-*-usage Canonical provider entrypoints ``` @@ -62,6 +63,10 @@ Errors return: `get-codex-usage` starts `codex app-server`, sends `initialize`, `account/read`, and `account/rateLimits/read`, then maps the official response to the common schema. The bridge uses a bounded process lifetime and never reads browser state. +## Antigravity protocol + +`get-antigravity-usage` reads the current Antigravity CLI OAuth profile from the desktop keyring, falling back to the IDE SQLite state used by older builds, and calls the read-only `v1internal:fetchAvailableModels` endpoint on `cloudcode-pa.googleapis.com` — the same host used by Antigravity IDE and the official gemini-cli. It groups model quotas into current families (Claude Opus 4.6, Claude Sonnet 4.6, Gemini 3.5 Flash, Gemini 3.1 Pro, GPT-OSS 120B), ordered by highest consumption. The bearer token is supplied to curl over stdin and is never printed or placed in process arguments. + ## Settings keys | Key | Default | Purpose | diff --git a/docs/configuration.md b/docs/configuration.md index 115de9d..c4ff2c3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -29,6 +29,8 @@ codex,claude,copilot Add API providers only after their required environment variables are available to the DMS process. +Antigravity does not use an environment variable. It prefers the signed-in CLI profile from Linux Secret Service via `secret-tool`, then falls back to `${XDG_CONFIG_HOME:-~/.config}/Antigravity/User/globalStorage/state.vscdb` via `sqlite3` for older IDE builds. + ## Environment variables | Provider | Variables | diff --git a/docs/providers.md b/docs/providers.md index c8b1f78..751af66 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -21,7 +21,7 @@ Every provider maps to exactly one coverage level. The level dictates what the w | Level | Meaning | Example providers | | --- | --- | --- | -| **Quota** | Real `usedPercent` + reset window from an official protocol/API. | `codex`, `copilot`, `openrouter`, `zai`, `glm` | +| **Quota** | Real `usedPercent` + reset window from a protocol/API. | `codex`, `copilot`, `antigravity`, `openrouter`, `zai`, `glm` | | **Balance** | Remaining prepaid balance / credits in real currency. | `kimi`, `deepseek`, `together` | | **Analytics** | Consumption counters (requests/tokens/neurons/cost) with no remaining-quota value. | `cloudflare` (GraphQL), `9router`, `claude` (local) | | **Auth** | Read-only key validation only — no usage numbers. | `gemini`, `mistral`, `nvidia`, `qwen`, `byteplus`, `groq`, `cohere`, `replicate`, `fireworks`, `minimax`, `xai`, `kilo` | @@ -83,6 +83,17 @@ The matrix below summarises the **authentication/billing surface** for every sup
antigravity~/.config/Antigravityv1internal:fetchAvailableModels on cloudcode-pa.googleapis.comgeminiGET /v1beta/models