From 763b644660ff883aeee6d8f194dd89c7fd1ffe67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Rosenkranz?= Date: Mon, 24 Aug 2026 20:15:51 +0000 Subject: [PATCH 1/2] feat(providers): add Command Code with live 5h/weekly/monthly windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new quota provider for commandcode.ai subscriptions. Reads /alpha/billing/credits for live 5-hour and weekly USD usage plus the monthly credit balance, with a graceful fallback to the documented /provider/v1/models endpoint on alpha-namespace failures. The /alpha/ namespace is experimental — the adapter labels the fallback path honestly and never fabricates a percentage. Refs #20 Co-authored-by: René Rosenkranz --- AiOverviewControlSettings.qml | 1 + AiOverviewControlWidget.qml | 8 ++ README.md | 1 + docs/providers.md | 25 ++++ providers/get-commandcode-usage | 4 + providers/get-provider-usage | 123 ++++++++++++++++++ tests/fixtures/commandcode-billing.json | 14 ++ tests/fixtures/commandcode-models.json | 1 + tests/fixtures/commandcode-subscriptions.json | 1 + tests/fixtures/commandcode-whoami.json | 1 + tests/test-commandcode.sh | 93 +++++++++++++ 11 files changed, 272 insertions(+) create mode 100755 providers/get-commandcode-usage create mode 100644 tests/fixtures/commandcode-billing.json create mode 100644 tests/fixtures/commandcode-models.json create mode 100644 tests/fixtures/commandcode-subscriptions.json create mode 100644 tests/fixtures/commandcode-whoami.json create mode 100755 tests/test-commandcode.sh diff --git a/AiOverviewControlSettings.qml b/AiOverviewControlSettings.qml index 63bd1b0..2f88c37 100644 --- a/AiOverviewControlSettings.qml +++ b/AiOverviewControlSettings.qml @@ -269,6 +269,7 @@ PluginSettings { { id:"deepseek", name:"DeepSeek", icon:"search", mode:"telemetry", requirement:"API key", envVar:"DEEPSEEK_API_KEY", note:"Official account balance" }, { id:"kimi", name:"Kimi", icon:"language", mode:"telemetry", requirement:"API key", envVar:"MOONSHOT_API_KEY", note:"Account balance (USD/CNY), or Kimi Code subscription quota with a sk-kimi- key / KIMI_CODING_API_KEY" }, { id:"minimax", name:"MiniMax", icon:"bar_chart", mode:"telemetry", requirement:"API key", envVar:"MINIMAX_API_KEY", note:"Official models API authentication check" }, + { id:"commandcode", name:"Command Code", icon:"terminal", mode:"quota", requirement:"API key", envVar:"COMMAND_CODE_API_KEY", note:"Provider API key — same key used for the CLI and the Provider API. Reads /alpha/billing/credits for 5h/weekly/monthly quota; falls back to /provider/v1/models on alpha failure." }, { id:"glm", name:"GLM", icon:"memory", mode:"telemetry", requirement:"API key", envVar:"GLM_API_KEY", note:"China (Zhipu) quota windows and plan; falls back to models authentication" }, { id:"zai", name:"Z.ai", icon:"bubble_chart", mode:"telemetry", requirement:"API key", envVar:"ZAI_API_KEY", note:"Official quota windows and plan; falls back to models authentication" }, { id:"mistral", name:"Mistral", icon:"wind_power", mode:"telemetry", requirement:"API key", envVar:"MISTRAL_API_KEY", note:"Official models API authentication check" }, diff --git a/AiOverviewControlWidget.qml b/AiOverviewControlWidget.qml index 6e0ae09..7a3b697 100644 --- a/AiOverviewControlWidget.qml +++ b/AiOverviewControlWidget.qml @@ -184,6 +184,7 @@ PluginComponent { "glm", "zai", "minimax", + "commandcode", "qwen", "nvidia", "cloudflare", @@ -587,6 +588,9 @@ PluginComponent { zhipu: "GLM", zai: "Z.ai", minimax: "MiniMax", + commandcode: "Command Code", + cmd: "Command Code", + cmdcode: "Command Code", qwen: "Qwen", dashscope: "Qwen", alibaba: "Qwen", @@ -845,6 +849,7 @@ PluginComponent { if (providerId === "mistral") return Theme.warning; if (providerId === "glm" || providerId === "zhipu" || providerId === "zai") return Theme.primary; if (providerId === "minimax") return Theme.success; + if (providerId === "commandcode" || providerId === "cmd" || providerId === "cmdcode") return Theme.primary; if (providerId === "qwen" || providerId === "dashscope" || providerId === "alibaba") return Theme.warning; if (providerId === "nvidia" || providerId === "nim") return Theme.success; if (providerId === "cloudflare") return Theme.warning; @@ -1316,6 +1321,9 @@ PluginComponent { zhipu: "https://open.bigmodel.cn/usercenter/financial", zai: "https://z.ai/manage-apikey/billing", minimax: "https://platform.minimax.io/user-center/payment/balance", + commandcode: "https://commandcode.ai/billing", + cmd: "https://commandcode.ai/billing", + cmdcode: "https://commandcode.ai/billing", qwen: "https://dashscope.console.aliyun.com", dashscope: "https://dashscope.console.aliyun.com", alibaba: "https://dashscope.console.aliyun.com", diff --git a/README.md b/README.md index 5169f40..2f6a46c 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,7 @@ Notable integrations: | Together | Read-only API-key validation; usage and billing remain in the Together console. | | Cloudflare | Token verification and optional Workers AI GraphQL analytics. | | Z.ai, GLM | `GET /api/monitor/usage/quota/limit` — real per-window usage %, reset timestamps, and plan tier. Falls back to `/models` auth-only check. | +| Command Code | Live 5h/weekly/monthly usage via `/alpha/billing/credits`. | | xAI, MiniMax, Qwen, Mistral | Read-only `/models` (or `/api-key`) validation — zero token consumption. | | NVIDIA | Configured-key status only; its public model catalog cannot validate the key. | | Ollama | Installed and running models from `/api/tags` and `/api/ps`. | diff --git a/docs/providers.md b/docs/providers.md index 371c77b..bbffa14 100644 --- a/docs/providers.md +++ b/docs/providers.md @@ -160,6 +160,17 @@ The matrix below summarises the **authentication/billing surface** for every sup platform.minimax.io/docs +commandcode +Quota +✅ GET /provider/v1/models +✅ /alpha/billing/credits (5h + weekly) +✅ Go / GOAT / Pro / Max / Team Pro / Provider API +✅ USD credit balance + per-window USD usage +COMMAND_CODE_API_KEY +commandcode.ai/billing +Provider API docs + + kimi Balance / Quota ✅ GET /v1/models @@ -533,6 +544,20 @@ Detailed adapter notes for the focus providers (Gemini, Cloudflare, Mistral, GLM | **Changelog** | **2026-06-01 MiniMax-M3** (1M ctx, adaptive thinking, coding SOTA). 2026-03-18 M2.7/M2.7-highspeed. 2026-02 M2.5. 2025-12-22 M2.1. 2025-10-27 M2 + Hailuo-2.3. Token Plan replaced Coding Plan (broader coverage, separate Subscription Key). | | **Adapter** | `fetch_minimax_native` — `/v1/models` validation. | +### Command Code + +| | | +| --- | --- | +| **API base** | `https://api.commandcode.ai/provider/v1` (OpenAI/Anthropic-compatible); quota `https://api.commandcode.ai/alpha/billing/credits` (Bearer, no cookies). | +| **Env var** | `COMMAND_CODE_API_KEY` — same Provider API key used for `/provider/v1/models`, `/alpha/whoami`, `/alpha/billing/credits`. | +| **Auth** | `Authorization: Bearer ***` | +| **Quota / balance** | `/alpha/billing/credits` returns `windowLimits.fiveHour` (5h USD used/cap, Unix-ms `resetAt`), `windowLimits.weekly` (7-day USD used/cap, Unix-ms `resetAt`), and `credits.monthlyCredits` (remaining USD this billing cycle). `/alpha/billing/subscriptions` exposes `planId` (e.g. `individual-goat`) and `currentPeriodEnd`. | +| **Plans** | **Go** $1 / $10 credit · **GOAT** $10 / $70 credit, 5h $14 / weekly $35 · **Pro** $20 / $80 credit, 5h $16 / weekly $40 · **Max 10×** $100 / $150 credit, 5h $45 / weekly $90 · **Max 20×** $200 / $300 credit, 5h $90 / weekly $180 · **Team Pro** $40 / $40 credit, 5h $12 / weekly $24 · **Provider API** $15 + pay-as-you-go. | +| **Billing** | Per-token, no markup on the Provider plan. Credits roll over and never expire. Window caps are USD ceilings — model deals (e.g. `minimax-m3` 2×, `google/gemini-3.7-flash` 50% off, `mimo-v2.5-pro` 99% off) apply automatically. | +| **Stability** | The `/alpha/` namespace is **experimental** — no documented versioned contract, can change without notice. Adapter degrades to the documented `/provider/v1/models` endpoint on alpha failure and emits a clearly-labeled "quota endpoint unavailable" note; it never fabricates a percentage. | +| **Dashboard** | [commandcode.ai/billing](https://commandcode.ai/billing) — billing, plan, and credit top-ups. | +| **Adapter** | `fetch_commandcode_native` — `/alpha/billing/credits` + `/alpha/whoami` + `/alpha/billing/subscriptions`, with documented-endpoint fallback. | + ### Kimi (Moonshot AI) | | | diff --git a/providers/get-commandcode-usage b/providers/get-commandcode-usage new file mode 100755 index 0000000..8fda3fc --- /dev/null +++ b/providers/get-commandcode-usage @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +exec "$SCRIPT_DIR/get-provider-wrapper" commandcode \ No newline at end of file diff --git a/providers/get-provider-usage b/providers/get-provider-usage index f0ebe66..b72ed84 100755 --- a/providers/get-provider-usage +++ b/providers/get-provider-usage @@ -1473,6 +1473,126 @@ fetch_minimax_native() { json_error minimax minimax-api "${http_status:-1}" provider "MiniMax API key invalid (HTTP ${http_status:-0}). Balance visible at platform.minimax.io only." } +fetch_commandcode_native() { + # Command Code (commandcode.ai) — coding-agent subscription quota. The same + # Provider API key drives inference (/provider/v1/models) and quota + # introspection (/alpha/billing/credits). The /alpha/ namespace is + # experimental, so on failure we degrade to /provider/v1/models (auth-only). + local key="${COMMAND_CODE_API_KEY:-}" + if [ -z "$key" ]; then + json_error commandcode commandcode-api 2 provider "COMMAND_CODE_API_KEY is not set. Get your key at commandcode.ai/studio" + return 0 + fi + + local tmp_body tmp_sub tmp_who http_status + tmp_body="$(mktemp)" + tmp_sub="$(mktemp)" + tmp_who="$(mktemp)" + + # Primary: /alpha/billing/credits — 5h USD used/cap, weekly USD used/cap, and + # the monthly USD credit balance. Zero token cost, no inference call. + http_status="$(curl -sS --max-time 8 -o "$tmp_body" -w '%{http_code}' \ + -H "Authorization: Bearer ***" \ + -H "Accept: application/json" \ + "https://api.commandcode.ai/alpha/billing/credits" 2>/dev/null || true)" + + if [ "$http_status" = "401" ] || [ "$http_status" = "403" ]; then + local message + message="$(jq -r '.error.message // .message // empty' "$tmp_body" 2>/dev/null || true)" + [ -n "$message" ] || message="Command Code API key invalid (HTTP ${http_status})." + rm -f "$tmp_body" "$tmp_sub" "$tmp_who" + json_error commandcode commandcode-api "${http_status}" provider "$message" + return 0 + fi + + if [ "$http_status" = "200" ] && jq -e '.windowLimits and .credits' "$tmp_body" >/dev/null 2>&1; then + # Best-effort identity enrichment (4s timeouts — never fail the whole call). + curl -sS --max-time 4 -o "$tmp_who" \ + -H "Authorization: Bearer ***" \ + -H "Accept: application/json" \ + "https://api.commandcode.ai/alpha/whoami" 2>/dev/null || printf '' >"$tmp_who" + curl -sS --max-time 4 -o "$tmp_sub" \ + -H "Authorization: Bearer ***" \ + -H "Accept: application/json" \ + "https://api.commandcode.ai/alpha/billing/subscriptions" 2>/dev/null || printf '' >"$tmp_sub" + + jq -c --slurpfile who "$tmp_who" --slurpfile sub "$tmp_sub" ' + def clamp($n): if $n < 0 then 0 elif $n > 100 then 100 else $n end; + def ms_to_iso($ms): if $ms then (($ms / 1000) | todate) else null end; + def num($v): ($v // 0 | tonumber? // 0); + def plan_name($id): + if $id == "individual-go" then "Go" + elif $id == "individual-goat" then "GOAT" + elif $id == "individual-pro" then "Pro" + elif $id == "individual-max-10x"then "Max 10x" + elif $id == "individual-max-20x"then "Max 20x" + elif $id == "team-pro" then "Team Pro" + elif $id == "provider" then "Provider API" + else ($id // "Command Code account") end; + def make_window($w; $minutes; $label): + if $w == null then null + else { + usedPercent: clamp(((num($w.used) / num($w.cap)) * 100)), + windowMinutes: $minutes, + resetsAt: ms_to_iso($w.resetAt), + resetDescription: $label, + displayValue: ("$" + ($w.used | tostring) + " / $" + ($w.cap | tostring)) + } end; + + . as $body | + ($who[0].user.email // null) as $email | + ($who[0].user.name // null) as $name | + ($sub[0].data.planId // null) as $plan | + plan_name($plan) as $plan_label | + (if $email != null and $email != "" then + (if $name != null and $name != "" then "\($name) (\($email))" else $email end) + elif $plan != null then ("Command Code " + $plan_label) + else "Command Code account" end) as $identity | + ($body.credits.monthlyCredits // null) as $monthly | + ($body.windowLimits.fiveHour // null) as $fh | + ($body.windowLimits.weekly // null) as $wk | + ($fh != null or $wk != null) as $has_window | + (if $has_window then "commandcode-alpha" else "commandcode-api" end) as $source | + { + provider: "commandcode", + source: $source, + usage: { + identity: {providerID: "commandcode", accountEmail: $identity, loginMethod: "api-key"}, + accountEmail: $identity, + loginMethod: "api-key", + primary: make_window($fh; 300; "5h"), + secondary: make_window($wk; 10080; "weekly"), + tertiary: null, + updatedAt: (now | todate) + }, + credits: {remaining: (if $monthly != null then ("$" + ($monthly | tostring)) else ("Command Code " + $plan_label) end)} + } + ' "$tmp_body" + rm -f "$tmp_body" "$tmp_sub" "$tmp_who" + return 0 + fi + + # /alpha/ failed (timeout, 5xx, parse error). Try the documented + # /provider/v1/models endpoint — auth-only confirmation that the key works. + rm -f "$tmp_body" + tmp_body="$(mktemp)" + http_status="$(curl -sS --max-time 8 -o "$tmp_body" -w '%{http_code}' \ + -H "Authorization: Bearer ***" \ + -H "Accept: application/json" \ + "https://api.commandcode.ai/provider/v1/models" || true)" + rm -f "$tmp_body" "$tmp_sub" "$tmp_who" + + if [ "$http_status" = "200" ]; then + json_note_usage commandcode commandcode-models "Command Code account" "api-key" \ + "Authenticated — quota endpoint unavailable, billing at commandcode.ai/billing" \ + "commandcode.ai/billing" + return 0 + fi + json_note_usage commandcode commandcode-api "Command Code account" "api-key" \ + "API key set; Command Code unreachable" \ + "commandcode.ai/billing" +} + fetch_glm_native() { # GLM and Z.ai share one credential family. Honor ZAI_API_KEY here too so a # single key drives both cards (matches docs/providers.md credential matrix). @@ -2253,6 +2373,9 @@ fetch_provider() { minimax) fetch_minimax_native ;; + commandcode|cmd|cmdcode) + fetch_commandcode_native + ;; glm|zhipu) fetch_glm_native ;; diff --git a/tests/fixtures/commandcode-billing.json b/tests/fixtures/commandcode-billing.json new file mode 100644 index 0000000..28d1662 --- /dev/null +++ b/tests/fixtures/commandcode-billing.json @@ -0,0 +1,14 @@ +{ + "credits": { + "belowThreshold": false, + "monthlyCredits": 32.50, + "purchasedCredits": 0, + "freeCredits": 0 + }, + "windowLimits": { + "limited": true, + "exceeded": null, + "fiveHour": { "used": 4.20, "cap": 14, "exceeded": false, "resetAt": 1789000000000 }, + "weekly": { "used": 25.00, "cap": 35, "exceeded": false, "resetAt": 1789999999000 } + } +} \ No newline at end of file diff --git a/tests/fixtures/commandcode-models.json b/tests/fixtures/commandcode-models.json new file mode 100644 index 0000000..3384565 --- /dev/null +++ b/tests/fixtures/commandcode-models.json @@ -0,0 +1 @@ +{ "object": "list", "data": [{"id": "claude-sonnet-5", "object": "model", "created": 1, "owned_by": "command-code", "name": "Claude Sonnet 5", "context_length": 1000000}] } \ No newline at end of file diff --git a/tests/fixtures/commandcode-subscriptions.json b/tests/fixtures/commandcode-subscriptions.json new file mode 100644 index 0000000..342c7e2 --- /dev/null +++ b/tests/fixtures/commandcode-subscriptions.json @@ -0,0 +1 @@ +{ "success": true, "data": { "planId": "individual-goat", "status": "active", "currentPeriodEnd": "2026-09-20T13:22:17.000Z", "cancelAtPeriodEnd": false } } \ No newline at end of file diff --git a/tests/fixtures/commandcode-whoami.json b/tests/fixtures/commandcode-whoami.json new file mode 100644 index 0000000..e0adc21 --- /dev/null +++ b/tests/fixtures/commandcode-whoami.json @@ -0,0 +1 @@ +{ "success": true, "user": { "id": "test-id", "name": "Test User", "email": "test@example.com", "userName": "testuser" } } \ No newline at end of file diff --git a/tests/test-commandcode.sh b/tests/test-commandcode.sh new file mode 100755 index 0000000..572f5b1 --- /dev/null +++ b/tests/test-commandcode.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# Command Code subscription quota tracking — fake-curl unit test. +# Verifies the alpha billing endpoint maps to 5h (primary) + weekly (secondary) +# + monthly USD credits, with graceful fallback to /provider/v1/models on alpha failure. +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +TMP="$(mktemp -d)" +trap 'rm -rf "$TMP"' EXIT +mkdir -p "$TMP/bin" + +# Fake curl that mimics real curl behavior: +# -o file → writes body to file, suppresses body on stdout +# -w FORMAT → writes FORMAT to stdout (independent of -o) +# When both -o and -w are present, body goes to file and FORMAT goes to stdout — +# exactly like real curl. +# +# The stub MUST exit 0 in every branch — the parent script runs curls without +# -w for identity enrichment and treats a non-zero exit as a network error, +# overwriting the body file with an empty string. Forcing `exit 0` at the end +# keeps that error-handling path inert for our fixture-backed tests. +# +# The heredoc MUST be single-quoted ('STUB') so $@, ${args[@]}, etc. are written +# literally and expanded at stub-execution time, not heredoc-write time. +make_stub() { + local pattern="$1" + cat > "$TMP/bin/curl" <<'STUB' +#!/usr/bin/env bash +out="" +url="" +write_code=0 +args=("$@") +for ((i = 0; i < ${#args[@]}; i++)); do + case "${args[$i]}" in + -o) out="${args[$((i + 1))]}" ;; + -w) write_code=1 ;; + http*) url="${args[$i]}" ;; + esac +done +case "$url" in +__PATTERN__ +esac +if [ "$write_code" -eq 1 ]; then printf '200'; fi +exit 0 +STUB + # Replace the __PATTERN__ placeholder with the actual case body for this test. + python3 -c " +import sys +fn = '$TMP/bin/curl' +with open(fn) as f: s = f.read() +s = s.replace('__PATTERN__', '''$pattern''') +with open(fn, 'w') as f: f.write(s) +" + chmod +x "$TMP/bin/curl" +} + +# 1. Happy path — alpha billing returns quota + whoami + subscriptions. +# The literal $out / $ROOT in the case arms are the source of truth for the +# running stub (set at execution time, not heredoc-write time); shellcheck +# flags them as SC2016 because they sit inside a single-quoted shell fragment +# we deliberately only expand with help. The braces below keep SC2016 scoped +# to these three lines without disabling it for the whole file. +# shellcheck disable=SC2016 +make_stub ' *alpha/billing/credits*) [ -n "$out" ] && cp "'"$ROOT"'/tests/fixtures/commandcode-billing.json" "$out" ;; + *alpha/billing/subscriptions*)[ -n "$out" ] && cp "'"$ROOT"'/tests/fixtures/commandcode-subscriptions.json" "$out" ;; + *alpha/whoami*) [ -n "$out" ] && cp "'"$ROOT"'/tests/fixtures/commandcode-whoami.json" "$out" ;;' + +run() { PATH="$TMP/bin:$PATH" "$@" "$ROOT/providers/get-provider-usage" commandcode 2>/dev/null; } +fail() { echo "FAIL: $1" >&2; exit 1; } + +out="$(run env -u COMMAND_CODE_API_KEY COMMAND_CODE_API_KEY=user_test)" +[ "$(jq -r '.[0].source' <<<"$out")" = "commandcode-alpha" ] || fail "source" +[ "$(jq -r '.[0].usage.primary.windowMinutes' <<<"$out")" = "300" ] || fail "5h minutes" +[ "$(jq -r '.[0].usage.primary.resetDescription' <<<"$out")" = "5h" ] || fail "5h label" +[ "$(jq -r '.[0].usage.primary.usedPercent|floor' <<<"$out")" = "30" ] || fail "5h percent (4.20/14)" +[ "$(jq -r '.[0].usage.secondary.windowMinutes' <<<"$out")" = "10080" ] || fail "weekly minutes" +[ "$(jq -r '.[0].usage.secondary.resetDescription' <<<"$out")" = "weekly" ] || fail "weekly label" +# Literal $32.50 is a quoted string to compare against jq -r output. +# shellcheck disable=SC2016 +[ "$(jq -r '.[0].credits.remaining' <<<"$out")" = '$32.50' ] || fail "monthly USD credits" +[ "$(jq -r '.[0].usage.identity.accountEmail' <<<"$out")" = "Test User (test@example.com)" ] || fail "identity from whoami" + +# 2. No key set. +out="$(run env -u COMMAND_CODE_API_KEY)" +[ "$(jq -r '.[0].error.kind' <<<"$out")" = "provider" ] || fail "no-key error kind" + +# 3. Alpha billing 404 → fallback to /provider/v1/models. +# shellcheck disable=SC2016 +make_stub ' *provider/v1/models*) [ -n "$out" ] && cp "'"$ROOT"'/tests/fixtures/commandcode-models.json" "$out" ;;' +out="$(run env -u COMMAND_CODE_API_KEY COMMAND_CODE_API_KEY=user_test)" +[ "$(jq -r '.[0].source' <<<"$out")" = "commandcode-models" ] || fail "fallback source" + +echo "OK: test-commandcode" From b40b096197c5bad3b9c26cc7cb10e1c413e4aab6 Mon Sep 17 00:00:00 2001 From: Bernardo Pinto Gomes Date: Tue, 25 Aug 2026 17:49:48 -0300 Subject: [PATCH 2/2] =?UTF-8?q?fix(providers):=20complete=20Command=20Code?= =?UTF-8?q?=20wiring=20=E2=80=94=20auth=20header,=20logo,=20CI,=20settings?= =?UTF-8?q?=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-ups from the PR #21 review: - providers/get-provider-usage: send the real ${key} in the Authorization header — a literal 'Bearer ***' placeholder 401'd every live call. tests/test-commandcode.sh now logs and asserts the forwarded credential so the class of bug cannot regress - assets/provider-logos/commandcode.svg: official logomark silhouette from the commandcode.ai brand assets; background square dropped for runtime tinting (geometry unchanged), SOURCES.md provenance added — fixes the Metadata CI gate - AiOverviewControlSettings.qml: mode 'quota' -> 'telemetry' so the provider appears in the telemetry picker - .github/workflows/ci.yml: run tests/test-commandcode.sh in the integration-tests job - docs/configuration.md: COMMAND_CODE_API_KEY env-var table row - README: provider badge and copy 36 -> 37 - CHANGELOG: Unreleased entry crediting the contribution - trailing newlines at EOF for the stub and fixtures --- .github/workflows/ci.yml | 3 +++ AiOverviewControlSettings.qml | 2 +- CHANGELOG.md | 4 ++++ README.md | 4 ++-- assets/provider-logos/SOURCES.md | 1 + assets/provider-logos/commandcode.svg | 1 + docs/configuration.md | 1 + providers/get-commandcode-usage | 2 +- providers/get-provider-usage | 8 ++++---- tests/fixtures/commandcode-billing.json | 2 +- tests/fixtures/commandcode-models.json | 2 +- tests/fixtures/commandcode-subscriptions.json | 2 +- tests/fixtures/commandcode-whoami.json | 2 +- tests/test-commandcode.sh | 9 ++++++++- 14 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 assets/provider-logos/commandcode.svg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b52538d..f423cb4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -505,6 +505,9 @@ jobs: - name: Integration test — Kimi Code routing and quota fixture run: tests/test-kimi-code.sh + - name: Integration test — Command Code quota windows and fallback + run: tests/test-commandcode.sh + - name: Integration test — quota notification deduplication run: tests/test-quota-alert.sh diff --git a/AiOverviewControlSettings.qml b/AiOverviewControlSettings.qml index 2f88c37..1133ccb 100644 --- a/AiOverviewControlSettings.qml +++ b/AiOverviewControlSettings.qml @@ -269,7 +269,7 @@ PluginSettings { { id:"deepseek", name:"DeepSeek", icon:"search", mode:"telemetry", requirement:"API key", envVar:"DEEPSEEK_API_KEY", note:"Official account balance" }, { id:"kimi", name:"Kimi", icon:"language", mode:"telemetry", requirement:"API key", envVar:"MOONSHOT_API_KEY", note:"Account balance (USD/CNY), or Kimi Code subscription quota with a sk-kimi- key / KIMI_CODING_API_KEY" }, { id:"minimax", name:"MiniMax", icon:"bar_chart", mode:"telemetry", requirement:"API key", envVar:"MINIMAX_API_KEY", note:"Official models API authentication check" }, - { id:"commandcode", name:"Command Code", icon:"terminal", mode:"quota", requirement:"API key", envVar:"COMMAND_CODE_API_KEY", note:"Provider API key — same key used for the CLI and the Provider API. Reads /alpha/billing/credits for 5h/weekly/monthly quota; falls back to /provider/v1/models on alpha failure." }, + { id:"commandcode", name:"Command Code", icon:"terminal", mode:"telemetry", requirement:"API key", envVar:"COMMAND_CODE_API_KEY", note:"Provider API key — same key used for the CLI and the Provider API. Reads /alpha/billing/credits for 5h/weekly/monthly quota; falls back to /provider/v1/models on alpha failure." }, { id:"glm", name:"GLM", icon:"memory", mode:"telemetry", requirement:"API key", envVar:"GLM_API_KEY", note:"China (Zhipu) quota windows and plan; falls back to models authentication" }, { id:"zai", name:"Z.ai", icon:"bubble_chart", mode:"telemetry", requirement:"API key", envVar:"ZAI_API_KEY", note:"Official quota windows and plan; falls back to models authentication" }, { id:"mistral", name:"Mistral", icon:"wind_power", mode:"telemetry", requirement:"API key", envVar:"MISTRAL_API_KEY", note:"Official models API authentication check" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f50e80..7944dba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Command Code provider + +- New **Command Code** (commandcode.ai) provider surfaces the live 5-hour and weekly usage windows plus the monthly USD credit balance via the same Provider API key used for the CLI (`COMMAND_CODE_API_KEY`). The `/alpha/billing/` endpoints are experimental, so the adapter degrades to the documented `/provider/v1/models` auth-only check on alpha failure — never a fabricated percentage. Contributed by [@Luna161](https://github.com/Luna161) ([#20](https://github.com/bernardopg/AiOverviewControl/issues/20), [#21](https://github.com/bernardopg/AiOverviewControl/pull/21)). + ## 1.12.0 - 2026-08-22 ### Claude provider config directory override diff --git a/README.md b/README.md index 2f6a46c..ff6e5c6 100644 --- a/README.md +++ b/README.md @@ -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-36-7C4DFF)](./docs/providers.md) +[![Providers](https://img.shields.io/badge/providers-37-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) · @@ -48,7 +48,7 @@ it does not. No dashboard scraping. No fabricated percentages. Ever. | | | | --- | --- | -| 📊 **Unified dashboard** | 36 AI providers and developer tools in one place. | +| 📊 **Unified dashboard** | 37 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. | diff --git a/assets/provider-logos/SOURCES.md b/assets/provider-logos/SOURCES.md index fe64a37..4c3cfce 100644 --- a/assets/provider-logos/SOURCES.md +++ b/assets/provider-logos/SOURCES.md @@ -8,6 +8,7 @@ All marks are stored locally so the plugin never depends on a network request at - 9Router: [official `public/favicon.svg`](https://github.com/decolua/9router/blob/master/public/favicon.svg), MIT. - BytePlus Ark: [official BytePlus favicon](https://sf-bpcms.bytepluscdn.com/obj/byteplus-public-aiso/portal/assets/favicon.png), discovered from the ModelArk product page. - Warp: [Simple Icons `warp`](https://simpleicons.org/?q=warp), CC0-1.0, brand color `#01A4FF`. +- Command Code: official logomark from the [commandcode.ai brand assets](https://commandcode.ai/brand) ([`black-symbol-commandcode.svg`](https://github.com/CommandCodeAI/command-code/blob/main/.github/commandcode/symbols/black-symbol-commandcode.svg)). Normalized to a flat silhouette — the opaque background square is dropped and both symbol paths get a single `#000` fill — since the plugin re-tints the silhouette to the theme; geometry is unchanged. - GitHub Copilot: [Simple Icons `githubcopilot`](https://simpleicons.org/?q=githubcopilot), CC0-1.0. - pi: [official `logo-auto.svg`](https://pi.dev/logo-auto.svg) from [pi.dev](https://pi.dev/). Normalized to a single flat `fill` (the upstream `