fix(mac): accept Kimi Code Plan API keys - #1211
MiguelMachado-dev wants to merge 2 commits into
Conversation
Kimi's special settings path bypassed provider-scoped API credentials and required a short-lived CLI token. Save the Code Plan key in CodeBurn's Keychain item and prefer it for the existing usage endpoint, with the CLI token retained as fallback.
|
The |
ozymandiashh
left a comment
There was a problem hiding this comment.
Thanks. swift build passes on the branch and on a merge with current main (clean). Three blockers, one of which main already solved for another provider.
-
Disconnect no longer sticks. A saved Keychain key is now sufficient for background activation (
AppStore.swift:151-155) and the refresh guard acceptsCapacityDockProviderCredentialPresence.contains(...)(line 1277). ButdisconnectKimi()(1301-1309) neither deletes the key nor records an opt-out, anddisconnectCapacityDockProvider(.kimiCode)returns throughlegacyFilterbefore the credential remover runs. So the user hits Disconnect and the nextkimiDuetick reconnects, with the secret still in the Keychain. Main fixed exactly this for Copilot in9794e94e/94218bf1withCopilotExplicitDisconnect; Kimi needs the same persisted opt-out, plus the remover actually reachable from the dock's Disconnect. -
Keychain read has no fallback.
fetchKimiUsage()resolves the key throughloadAsyncinsideperformAsync(timeout: 2.5). On timeout it throwsCapacityDockProviderCredentialStoreError.timedOut, which is not aFetchError, so Kimi lands in.failedwith "Keychain did not respond" even when a working CLI credential is on disk. After the merge this is more reachable, not less: main'sda20fd0froutesPresence.setthroughDispatchQueue.main.sync, andload(for:)calls it on the same background read racing the deadline. On any credential-read failure fall back tofreshToken(deps:), or map the loader error into aFetchError. -
The description doesn't match the diff. There is no key-format validation anywhere; the endpoint is unchanged (
api.kimi.com/coding/v1/usages, as your own commit message says); and "30 new assertions" is one test with one assertion covering trim + bearer. The one protocol change that is in the diff, droppingX-Msh-Platform/X-Msh-Device-Idfor key auth, replaces a comment with its opposite and has no fixture. Please rewrite the body to describe what changed, and add tests forapiKeyRejected, the header suppression, the CLI fallback and the timeout path. You built aDependenciesDI seam but never wired it throughAppStore(deps: .live); main'sCopilotQuotaRuntimeis the pattern to follow so the store-level path is testable.
Separately: commit 2's "short window first" is a details.append(details.removeFirst()) rotation applied to every Kimi user including CLI-only ones, correct only for the two-window shape, and untested. Drop it from this PR.
The security side is fine: Keychain-only storage, SecureField, no logging, sanitizeForUI redacts the bearer.
iamtoruk
left a comment
There was a problem hiding this comment.
Rebased this on main to check status. All three earlier blockers are still open, no commits since Aug 31. Also, main added a localization coverage test since your last push (LocalizationCoverageTests), and this PR fails it: 8 new strings in SettingsView.swift are not wrapped in L(...), so a zh-Hans build shows English. Wrap them and add the keys to both en.lproj and zh-Hans.lproj.
Needed before this moves forward:
- Disconnect actually removing the Keychain key and sticking (see the CopilotExplicitDisconnect pattern)
- Keychain read falling back to the CLI token on timeout
deps: .livewired through AppStore, not just defined- Drop the window rotation change, or add a test and scope it to the two-window case
- Screenshots of the new Settings section, light and dark
- Confirm on your machine that the plain CLI-token path still works after this change
The description also needs to match the diff: there is no key-format validation, and it is one test, not thirty assertions.
Problem
The mac menubar rejects Kimi Code Plan API keys, so users on Kimi's flat-rate coding plan can't connect their quota to the Capacity Dock.
Fix
KimiSubscriptionService(key format validation + the quota endpoint that plan uses)Tests
KimiUsageParsingTestsextended (30 new assertions covering the Code Plan key path)