Skip to content

Commit ea93ddb

Browse files
committed
feat: manage AI providers without CodexBar
1 parent a6c5200 commit ea93ddb

25 files changed

Lines changed: 1324 additions & 3188 deletions

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ body:
3939
Quickshell:
4040
Compositor:
4141
Distro:
42-
bash/node/jq/curl:
42+
bash/jq/curl:
4343
validations:
4444
required: true
4545
- type: textarea
@@ -75,4 +75,4 @@ body:
7575
placeholder: |
7676
jq . plugin.json
7777
bash -n providers/get-provider-usage providers/get-copilot-usage providers/get-claude-usage
78-
./providers/get-provider-usage "$(command -v codexbar)" "codex,claude,copilot" "cli" ./providers/get-copilot-usage
78+
./providers/get-provider-usage "codex,claude,copilot" ./providers/get-copilot-usage

.github/workflows/ci.yml

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ jobs:
165165
from pathlib import Path
166166
167167
# collect stub IDs: get-<id>-usage (strip known non-provider scripts)
168-
skip = {'provider', 'provider-wrapper', 'copilot', 'claude'}
168+
skip = {'provider', 'provider-wrapper', 'copilot', 'claude', 'codex', 'provider-health'}
169169
stubs = set()
170170
for f in Path('providers').glob('get-*-usage'):
171171
name = f.name.removeprefix('get-').removesuffix('-usage')
@@ -237,7 +237,7 @@ jobs:
237237
238238
- name: Smoke test — get-provider-usage single provider (error path)
239239
run: |
240-
OUT="$(providers/get-provider-usage "" "openrouter" "cli" "" 2>/dev/null || true)"
240+
OUT="$(providers/get-provider-usage "openrouter" "" 2>/dev/null || true)"
241241
echo "$OUT" | jq --exit-status '. | type == "array" and length > 0' >/dev/null || {
242242
echo "::error::get-provider-usage did not return a non-empty JSON array"
243243
echo "Output was: ${OUT}"
@@ -256,7 +256,7 @@ jobs:
256256
for stub in providers/get-*-usage; do
257257
name="$(basename "$stub")"
258258
case "$name" in
259-
get-provider-usage|get-copilot-usage|get-claude-usage) continue ;;
259+
get-provider-usage|get-provider-health|get-copilot-usage|get-claude-usage|get-codex-usage) continue ;;
260260
esac
261261
# Each stub must exec get-provider-wrapper — verify it contains the pattern
262262
grep -q 'get-provider-wrapper' "$stub" || {
@@ -266,6 +266,22 @@ jobs:
266266
done
267267
exit "$FAIL"
268268
269+
- name: Smoke test — prerequisite health schema
270+
run: |
271+
OUT="$(providers/get-provider-health "codex,perplexity")"
272+
echo "$OUT" | jq --exit-status '
273+
type == "array" and length == 2 and
274+
all(.[]; has("provider") and has("status") and has("detail"))
275+
' >/dev/null
276+
277+
- name: Reject removed aggregation dependency
278+
run: |
279+
removed_name="codex""bar"
280+
if grep -Rin --exclude-dir=.git --exclude='screenshot*.png' "$removed_name" .; then
281+
echo "::error::Removed aggregation dependency is still referenced"
282+
exit 1
283+
fi
284+
269285
# ─── qml ─────────────────────────────────────────────────────────────────────
270286
qml:
271287
name: QML lint

AiOverviewControlSettings.qml

Lines changed: 240 additions & 886 deletions
Large diffs are not rendered by default.

AiOverviewControlWidget.qml

Lines changed: 63 additions & 61 deletions
Large diffs are not rendered by default.

CHANGELOG.md

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,29 @@
22

33
## [Unreleased]
44

5+
## 1.3.0 - 2026-06-10
6+
7+
### Architecture
8+
- Removed the external aggregation executable and its settings, detection, dispatcher arguments, documentation, and diagnostics.
9+
- Added a native Codex adapter using the official `codex app-server` protocol and `account/rateLimits/read`.
10+
- Preserved Copilot quota collection through the authenticated GitHub session without an external aggregator.
11+
- Added provider prerequisite health checks and a truthful coverage model: quota, local analytics, authentication, or informational.
12+
13+
### Providers
14+
- Replaced undocumented Cloudflare, Cohere, Fireworks, MiniMax, GLM, and AI21 quota claims with documented authentication checks or explicit informational states.
15+
- Added Ollama `/api/ps` running-model status alongside `/api/tags`.
16+
- Added upstream verification policy and source links in `docs/provider-verification.md`.
17+
18+
### UI and settings
19+
- Added compact and comfortable dashboard density modes.
20+
- Added provider filtering when more than eight cards are visible.
21+
- Rebuilt settings around provider health, telemetry coverage, informational coverage, and plugin-managed diagnostics.
22+
- Removed obsolete source mode and external-binary path controls.
23+
24+
### Quality
25+
- Updated CI for the new dispatcher contract, health schema, and a regression check preventing the removed dependency from returning.
26+
- Rebuilt English, Brazilian Portuguese, and Simplified Chinese locale bundles with key parity.
27+
528
## 1.2.4 - 2026-05-26
629

730
### Dashboard — UX
@@ -35,7 +58,7 @@
3558
- Pill settings: added pill display options (single/multi accent, label visibility) to the Settings panel.
3659

3760
### Providers — New
38-
- **Warp** (`warp`): codexbar fallback + note-card.
61+
- **Warp** (`warp`): provider note-card.
3962
- **Qwen / DashScope** (`qwen`): key validation via DashScope compatible-mode models endpoint; note-card (no public balance API).
4063
- **Vertex AI** (`vertexai`): `gcloud auth print-access-token` check; note-card (no programmatic quota endpoint).
4164
- Added all 3 providers to `availableProviderOptions`, `providerName()`, `iconForProvider()`, `providerAccent()`, and `allProviders` in Settings.
@@ -86,7 +109,7 @@
86109
- Polished provider cards, metric tiles, overview styling, hover states, and displayed provider counts.
87110
- Fixed Claude daily totals to use the current weekday instead of a hard-coded weekday index.
88111
- Fixed the plugin author metadata.
89-
- Added `codexbar` timeout handling and safer shell interpolation in usage helpers.
112+
- Added external-helper timeout handling and safer shell interpolation in usage helpers.
90113
- CI: restored `actions/checkout@v6.0.2` and `softprops/action-gh-release@v3.0.0` (versões corretas, não existentes antes de 2026).
91114
- Release: corrigido `zip -r "$ZIP" -@``zip "$ZIP" -@` (flags `-r` e `-@` são mutuamente exclusivos).
92115
- Release: substituídas duas etapas separadas `shogo82148/actions-upload-release-asset` pelo parâmetro `files:` nativo do `softprops/action-gh-release@v3.0.0`.
@@ -97,18 +120,18 @@
97120
## 1.2.0 - 2026-04-30
98121

99122
- Added a local `get-provider-usage` backend so AiOverviewControl no longer depends on another DMS plugin for provider aggregation.
100-
- Made `codexbar` an optional executable fallback instead of a hard plugin requirement.
123+
- Made the provider aggregator optional instead of a hard plugin requirement.
101124
- Added native/fallback provider handling for Claude, Copilot, Gemini, and OpenRouter with structured per-provider errors.
102125
- Improved dashboard responsiveness with adaptive cards, grids, provider controls, and long-text handling.
103126
- Made **Show Provider Errors** actually filter provider cards when disabled.
104127
- Updated settings copy to describe local helpers, fallback source mode, and optional fallback binary behavior.
105128
- Reworked the user documentation in Portuguese with a shorter README and focused guides under `docs/`.
106129
- Added practical installation, configuration, provider, troubleshooting, and architecture references.
107-
- Clarified that the plugin is self-contained in `AiOverviewControl` and uses the `codexbar` executable only as a provider fallback, not as another DMS plugin.
130+
- Clarified that the plugin is self-contained in `AiOverviewControl`.
108131

109132
## 1.1.3 - 2026-04-29
110133

111-
- Fixed Copilot on Linux by bypassing the unsupported CodexBar `copilot --source cli` path.
134+
- Fixed Copilot on Linux by using the authenticated GitHub session directly.
112135
- Added `get-copilot-usage`, which uses the authenticated GitHub session to read real Copilot subscription quota data.
113136
- Mapped Copilot Premium, Chat, and Completions windows into the same provider-card data model used by the other providers.
114137
- Updated provider-card labels so named quota windows such as Premium and Chat are shown consistently.
@@ -117,7 +140,7 @@
117140

118141
- Normalized provider display logic so cards use the same current window, weekly window, account, login, credits, source, and error helpers.
119142
- Fixed inconsistent current-vs-weekly percentage rendering in collapsed provider cards.
120-
- Simplified CodexBar error output so unsupported providers show the real provider error instead of raw JSON.
143+
- Simplified aggregator error output so unsupported providers show the real provider error instead of raw JSON.
121144
- Added a dashboard provider manager with an **Add provider** button.
122145
- Added per-card remove controls and a custom provider list field in settings.
123146

@@ -140,7 +163,7 @@
140163

141164
## 1.0.0 - 2026-04-29
142165

143-
- Created AiOverviewControl as a renamed and expanded successor to the DMS CodexBar widget.
166+
- Created AiOverviewControl as a renamed and expanded AI usage widget.
144167
- Added configurable provider sets and source modes.
145168
- Added Linux-friendly `cli` default.
146169
- Added partial provider failure handling.

CLAUDE.md

Lines changed: 30 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -1,142 +1,52 @@
11
# CLAUDE.md
22

3-
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
3+
## Project
44

5-
## Cooauthor
6-
Do not mention the AI provider/model as a cooauthor in the commit message or PR description.
5+
AiOverviewControl is a self-contained DankMaterialShell widget for AI quota, billing, authentication, and local usage telemetry.
76

8-
## Project Overview
7+
Runtime: QML/Quickshell plus Bash helpers. Core dependencies: `bash`, `jq`, and `curl`.
98

10-
DMS widget plugin that monitors AI provider quota health. Shows most-limited provider in DankBar pill; floating dashboard with per-provider cards.
9+
## Rules
1110

12-
**Runtime stack:** QML (Quickshell), bash helper scripts, optional `codexbar` CLI fallback.
11+
- Do not mention an AI provider/model as coauthor in commits or pull requests.
12+
- Keep provider failures isolated.
13+
- Never fabricate quota percentages for providers without a documented surface.
14+
- Prefer official CLI protocols and documented APIs; do not scrape authenticated dashboards.
15+
- Keep the plugin self-contained and preserve user settings during upgrades.
1316

14-
**Key dependencies:** `bash`, `node`, `jq`, `curl`. Optional: `codexbar`, `gh` (Copilot), `claude` CLI.
17+
## Data flow
1518

16-
## Key Files
19+
1. Widget runs `providers/get-provider-usage <providers> <copilot-helper>`.
20+
2. Dispatcher calls one local adapter per provider.
21+
3. Every result follows `{provider, source, usage, credits, error}`.
22+
4. Widget renders healthy and failed providers independently.
23+
5. Claude analytics run separately from the main dispatcher.
1724

18-
| File | Role |
19-
|------|------|
20-
| `AiOverviewControlWidget.qml` | DankBar pill, popout dashboard, QML data collection and normalization |
21-
| `AiOverviewControlSettings.qml` | DMS settings UI |
22-
| `providers/get-provider-usage` | Unified shell backend — dispatches per-provider, returns JSON array |
23-
| `providers/get-copilot-usage` | GitHub Copilot bridge via `gh auth token` or env tokens |
24-
| `providers/get-claude-usage` | Claude Code analytics from `~/.claude` JSONL logs + optional OAuth |
25-
| `plugin.json` | Plugin metadata, capabilities, permissions |
25+
## Settings
2626

27-
## Data Flow
27+
`refreshInterval`, `providerSelection`, `showErrorProviders`, `pillMode`, `pillProviders`, `densityMode`, `costCurrency`, `showClaudeProjects`, `languageOverride`.
2828

29-
1. Widget calls `providers/get-provider-usage` with `providerSelection`, `sourceMode`, optional `codexbarPath`, optional Copilot helper path.
30-
2. Script dispatches per provider — local bridges first, `codexbar` fallback for others.
31-
3. Returns JSON array. Each item: `{ provider, source, usage, credits, error }`.
32-
4. Widget normalizes and renders cards. Errors become isolated cards — do not suppress healthy providers.
33-
5. Provider with highest `usedPercent` drives the compact DankBar indicator.
34-
6. For `claude`, widget may also spawn `providers/get-claude-usage` for 5h/7d windows, token counts, cost estimates.
35-
36-
## Provider Output Schema
37-
38-
```text
39-
provider / source / error
40-
usage.identity.accountEmail
41-
usage.primary / secondary / tertiary
42-
usedPercent, windowMinutes, resetsAt, resetDescription, remaining, unlimited, hasQuota
43-
credits.remaining
44-
```
45-
46-
## Settings Keys
47-
48-
`refreshInterval`, `codexbarPath`, `providerSelection`, `sourceMode`, `showErrorProviders`
49-
50-
Stored in DMS settings store — never overwrite user preferences when updating plugin files.
51-
52-
## Validation Commands
29+
## Validation
5330

5431
```bash
55-
# Lint QML
56-
qmllint AiOverviewControlWidget.qml AiOverviewControlSettings.qml || true
57-
58-
# Validate plugin metadata
5932
jq . plugin.json
33+
bash -n providers/get-*
34+
shellcheck providers/get-*
35+
qmllint AiOverviewControlWidget.qml AiOverviewControlSettings.qml AiOverviewControlI18n.qml
36+
./providers/get-provider-health "codex,claude,copilot" | jq .
37+
./providers/get-codex-usage | jq .
38+
./providers/get-provider-usage "codex,claude,copilot" ./providers/get-copilot-usage | jq .
39+
```
6040

61-
# Test data pipeline end-to-end
62-
~/.config/DankMaterialShell/plugins/AiOverviewControl/providers/get-provider-usage \
63-
"$(command -v codexbar)" "codex,claude,copilot" "cli" \
64-
~/.config/DankMaterialShell/plugins/AiOverviewControl/providers/get-copilot-usage
65-
66-
# Test individual bridges
67-
~/.config/DankMaterialShell/plugins/AiOverviewControl/providers/get-copilot-usage
68-
~/.config/DankMaterialShell/plugins/AiOverviewControl/providers/get-claude-usage
41+
## Provider policy
6942

70-
# Test via codexbar fallback
71-
codexbar usage --format json --provider codex --source cli
72-
codexbar usage --format json --provider claude --source cli
73-
```
43+
See `docs/providers.md` for behavior and `docs/provider-verification.md` for upstream documentation links and evidence level.
7444

7545
## Release
7646

77-
Releases trigger on `v*` tags. CI runs on push/PR to `main` (validates `plugin.json` + optional `qmllint`).
47+
Tag must match `plugin.json` and the changelog entry:
7848

7949
```bash
80-
git tag v1.x.y && git push origin v1.x.y
50+
git tag v1.x.y
51+
git push origin v1.x.y
8152
```
82-
83-
Artifacts: `AiOverviewControl-vX.Y.Z.zip` and `.tar.gz` built from `git ls-files`.
84-
85-
## Provider Matrix
86-
87-
| ID | Name | Source | Env vars required | API endpoint |
88-
|----|------|--------|-------------------|--------------|
89-
| `codex` | Codex | codexbar → 9router fallback || codexbar CLI |
90-
| `claude` | Claude | OAuth local + JSONL | `~/.claude/.credentials.json` | `api.anthropic.com/api/oauth/usage` |
91-
| `copilot` | Copilot | GitHub API | `gh auth login` or `COPILOT_GITHUB_TOKEN` | `api.github.com/copilot_internal/user` (AI Credits model since 2026-06-01: `entitlement`/`remaining`/`token_based_billing`) |
92-
| `gemini` | Gemini | OAuth local or API key | `GEMINI_API_KEY` or `~/.gemini/oauth_creds.json` | Validates key only |
93-
| `openrouter` | OpenRouter | REST API | `OPENROUTER_API_KEY` | `openrouter.ai/api/v1/auth/key` |
94-
| `9router` | 9Router | SQLite local || `~/.9router/db/data.sqlite` |
95-
| `deepseek` | DeepSeek | REST API | `DEEPSEEK_API_KEY` | `api.deepseek.com/user/balance` |
96-
| `kimi` | Kimi | REST API | `MOONSHOT_API_KEY` or `KIMI_API_KEY` (opt. `MOONSHOT_API_BASE`) | `api.moonshot.ai` (global/USD) → `api.moonshot.cn` (China/CNY) fallback, `/v1/users/me/balance` |
97-
| `mistral` | Mistral | API key validation only | `MISTRAL_API_KEY` | `api.mistral.ai/v1/models` (no quota endpoint) |
98-
| `glm` | GLM/Zhipu | REST API | `GLM_API_KEY` or `ZHIPU_API_KEY` | `bigmodel.cn/api/monitor/usage/quota/limit` |
99-
| `minimax` | MiniMax | REST API | `MINIMAX_API_KEY` | `minimax.io/v1/token_plan/remains` |
100-
| `qwen` | Qwen | API key validation only | `DASHSCOPE_API_KEY` or `QWEN_API_KEY` | No quota endpoint — UI only |
101-
| `nvidia` | NVIDIA NIM | API key validation only | `NVIDIA_API_KEY` | No quota endpoint — UI only |
102-
| `cloudflare` | Cloudflare AI | REST API | `CLOUDFLARE_AI_TOKEN`, `CLOUDFLARE_ACCOUNT_ID` | `api.cloudflare.com/v4/accounts/{id}/ai/usage` |
103-
| `vertexai` | Vertex AI | gcloud OAuth | `gcloud auth login` | gcloud local auth check |
104-
| `byteplus` | BytePlus Ark | API key validation only | `BYTEPLUS_API_KEY` or `ARK_API_KEY` | No quota endpoint — UI only |
105-
| `ollama` | Ollama | Local HTTP | `OLLAMA_HOST` (default: localhost:11434) | `localhost:11434/api/tags` |
106-
| `perplexity` | Perplexity | codexbar or note || No public quota endpoint |
107-
| `cursor` | Cursor | codexbar or note || No public quota endpoint |
108-
| `cline` | Cline | note || No REST endpoint |
109-
| `opencode` | OpenCode | note || Proxy only, no billing |
110-
| `kilo` | Kilo | codexbar or note || No public quota endpoint |
111-
| `kiro` | Kiro | codexbar or note || No public quota endpoint |
112-
| `warp` | Warp | codexbar or note || No public quota endpoint |
113-
| `amp` | Amp | codexbar or note || No public quota endpoint |
114-
115-
**Providers not implemented (no API, ToS issues):** Antigravity (Google, ToS violation risk).
116-
117-
## Design Constraints
118-
119-
- Plugin must be self-contained — no imports from other DMS plugins.
120-
- Per-provider isolation: one provider failure must not hide others.
121-
- New provider bridges must output `provider/source/usage/credits/error` schema.
122-
- Collection timeout: 45 seconds. Exceeded → show timeout error, discard stale output.
123-
- Follow DMS theme tokens and Quickshell UI patterns for visual consistency.
124-
125-
## Design Context
126-
127-
### Users
128-
Power users and developers using Dank Material Shell as a daily desktop control surface. They need to glance at AI assistant quota health while switching between CLIs, editors, and providers.
129-
130-
### Brand Personality
131-
Refined, premium, calm. The interface should feel like a dependable shell instrument: compact, readable, and direct, without marketing-style decoration.
132-
133-
### Aesthetic Direction
134-
Dark, token-driven DMS styling with restrained provider accents. Prefer layered surfaces, precise spacing, and a premium control-surface feel that adapts from narrow popouts to larger desktop panels without hiding core actions.
135-
136-
### Design Principles
137-
- Make provider health scannable first, details second.
138-
- Keep every dependency local to AiOverviewControl unless it is an explicit external CLI/API fallback.
139-
- Use responsive component reflow instead of fixed desktop-only rows.
140-
- Treat errors as actionable provider states, not global failure.
141-
- Preserve DMS theme tokens and interaction patterns for consistency with the shell.
142-
- Keep motion subtle, purposeful, and calm.

0 commit comments

Comments
 (0)