132 Commits

Author SHA1 Message Date
Peter Urda 099bf56f71 Add per-provider accent color override
Every provider settings card gets an accent color row: swatch, hex field, color well,
and a reset shown only when an override exists. Descriptor colors stay compile-time constants,
so a reset restores the shipped color.

Overrides persist as ProviderConfig.accentColor in ~/.codexbar/config.json,
which reaches the app and the codexbar serve dashboard, and mirror
into App Group defaults for the widget, which cannot read that file.
Overrides sync across Macs via ProviderIntentPayload.

Translations for the 22 non-English catalogs are machine-generated and want a native-speaker pass.
2026-08-16 01:12:30 -07:00
Peter Steinberger 46a7a7f10e fix: make widget background removable 2026-08-14 19:23:12 -07:00
Peter Steinberger 4cdb349cbc test: harden the provider special-case gatekeeper and derive its findings (#2693)
* test: harden provider architecture gatekeeper

* refactor: derive provider presentation policies

* test: pin provider dispatch constructs

* test: document gatekeeper catalog lint scope

---------

Co-authored-by: Peter Steinberger <steipete@clawstudio.local>
2026-08-05 18:41:45 -07:00
Peter Steinberger 61fbe9fac5 refactor: derive or justify every remaining provider special case (#2691)
* refactor: derive settings provider special cases

* refactor: justify usage store provider state

* refactor: derive controller provider policy

* refactor: derive cli provider capabilities

* refactor: justify scanner provider ownership

* test: gate provider special case clusters

* build: refresh codex parser hash

* style: satisfy special case gate lint

* style: accept cli cards command size

---------

Co-authored-by: Peter Steinberger <steipete@clawstudio.local>
2026-08-05 17:18:44 -07:00
Peter Steinberger fb66e63e87 refactor: move usage presentation policy into provider descriptors (#2688)
* test: pin provider presentation policy

* refactor: move usage window policy into descriptors

* refactor: move usage menu policy into descriptors

---------

Co-authored-by: Peter Steinberger <steipete@clawstudio.local>
2026-08-05 16:04:53 -07:00
Peter Steinberger 45793d72c4 refactor: derive the remaining per-provider bookkeeping from descriptors (#2682)
* refactor: derive widget colors from provider branding

* refactor: generate provider manifests from one registry

* refactor: colocate provider cookie import priorities

* refactor: move share plan labels into descriptors

* refactor: move debug defaults into provider descriptors

* refactor: derive debug pane provider curation

* refactor: derive provider presentation capabilities

* refactor: unify standard provider config bindings

* style: remove stale lint suppression

* fix: use grep instead of rg in manifest regeneration script

CI lint runners do not have ripgrep; grep -rlE --include is portable and
matches the same files.

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-05 12:32:33 -07:00
Peter Steinberger 15a855a213 refactor: introduce ProviderInstanceID identity seam (#2636)
* test: characterize provider instance identity

* feat: add provider instance identity seam

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-03 21:36:49 -07:00
Peter Steinberger 7002b57820 feat: add China Kimi and GLM quota routing (#2621)
Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
Co-authored-by: haoli <haoli@local.dev>
2026-08-03 13:51:17 -07:00
Peter Steinberger cafb2094dd fix: make widget ProviderChoice display metadata a static literal
The AppIntents metadata processor in current Xcode rejects computed
caseDisplayRepresentations (must be a literal, exhaustive dictionary),
which broke the 0.47.0 release build. Titles are pinned to the
descriptor registry by WidgetProviderChoiceTests so providers cannot
drift silently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 09:43:55 -07:00
n0ah37 8393fc89bd Add Notion AI provider (#2552)
* Add Notion AI provider

Tracks the two usage-allowance windows Notion shows in Settings > Notion AI >
Usage: the rolling 6-hour window and the billing-period window. Notion begins
enforcing the allowance on 2026-08-03; before then the same endpoint already
returns real numbers with "enforcement": "preview".

Reads two cookie-authenticated endpoints on app.notion.com that the Notion web
app itself calls: getSpaces for account identity and workspace plans, and
getCreditRateLimitStatus for the allowance. Only Business and Enterprise
workspaces carry one; anything else reports not_applicable as a clear error
rather than an empty gauge.

The imported cookie header is persisted through CookieHeaderCache. Chromium
cookie reads are gated to user-initiated refreshes to avoid a Keychain prompt,
so without a cached header the provider fails on every background refresh and
reports "no cookies found" while the session is valid. Cookies are also
de-duplicated by name across the Notion domains, since a stale token_v2 left on
the legacy notion.so alongside the live one would otherwise send both.

Every field of the rate-limit response is optional, so an unrelated 200 body
decodes cleanly into an all-nil status. The parser rejects a payload carrying
neither window, and a window with no usable limit is omitted rather than
reported as 0% used.

Adding the .notion debug-log case tipped UsageStore.debugLogText past the
cyclomatic-complexity cap, so .openai and .azureopenai are folded into one case;
both already call the same apiKeyDebugLine helper.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(notion): harden cookie session handling

* test: isolate widget snapshot persistence

* feat(notion): pace both allowance bars and honor CLI provider settings

The billing-period window is scored against the real calendar month ending
at its reset rather than a flat 30 days, and the rolling window gets the
session-pace treatment on both the card and in `codexbar usage`.

Notion reports only `periodEndMs` for the billing period, so the snapshot
carries the shared monthly sentinel and the descriptor declares
`.calendarMonthResetWindow`. Resolution then substitutes the true cycle
length. Three paths scored these windows without resolving first --
`UsageStore.weeklyPace` (menu-bar pace token, "runs out" text, predictive
pace warnings) and `resetWindowPaceDetail` when handed a precomputed pace
-- so a February cycle read 6% expected at 0% used and a 31-day cycle lost
its pace token for a day. Both now resolve, which also fixes the eight
other providers that carry the same sentinel.

The CLI ignored the Notion settings snapshot entirely, so Workspace ID, a
manual cookie header, and the `off` source had no effect on `codexbar`.

Also drops a rolling window length that parses to exactly the monthly
sentinel (`30d`, `720h`, `43200m`), which would otherwise be resolved as a
calendar cycle ending hours from now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-03 09:14:33 -07:00
Peter Steinberger a557d0229f refactor: derive provider registrations from descriptors (#2606)
* refactor: consolidate provider bootstrap manifests

* refactor: derive provider icon styles from descriptors

* refactor: derive provider ancillary registrations

* refactor: derive widget provider metadata

* test: enforce provider widget metadata sync

* docs: simplify provider authoring workflow

---------

Co-authored-by: Peter Steinberger <steipete@mac-studio-sf2.local>
2026-08-03 01:53:46 -07:00
SilentKnight87 1196987c4d feat: add xAI platform billing provider
Add a separate xai provider for xAI developer-platform billing from the
documented Management API (management key + team ID): prepaid credit
balance from /prepaid/balance (inverted ledger in string USD cents; a
200 without a parseable total is an error, never $0.00) and a 30-day
daily USD spend dashboard from /usage via the shared cost-history seam.
History is best-effort enrichment - its failure keeps the balance while
auth failures and cancellation escalate - and limitReached marks the
window "(partial)" with estimated confidence instead of exact. No
coupling to the Grok subscription provider. Covers descriptor, fetcher,
settings reader/store, registries, config projection, widget and CLI
switches, template icon with a Grok-distinctness test, docs, and
fixture-based tests on stubbed transports. Moves ProviderIdentitySnapshot
to its own file to hold the UsageFetcher length limit. (#1712)
2026-07-29 09:01:36 -07:00
Peter Steinberger 84d6b6f410 Merge main; union provider list, regenerate parser hash 2026-07-28 22:29:44 -07:00
Peter Steinberger bc8f33e595 Merge pull request #2354 from jarvisluk/fix/widget-vibrant-background
fix(widget): remove unintended dark background overlay
2026-07-28 20:28:44 -04:00
Peter Steinberger 8c4a346023 Merge remote-tracking branch 'origin/main' into codex/zoommate-2344 2026-07-28 14:08:59 -07:00
Peter Steinberger 650b998dec Merge branch 'main' into fix/widget-vibrant-background 2026-07-28 16:02:46 -04:00
Peter Steinberger 7d1d43deec Merge remote-tracking branch 'origin/main' into codex/pr-2361-repair
# Conflicts:
#	CHANGELOG.md
2026-07-28 00:13:43 -07:00
Umut Keltek df23669454 feat(providers): add Qwen Cloud individual token-plan provider
Add a fully-wired "Qwen Cloud" provider that tracks the individual token
plan subscription on https://home.qwencloud.com/billing/subscription/token-plan-individual
(the plan that grants hosted Claude access), alongside all existing settings.

Qwen Cloud shares the Aliyun one-console auth + BssOpenAPI gateway used by
the Alibaba token plan, so it reuses that parser/cookie plumbing:

- New provider `.qwencloud` (CLI name `qwen-cloud`, aliases qwencloud/qwen/
  qwen-token-plan) with descriptor, web fetch strategy, monochrome icon, and
  a curated confetti palette.
- QwenCloudUsageFetcher posts form-encoded GetSubscriptionSummary
  (BssOpenAPI-V3, productCode sfm_tokenplansolo_public_intl) after resolving
  sec_token from the dashboard HTML, the sec_token cookie, or /tool/user/info.json.
- URL-scoped cookie headers for qwencloud.com plus a browser cookie importer
  over the qwencloud/alibabacloud/aliyun passport domains.
- Settings UI (cookie source picker + manual Cookie header + "Open Token Plan"
  link), CLI (`codexbar usage --provider qwen-cloud`), diagnostics, widget,
  and docs (docs/qwen-cloud.md, README, providers.md, configuration.md).
- Generalized AlibabaCodingPlanCookieImporter.importSession to accept a
  provider-specific domain list + session validator so Qwen Cloud can reuse it;
  the existing Alibaba behavior is unchanged (delegates with its own defaults).
- Extended the Alibaba token-plan parser to read nested EquityList quota fields
  (CycleTotalValue/CycleSurplusValue/EndTime) without changing existing results.

Tests: parser/snapshot/cookie-header/stub-fetch/import-validation suites plus
an opt-in live smoke test (disabled by default; gated on QWEN_CLOUD_LIVE_TEST=1
and QWEN_CLOUD_COOKIE) so CI never touches the network or Keychain.
2026-07-21 19:25:37 +03:00
Yuxin Qiao 83b6b91f05 Prevent WidgetKit reload loop in BurnDownRefreshSchedule 2026-07-21 17:35:57 +08:00
junrong 4f11751a49 fix(widget): remove unintended dark overlay 2026-07-20 14:18:03 +08:00
Ryan Weddle 264ba395cd Add ZoomMate usage provider 2026-07-19 13:32:18 -04:00
Peter Steinberger d2e068b6e2 fix: keep widget cost rows compact 2026-07-19 15:42:31 +01:00
Peter Steinberger 6e82f86fb8 chore: merge main into DeepInfra provider 2026-07-17 22:11:46 +01:00
Peter Steinberger 5ac0d7fb7f Merge remote-tracking branch 'origin/main' into codex/deepinfra-provider
# Conflicts:
#	Sources/CodexBar/MenuCardView.swift
#	Sources/CodexBar/MenuDescriptor.swift
#	Sources/CodexBar/SettingsStore+MenuPreferences.swift
#	Sources/CodexBar/UsageStore.swift
#	Sources/CodexBarCore/Config/ProviderConfigEnvironment.swift
#	Sources/CodexBarCore/Generated/CodexParserHash.generated.swift
#	Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift
#	docs/cli.md
2026-07-17 20:11:47 +01:00
Jetha Chan 324d9fa072 feat: add ai& spend provider
Sum 30-day organization spend from ai&'s documented request-log API with
an org-scoped API key (AIAND_API_KEY or ~/.codexbar/config.json), parsing
per-request cost strings as exact decimals in the org's billing currency
and following dual-cursor pagination capped at 10 pages (capped totals
are labeled partial, never silently truncated). ai& is prepaid with no
quota windows, so the snapshot carries only the cost figure and no rate
windows. Covers descriptor, fetcher, settings reader/store, registries,
widget and CLI switches, provider icon, and fixture-based tests.
2026-07-18 01:48:18 +09:00
Peter Steinberger 0ececf11c3 Merge remote-tracking branch 'origin/main' into codex/neuralwatt-provider
# Conflicts:
#	README.md
#	Sources/CodexBar/Providers/Shared/ProviderImplementationRegistry.swift
#	Sources/CodexBarCore/Config/ProviderConfigEnvironment.swift
#	Sources/CodexBarCore/Generated/CodexParserHash.generated.swift
#	Sources/CodexBarCore/Providers/ProviderDescriptor.swift
#	Sources/CodexBarCore/Providers/Providers.swift
#	Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift
#	Tests/CodexBarTests/CLIDiagnoseCommandTests.swift
#	Tests/CodexBarTests/ProviderSettingsDescriptorTests.swift
#	docs/configuration.md
#	docs/index.html
#	docs/llms.txt
#	docs/providers.md
#	docs/site-locales.mjs
#	docs/social.html
#	docs/social.png
2026-07-17 08:52:07 +01:00
Peter Steinberger 54cfd1a3f5 chore: retire unverified provider relays 2026-07-17 06:19:00 +01:00
Peter Steinberger 7f1e539dcb Merge remote-tracking branch 'origin/main' into codex/neuralwatt-provider
# Conflicts:
#	README.md
#	Sources/CodexBar/UsageStore.swift
#	Sources/CodexBarCore/Generated/CodexParserHash.generated.swift
#	Sources/CodexBarCore/Vendored/CostUsage/CostUsageScanner.swift
#	docs/configuration.md
#	docs/index.html
#	docs/llms.txt
#	docs/providers.md
#	docs/site-locales.mjs
#	docs/social.html
2026-07-17 05:38:41 +01:00
Peter Steinberger 60e5f61064 feat: add LongCat usage provider 2026-07-17 03:33:40 +01:00
Peter Steinberger 3abb077705 Merge remote-tracking branch 'origin/main' into codex/clinepass-provider
# Conflicts:
#	Sources/CodexBarCore/Generated/CodexParserHash.generated.swift
2026-07-17 01:40:02 +01:00
Bill Erickson c83073139e Add DeepInfra usage provider 2026-07-16 16:33:14 -05:00
Peter Steinberger e5d2b76c9c Merge remote-tracking branch 'origin/main' into fix/codex-api-estimate-disclosure
# Conflicts:
#	Sources/CodexBar/InlineUsageDashboardContent.swift
2026-07-16 22:26:57 +01:00
Peter Steinberger 96363a7f57 fix: disclose cached Codex widget estimates 2026-07-16 19:00:52 +01:00
Yuxin Qiao 09f0fbec0b fix: complete Codex estimate compatibility labels 2026-07-16 20:17:04 +08:00
jrimmer 479e12846e Add Neuralwatt provider 2026-07-16 13:03:09 +01:00
Derek Zeng 3cb9d0d995 Add ClinePass usage provider 2026-07-16 12:58:47 +01:00
Kevin Peng 59c0813320 feat: add ZenMux Management API usage (#2133)
Co-authored-by: kays0x <48529172+kays0x@users.noreply.github.com>
2026-07-16 02:58:08 -07:00
Yuxin Qiao 288e82360d fix: finish Codex estimate disclosure surfaces 2026-07-16 17:47:38 +08:00
Yuxin Qiao 49212f8cde fix: preserve Codex estimate disclosure in widgets 2026-07-16 17:44:36 +08:00
Yuxin-Qiao 88c0d36d74 Complete Codex estimate disclosure surfaces 2026-07-16 17:44:35 +08:00
weirdo-adam bf92f4ab8f Add sub2api provider support 2026-07-11 15:27:09 +08:00
Zihao Qi 4bf9c2cfe6 Add Cursor and filter widget provider options (#2042)
* Add Cursor widget provider options

* Label legacy Cursor widget quota as Requests

Match the menu bar label for request-based Cursor plans so widgets do not show Total for that quota.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: ignore stale widget providers

* fix: narrow Cursor widget support

---------

Co-authored-by: Zihaoqi <Zihao-Qi@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-10 23:48:16 -07:00
Tom Ballard 6db1876c9e Add Wayfinder app integration (settings pane, icon, menu and CLI lines) 2026-07-09 05:58:02 -07:00
Jaehwan Lee 6907328791 fix: Give widget token rows their own updated time instead of inheriting snapshot freshness (#1967)
* fix: give widget token rows their own age instead of inheriting snapshot freshness

Token-cost rows refresh on a slower cadence than quota rows, so a fresh
widget snapshot could present hour-old token data as current
(steipete/CodexBar#1964). Persist a token-specific updatedAt on
WidgetSnapshot.TokenUsageSummary, suffix widget row titles with the token
snapshot's own age once it lags the entry's freshness signal past ten
minutes, and clear the token-fetch TTL on fast failures so the next
scheduled pass retries instead of serving stale rows for the rest of the
TTL. Legacy snapshots without the new field decode as fresh.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: cover stale token age across widgets

* fix: keep cached codex scan time as token snapshot updatedAt

Hydrating from the persisted codex scan cache rebuilt the token snapshot
with the hydration time as updatedAt while returning the real cache scan
time separately, so a stale cached token row could inherit app-start
freshness and skip the widget's stale-age suffix for the rest of the
fetch TTL. Cached snapshots now carry the cache's lastScan time; paths
without a known scan time keep the previous behavior.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix: keep the oldest cache scan time when cached pi sessions merge

Merged cached codex snapshots dropped the known scan times entirely, so
a hydrated snapshot that included cached pi sessions fell back to the
hydration time as updatedAt. Expose the pi cache's lastScan time and use
the oldest constituent scan as the merged snapshot's updatedAt, while
keeping TTL bookkeeping native-only so merged loads never suppress a
pending rescan.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor: clarify widget freshness summary

* test: strengthen widget freshness coverage

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 07:34:51 +01:00
LeoLin 39b5b5af1c Merge upstream/main; isolate LongCat transport (cookie-free ephemeral session)
Third conflict resolution (clawrouter + earlier crossmodel/qoder landings) across the
shared registration surfaces; docs regenerated in enum order, CodexParserHash regenerated.

Address the ClawSweeper P1 patch-quality finding: LongCat fetches now run on an isolated,
ephemeral, cookie-free ProviderHTTPClient (httpCookieStorage = nil, httpShouldSetCookies =
false) so the console's Set-Cookie responses never enter the shared provider cookie jar; auth
is carried solely by the explicit request Cookie header. Mirrors the Sakana provider.
2026-07-07 17:15:58 +08:00
Yuxin Qiao ff1c6c70a6 Cap Codex session display when weekly quota is exhausted (#1930)
* Cap Codex session display when weekly quota is exhausted.

When the weekly lane is the binding cap, show 0% session remaining and the weekly reset time so the menu card and menu bar do not imply usable 5-hour quota.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Address weekly-cap review feedback for Codex session display.

Retarget the session reset whenever the weekly cap is active, omit the 5h reset when weekly reset metadata is missing, and evaluate cap expiry against render time.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: cap Codex session by weekly quota

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: refresh Codex fallbacks after resets

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: ignore expired Codex limits in menu bar

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: hide expired Codex quota lanes

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: observe merged Codex reset transitions

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: exclude weekly-capped Codex from ranking

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: preserve later Codex quota reset

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* fix: project legacy Codex widget quotas

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

* test: split legacy Codex widget regression

Co-authored-by: Yuxin Qiao <104957188+Yuxin-Qiao@users.noreply.github.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 09:31:44 +01:00
JoeVenner 76a63dc559 Add Kimi widget support (#1918)
Co-authored-by: JoeVenner <ylafrimi@gmail.com>
2026-07-06 05:36:23 +01:00
FND f1de700602 feat: add cost chart scale labels (#1898)
Add compact cost scale labels to detailed history charts, inline usage bars, and widgets. Keep labels truthful to the plotted domain, reserve layout space to avoid peak-bar overlap, and use consistent currency formatting across surfaces.

Co-authored-by: FND <fndevve@proton.me>
2026-07-05 01:11:55 -04:00
FND 37e42252c3 Add Devin extra usage balance
Add and validate Devin extra-usage balances across menus, CLI, widgets, and snapshots.

Co-authored-by: FND <fndevve@proton.me>
2026-07-04 23:34:04 -04:00
JoeVenner 4f281ab3d8 Add Mistral widget support (#1891) 2026-07-04 20:39:22 -04:00