feat: add Doubao Coding Plan usage#1841
Conversation
console.sakana.ai/billing always server-renders "Resets on <date>" in UTC (confirmed via the raw HTML's embedded "timeZone":"UTC" hydration payload marker, and Sakana's own "Weekly usage resets every Monday at 00:00 UTC" copy elsewhere on the page). The browser only corrects that text to the viewer's local timezone client-side, after JS hydration -- which this HTML-only fetcher never runs. SakanaUsageFetcher.parseResetDate parsed the raw string using TimeZone.current instead, so every non-UTC user got a reset time off by exactly their UTC offset -- 5.5h early on an IST machine, verified by building main into the codexbar CLI and running it against a real account: the tool's own JSON output landed 5.5h before the true reset instant shown in a browser on the same page at the same moment. Removes the timeZone parameter entirely (it no longer has a legitimate caller-supplied value; the source data is always UTC) and hardcodes UTC in parseResetDate. Updates the existing fixture-based tests, which previously asserted the buggy local-timezone interpretation as if it were correct, and adds a regression test pinned to a literal Unix timestamp independent of the date-building helper. Fixes #1826.
- The UTC regression test didn't actually pin the fix: on a UTC CI runner, the pre-fix TimeZone.current code would coincidentally still produce the correct instant, so the test would pass either way. Force NSTimeZone.default to UTC+14 for the test's duration (same pattern as BedrockUsageStatsTests) so it only passes when the parser genuinely ignores the device timezone. Verified by temporarily reverting the fix locally and confirming the test now fails with the expected 5.5h-off result before restoring it. - docs/sakana.md still said reset dates use the device's local time zone (TimeZone.current) -- exactly the behavior this PR removes. Updated to describe the actual UTC parsing and why, linking #1826.
clawsweeper's re-review flagged that the new NSTimeZone.default override test lives in a non-serialized suite, unlike the existing BedrockUsageStatsTests that uses the same pattern -- unrelated parallel Swift Testing cases could observe UTC+14 and fail nondeterministically. Mark @suite(.serialized), matching Bedrock's precedent exactly.
Move remaining provider UI copy through localization helpers and add Traditional Chinese translations. Preserve existing personal-info redaction behavior while localizing the visible placeholders and usage labels.
Keep stored OpenAI dashboard and Codex credits cached failure envelopes in English so CodexUIErrorMapper can parse the Cached values from marker. Add zh-Hant regression coverage for localized user-facing cached error messages.
Route the Claude Code sign-in menu label through localization and add English, zh-Hant, and strict-locale catalog entries. Add a zh-Hant regression test for the Claude account action.
Add the Claude Code sign-in label to localization catalogs covered by strict parity tests so CI passes after the menu action was localized.
CrossModel (https://crossmodel.ai) is a multi-provider, OpenAI- and Anthropic-compatible API aggregation platform billed against a prepaid USD wallet. This adds it as an API-key usage provider, modeled on the OpenRouter provider since the data shape is nearly identical (wallet balance + daily/weekly/monthly spend). Data source (two read-only endpoints, integer micro units): - GET /v1/credits -> balance_micro, uncollected_micro - GET /v1/usage -> daily/weekly/monthly cost_micro + tokens + counts Display: balance in the identity line (and optional menu bar), today/ this week/this month spend in the menu card, and a shared inline dashboard. No quota meter (prepaid wallet, no per-key limit). Auth: CROSSMODEL_API_KEY env var or Settings/CLI config. Base URL override via CROSSMODEL_API_URL (loopback HTTP allowed for local testing). Tests: CrossModelUsageStatsTests (decode, micro->USD, best-effort usage, 401, redaction, round-trip) and a ProviderConfigEnvironment regression covering Settings/CLI-saved keys.
CrossModel's balance lives in crossModelUsage, not the generic
credits path, so the fallback creditsHint text ("Wallet balance
from the CrossModel API") rendered as a misleading Credits row.
Suppress it the same way OpenRouter's balance-only card does.
Co-authored-by: LeoLin <leolin990405@gmail.com>
|
Codex review: found issues before merge. Reviewed July 2, 2026, 9:52 AM ET / 13:52 UTC. Summary Reproducibility: not applicable. as a bug reproduction: this is a feature PR for a new Doubao Coding Plan fetch path. The related PR discussion includes redacted live CodexBarCLI output showing the signed path rendering real Coding Plan windows. Review metrics: 3 noteworthy metrics.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Have a maintainer explicitly accept or reject the Doubao AK/SK credential path; if accepted, update Doubao docs and merge after required checks, leaving STS support as follow-up. Do we have a high-confidence way to reproduce the issue? Not applicable as a bug reproduction: this is a feature PR for a new Doubao Coding Plan fetch path. The related PR discussion includes redacted live CodexBarCLI output showing the signed path rendering real Coding Plan windows. Is this the best way to solve the issue? Technically yes: the implementation is focused on GetCodingPlanUsage, preserves Ark fallback, and has targeted compatibility tests. Product-wise it still needs maintainer acceptance of the AK/SK credential surface and a docs update. Full review comments:
Overall correctness: patch is correct AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 0a18391e1838. Label changesLabel justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
…-hardcoded-strings
…l-provider # Conflicts: # CHANGELOG.md # Sources/CodexBar/Resources/zh-Hant.lproj/Localizable.strings
…-plan # Conflicts: # CHANGELOG.md
…ing-plan # Conflicts: # CHANGELOG.md
|
Maintainer verification on exact head
This maintainer replacement preserves @LeoLin990405's co-author credit and changelog thanks because the original branch did not allow maintainer edits. Thanks for the contribution. |
…del/doubao-coding-plan conflicts) Second conflict resolution after upstream landed Doubao Coding Plan (steipete#1841), qoder, and crossmodel providers. Resolutions across the shared registration surfaces (Providers enum + IconStyle + cookie-import props, ProviderDescriptor, ProviderImplementationRegistry, UsageStore/CostUsageScanner switches, docs/configuration.md regenerated in enum order) keep all providers; longcat retained alongside qoder/crossmodel. CodexParserHash regenerated.
Recreates and improves #1727 on a maintainer-owned branch because the contributor branch does not allow maintainer edits.
Summary
GetCodingPlanUsageContributor commits are preserved through the commit's
Co-authored-bytrailer.Proof
swift test --filter 'Doubao|ProviderConfigEnvironmentTests|ConfigValidationTests'— 90/90 passedmake check— documentation links, locales, SwiftFormat, and SwiftLint passedmake test— all 45 shards passedLive authenticated proof and official CLI cross-check remain documented in #1727.