Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions AiOverviewControlSettings.qml
Original file line number Diff line number Diff line change
Expand Up @@ -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" },
Expand Down
9 changes: 9 additions & 0 deletions AiOverviewControlWidget.qml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ PluginComponent {
"codex",
"claude",
"copilot",
"antigravity",
"gemini",
"9router",
"openrouter",
Expand Down Expand Up @@ -526,6 +527,7 @@ PluginComponent {
codex: "Codex",
claude: "Claude",
copilot: "Copilot",
antigravity: "Antigravity",
cursor: "Cursor",
gemini: "Gemini",
openrouter: "OpenRouter",
Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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",
Expand Down
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ billing, authentication, and local usage telemetry — right in your DankBar.
[![CI](https://github.com/bernardopg/AiOverviewControl/actions/workflows/ci.yml/badge.svg)](https://github.com/bernardopg/AiOverviewControl/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/bernardopg/AiOverviewControl)](https://github.com/bernardopg/AiOverviewControl/releases/latest)
[![License](https://img.shields.io/github/license/bernardopg/AiOverviewControl)](./LICENSE)
[![Providers](https://img.shields.io/badge/providers-33-7C4DFF)](./docs/providers.md)
[![Providers](https://img.shields.io/badge/providers-34-7C4DFF)](./docs/providers.md)
[![Languages](https://img.shields.io/badge/UI%20languages-5-00BFA5)](./docs/i18n-crowdin.md)

[Install](#installation) · [Screenshots](#screenshots) · [Providers](./docs/providers.md) ·
Expand Down Expand Up @@ -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. |
Expand Down Expand Up @@ -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). |
Expand All @@ -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). |
Expand All @@ -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:

Expand Down
5 changes: 3 additions & 2 deletions docs/README.pt-BR.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ billing, autenticação e telemetria local de uso de IA — direto na sua DankBa
[![CI](https://github.com/bernardopg/AiOverviewControl/actions/workflows/ci.yml/badge.svg)](https://github.com/bernardopg/AiOverviewControl/actions/workflows/ci.yml)
[![Release](https://img.shields.io/github/v/release/bernardopg/AiOverviewControl)](https://github.com/bernardopg/AiOverviewControl/releases/latest)
[![Licença](https://img.shields.io/github/license/bernardopg/AiOverviewControl)](../LICENSE)
[![Provedores](https://img.shields.io/badge/provedores-33-7C4DFF)](./providers.md)
[![Provedores](https://img.shields.io/badge/provedores-34-7C4DFF)](./providers.md)
[![Idiomas](https://img.shields.io/badge/idiomas%20de%20UI-5-00BFA5)](./i18n-crowdin.md)

[Instalação](#instalação) · [Screenshots](#screenshots) · [Provedores](./providers.md) ·
Expand Down Expand Up @@ -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. |
Expand All @@ -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:

Expand Down
5 changes: 5 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -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 |
Expand Down
2 changes: 2 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
13 changes: 12 additions & 1 deletion docs/providers.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` |
Expand Down Expand Up @@ -83,6 +83,17 @@ The matrix below summarises the **authentication/billing surface** for every sup
</tr>
<!-- Focus providers -->
<tr>
<td><code>antigravity</code></td>
<td>Quota (Cloud Code Assist)</td>
<td>✅ local Antigravity OAuth session</td>
<td>⚠️ per-model remaining fraction + reset time</td>
<td>✅ Antigravity plan</td>
<td>—</td>
<td><code>~/.config/Antigravity</code></td>
<td>Antigravity IDE</td>
<td><code>v1internal:fetchAvailableModels</code> on <code>cloudcode-pa.googleapis.com</code></td>
</tr>
<tr>
<td><code>gemini</code></td>
<td>Auth</td>
<td>✅ <code>GET /v1beta/models</code></td>
Expand Down
2 changes: 1 addition & 1 deletion plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "aiOverviewControl",
"name": "AiOverviewControl",
"description": "Plugin-managed AI quota, billing, authentication, and local usage telemetry for DankMaterialShell",
"version": "1.4.12",
"version": "1.5.0",
"author": "bernardopg",
"icon": "monitoring",
"type": "widget",
Expand Down
5 changes: 5 additions & 0 deletions providers/get-antigravity-usage
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
exec "$SCRIPT_DIR/get-provider-wrapper" antigravity
4 changes: 4 additions & 0 deletions providers/get-provider-health
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ status_for() {
claude) command -v claude >/dev/null 2>&1 || [ -d "$HOME/.claude" ] || { status="missing"; detail="claude CLI or ~/.claude"; } ;;
copilot) command -v gh >/dev/null 2>&1 || has_any_env COPILOT_GITHUB_TOKEN GH_TOKEN GITHUB_TOKEN || { status="missing"; detail="gh CLI or GitHub token"; } ;;
gemini) command -v gemini >/dev/null 2>&1 || has_any_env GEMINI_API_KEY GOOGLE_API_KEY GOOGLE_GENERATIVE_AI_API_KEY || { status="missing"; detail="gemini CLI or API key"; } ;;
antigravity)
command -v secret-tool >/dev/null 2>&1 || command -v sqlite3 >/dev/null 2>&1 || { status="missing"; detail="secret-tool or sqlite3"; }
[ "$status" != "ready" ] || command -v secret-tool >/dev/null 2>&1 || [ -r "${XDG_CONFIG_HOME:-$HOME/.config}/Antigravity/User/globalStorage/state.vscdb" ] || { status="missing"; detail="CLI keyring or IDE state"; }
;;
9router) [ -f "$HOME/.9router/db/data.sqlite" ] || [ -f "$HOME/.9router/usage.json" ] || { status="missing"; detail="9Router usage database"; } ;;
openrouter) has_any_env OPENROUTER_API_KEY || [ -f "$HOME/.9router/db/data.sqlite" ] || { status="missing"; detail="OPENROUTER_API_KEY or 9Router data"; } ;;
deepseek) has_any_env DEEPSEEK_API_KEY || { status="missing"; detail="DEEPSEEK_API_KEY"; } ;;
Expand Down
Loading