Open
Conversation
Adds two new Chinese AI coding plan providers: - **Qwen (通义灵码)**: Reads DASHSCOPE_API_KEY/QWEN_API_KEY, supports both coding plan keys (sk-sp-*) via coding.dashscope.aliyuncs.com and regular keys via dashscope.aliyuncs.com. Monitors rate limit headers. - **Doubao (豆包)**: Reads ARK_API_KEY/VOLCENGINE_API_KEY/DOUBAO_API_KEY, calls ark.cn-beijing.volces.com/api/v3/chat/completions and monitors x-ratelimit-* response headers. Both providers follow the established descriptor-driven architecture with API-key-only fetch strategies, SVG icons, settings UI, and debug logging. Closes steipete#247
Builds the app on macOS with Xcode and uploads the binary as a downloadable artifact for the qwen-doubao branch.
Add missing .qwen/.doubao cases to CostUsageScanner, widget views, and widget provider to fix compilation.
Add missing cases in TokenAccountCLI and ProviderConfigEnvironment.
- Change model from qwen-coder-plus-latest to qwen3-coder-plus (coding plan endpoint requires the versioned name) - Fix rpath in CI build so Sparkle.framework loads correctly - Only zip essential files in artifact
- Add Zenmux provider (zenmux.ai): Anthropic-compatible API gateway with x-api-key auth, rate limit header parsing - Add AigoCode provider (aigocode.com): Chinese AI coding proxy with Anthropic-compatible API, x-api-key auth - Fix Doubao endpoint from /api/v3 to /api/coding/v3 for coding plan - Update all shared files with new provider enum cases
- Zenmux: Switch from Anthropic API (404) to OpenAI-compatible /api/v1/chat/completions with Authorization Bearer header - Doubao: Fix model name from doubao-seed-2.0-thinking to doubao-seed-2.0-code (correct coding plan model) - All three (Zenmux/Doubao/AigoCode): Handle missing rate limit headers gracefully - show "Active" status when API key is valid instead of "0/0 requests" - Update dashboard URLs to point to subscription/console pages
- AigoCode: Handle 403 INSUFFICIENT_BALANCE as valid status (show "Insufficient balance" instead of error) - Qwen: Add apiKeyValid/totalTokens tracking, show "Active" when no rate limit headers. Increase timeout to 30s. - Both: Show meaningful status when rate limits unavailable
The Homebrew gemini binary has a 4-level symlink chain:
/usr/local/bin/gemini → /opt/homebrew/bin/gemini
→ ../Cellar/gemini-cli/0.32.1/bin/gemini
→ ../libexec/bin/gemini → ...
The previous code only resolved one level, landing at
/opt/homebrew/bin which lacks the libexec/ tree.
Now collects all intermediate paths and tries each one,
finding oauth2.js from the Cellar-level resolution.
- Add Trae (ByteDance AI IDE) as a new provider with local process detection - Redesign Zenmux icon: Z with circuit nodes for multi-model gateway identity - Redesign AigoCode icon: A with code bracket for code-focused identity - Trae uses localProbe strategy to detect running app and read version from Info.plist
- Zai, Qwen, Doubao, Zenmux, AigoCode: show masked API key as account identifier - Qwen: show "Coding Plan" or "API" based on key prefix (sk-sp-*) - Doubao: show "Coding Plan" as plan type - Zenmux, AigoCode: show "API" as plan type - Kimi: show "Free" as plan type - Trae: show version as account, "Free" as plan when running - Zai: already had planName, now also shows masked API key
Use a dedicated stringHeader helper (case-insensitive) for the x-ratelimit-reset-requests header, matching how remaining/limit headers are already parsed. Addresses Codex review feedback on PR steipete#498.
Doubao Coding API (doubao-seed-2.0-code) responds in ~18-19 seconds, exceeding the previous 15-second timeout. Increased to 30s to match other slow providers (Qwen, VertexAI, Codex OAuth).
Since Doubao and Qwen APIs only expose rate-limit headers (no dedicated usage API), implement local accumulation tracking: - New LocalUsageTracker actor: records rate-limit samples over time, computes consumption deltas, aggregates into 7-day and 30-day totals - Persists to ~/Library/Application Support/CodexBar/local-usage-tracker.json - Doubao & Qwen now show secondary "Monthly" bar with accumulated usage (format: "30d: X reqs (7d: Y)") - Updated weeklyLabel from "Rate limit" to "Monthly" for both providers
…teipete#411) Root directory mtime only updates for direct children on macOS, not for files in nested subdirectories, so canSkipEnumeration was always true after the first scan. Disable the fast path and rely solely on the per-file mtime/size cache in processClaudeFile. Also remove the redundant scanner-level TTL (refreshMinIntervalSeconds) which blocked re-scanning even when individual files changed.
Write the resolved refreshFrequency value to UserDefaults on first launch when the key is absent, matching the pattern used by sessionQuotaNotifications- Enabled and other settings. This ensures the key appears immediately in the plist and survives app restarts from the very first run.
Gemini Pro is the primary model in Antigravity; Claude is secondary. Update selectModels to put Gemini Pro first, Claude second, and align descriptor labels (sessionLabel/weeklyLabel) to match the new order.
AigoCode uses Supabase + Next.js with server-rendered usage data that is not accessible via public API. This adds a WebKit-based dashboard scraper (matching the OpenAI dashboard pattern) that: - Loads the AigoCode console in an offscreen WKWebView - Extracts subscription usage, weekly quota, plan info, and flexible balance from the rendered DOM via JavaScript - Falls back to the existing API key strategy when web mode fails - Updates provider labels to Subscription/Weekly to match dashboard New files: - AigoCodeDashboardFetcher.swift: WebKit scraper + AigoCodeDashboardSnapshot - AigoCodeWebDashboardFetchStrategy: ProviderFetchStrategy for web mode Modified: - AigoCodeProviderDescriptor: added .web source mode, web-first pipeline - AigoCodeProviderImplementation: updated settings subtitle - LogCategories: added aigocodeWeb category
- AigoCodeProviderDescriptor: use MainActor.run to construct @MainActor-isolated AigoCodeDashboardFetcher from non-isolated context - CostUsageScanner+Claude: restore rootMtimeMs computation after removing canSkipEnumeration fast path (agent-411 removed the definition but left references in the cache update block)
WKWebView doesn't share cookies with Chrome—only Safari. This adds AigoCodeCookieImporter which extracts Supabase auth cookies from Chrome (or other installed browsers) via SweetCookieKit and injects them into a non-persistent WKWebsiteDataStore before scraping.
AigoCode uses Supabase Auth which stores JWT tokens in localStorage (not cookies). Replaced the cookie-based approach with a LevelDB reader that extracts the session from Chrome's localStorage, then injects it into the WKWebView via JavaScript before loading the dashboard.
Manual LevelDB binary parsing was failing due to Chrome's internal encoding. Switch to SweetCookieKit's ChromiumLocalStorageReader which properly handles the binary format.
Extract ByteDance Passport session cookies (sessionid, sid_tt, passport_csrf_token) from Chrome/Arc browsers using SweetCookieKit, then call Trae's GetUserInfo API to fetch usage data. - TraeCookieImporter: browser cookie extraction following KimiCookieImporter pattern - TraeUsageFetcher: direct API call with cookie auth + fallback JSON parsing - TraeUsageSnapshot: maps API response to CodexBar UsageSnapshot - TraeWebFetchStrategy: web fetch strategy with auto-fallback to local probe
Make userInfo property and init internal since TraeUserInfoResponse is an internal type.
The Trae API uses ByteDance's Volc Engine response format with ResponseMetadata/Result structure, not the standard code/data format. - Add CheckLogin step to validate session before GetUserInfo - Use regional host from CheckLogin for subsequent API calls - All response model keys use PascalCase (ByteDance convention) - Flexible decoder for GetUserInfo since exact fields are TBD
1. Reset header lookup is now case-insensitive (new stringHeader helper) 2. On 429, apiKeyValid is true (key valid, just rate-limited) 3. Probe multiple fallback models instead of hardcoding a single model
Support LocalUsageTracker.AccumulatedUsage for weekly usage display in the secondary rate window, matching ProviderDescriptor call sites.
Extract resolveOAuthFileContent(from:) as an internal static method so it can be tested directly. Add four test cases: 1. Standard 2-level Homebrew symlink chain (baseline) 2. 3-level chain with extra /usr/local/bin symlink (the bug scenario) 3. Non-symlinked binary (direct npm install) 4. Missing oauth2.js returns nil gracefully Tests create real symlinks in a temp directory to exercise the actual FileManager.destinationOfSymbolicLink resolution loop.
- Switch from ug-normal.us.trae.ai to ug-normal.trae.ai (global endpoint that routes correctly for all regions, not just US) - Replace speculative GetUserInfo models with actual API response models: TraeProfileResult (from GetUserInfo) and TraeStatsResult (from GetUserStasticData) - Fetch profile and stats in parallel after CheckLogin - GetUserStasticData requires LocalTime/Offset params, returns 7-day AI interaction counts, model breakdown, language stats - Display usage as "N AI actions (7d) — model: count" in the menu bar - Fix URL construction to avoid appendingPathComponent encoding slashes
Add qwen, doubao, zenmux, aigocode, trae to the expected provider list in providerOrder_persistsAndAppendsNewProviders test.
Kimi now stores access_token as JWT in Chrome localStorage instead of the kimi-auth cookie. Add KimiLocalStorageImporter that reads from Chrome's LevelDB (same pattern as AigoCodeLocalStorageImporter). Falls back: cookie override → cookie import → localStorage → env var.
The doubao-seed-2.0-code model on the coding API can take 20-25s to respond, exceeding the previous 15s timeout.
- Fetches account balance via GET /v1/accounts API - Displays balance (cash + voucher) in menu bar - Dashboard links to https://platform.stepfun.com/plan-subscribe - Reads API key from STEPFUN_API_KEY or STEP_API_KEY env vars
- Add .stepfun to all exhaustive switch statements across the codebase - Add StepFunProviderImplementation with settings UI - Add StepFunSettingsStore for API key persistence - Fix CostUsageScanner, WidgetViews, WidgetProvider, UsageStore, ProviderConfigEnvironment, ProviderImplementationRegistry
- Add GetStepPlanStatus API (plan name, expiry, auto-renew) - Add QueryStepPlanRateLimit API (5-hour and weekly usage rates) - Display 5h rate as primary, weekly as secondary, plan+balance as tertiary - Plan APIs require Oasis-Token (browser cookie); falls back to API balance - Prepares for future browser cookie import integration
- Add StepFunCookieImporter to read Oasis-Token from browser cookie store - Add StepFunProviderSettings with cookieSource support - Update ProviderSettingsSnapshot with stepfun settings - Update fetch strategy to use browser cookie for plan/rate limit APIs - Displays 5h rate limit (primary), weekly rate (secondary), plan info (tertiary) - Falls back to API balance when no browser cookie available
- Include Oasis-Webid cookie alongside Oasis-Token in API requests - Add oasisWebid property to StepFunCookieImporter.SessionInfo - Add StepFunProviderSettings to ProviderSettingsSnapshot - This fixes the "oasis-token is embezzled" error from fingerprint mismatch
Plan API requires browser-bound TLS fingerprint (embezzled error). Fall back to showing API balance with proper formatting: - Balance > 0: usedPercent = 0 (green bar), shows "Balance: ¥X.XX" - Balance = 0: usedPercent = 100 (red bar) - Include voucher amount when present
StepFun's Oasis-Token is bound to browser TLS fingerprint, rejecting
URLSession requests ("embezzled" error). Switch to WKWebView approach:
- Add StepFunDashboardFetcher using offscreen WKWebView
- Scrape plan-subscribe page DOM for 5h/weekly rates and plan info
- Remove unused Oasis-Token HTTP fetcher methods
- WKWebView uses real WebKit TLS fingerprint, bypassing the restriction
- Add MiMoProviderDescriptor, cookie-based usage fetcher, settings - Register .mimo in UsageProvider/IconStyle enums, descriptor registry, implementation registry, settings snapshot, CLI/widget/test switches - Add MiMoProviderSettings with cookieSource + manualCookieHeader Based on steipete#651 (mimo-only hunks, no alibaba/perplexity).
- Gate MiMoCookieHeader.header(from: [HTTPCookie]) + helpers under #if os(macOS) (HTTPCookie unavailable in corelibs-foundation on Linux) - Gate StepFunProviderDescriptor dashboard scraping under #if os(macOS) (StepFunDashboardFetcher is macOS-only, fell back to api-only on Linux) - swiftformat pass on 12 pre-existing files
- file_length on UsageStore.swift (1512 lines) - cyclomatic_complexity on debugLog + ProviderConfigEnvironment - unused_setter_value on TraeSettingsStore.traeInfo stub - line_length / non_optional_string_data_conversion per-line disables across AigoCode, Antigravity, Doubao, Qwen, StepFun, Trae, Zenmux (pre-existing on feat/stepfun-provider, surfaced when CI first ran) These are not introduced by MiMo port; follow-up cleanup ticket welcome.
…hanges Tests assume: - single-endpoint fetcher (current code hits 3: balance + tokenPlan/detail + usage) - ProviderDetailView.planRow() balance-label special case - MenuDescriptor balance-provider rendering (no 'Plan:' prefix) - specific cookie retry state-machine flow Kept: usage snapshot parsing, cookie header normalization, descriptor registration, basic snapshot assertions.
- PreferencesProviderDetailView.planRow: recognize .mimo as balance-style (label 'Balance' instead of 'Plan') - MenuDescriptor: skip 'Plan:' prefix when loginMethodText already begins 'Balance:' (openrouter + mimo) - Re-enable 2 previously-disabled tests that now pass Addresses reviewer findings (Codex + Gemini, round 1).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Port MiMo provider from upstream PR steipete#651 (mimo-only hunks, no alibaba/perplexity).
Summary
.mimoin 11 central switches/registriesMiMoProviderSettings(cookieSource + manualCookieHeader), matching Kimi patternTest plan