Skip to content

feat(kimi): add OAuth fallback + rename to Kimi for Coding#96

Merged
anthonybaldwin merged 11 commits into
mainfrom
feat/kimi-oauth-fallback
May 3, 2026
Merged

feat(kimi): add OAuth fallback + rename to Kimi for Coding#96
anthonybaldwin merged 11 commits into
mainfrom
feat/kimi-oauth-fallback

Conversation

@anthonybaldwin
Copy link
Copy Markdown
Owner

Summary

  • Renames the Stream Deck action and provider name Kimi → Kimi for Coding to clearly distinguish from Kimi K2 (single-model API key) and Moonshot (developer platform balance). UUID io.github.anthonybaldwin.UsageButtons.kimi and provider ID kimi are preserved so installed buttons keep working.
  • Adds an OAuth fallback: when the Helper extension isn't connected (or returns 401/403), the provider loads ~/.kimi/credentials/kimi-code.json (placed by kimi login), refreshes tokens against auth.kimi.com 5 minutes before expiry, and reads api.kimi.com/coding/v1/usages directly. Extension-first remains the preferred path.
  • Closes a coverage gap noted in the openusage comparison: openusage offers OAuth-only auth for Kimi for Coding; we now match while keeping the browser-cookie path primary.

Test plan

  • go vet ./..., golangci-lint run ./..., go test ./...
  • New unit tests cover credential parsing, 5-min refresh window, OAuth refresh round-trip, 401 surfacing, transient-failure leniency, OAuth envelope parsing
  • install-dev.sh --restart linked + restarted Stream Deck locally
  • Manual: confirm Property Inspector shows the updated Kimi for Coding label and the new OAuth hint
  • Manual: with the Helper extension disabled, confirm the OAuth fallback hits api.kimi.com/coding/v1/usages and surfaces session/weekly metrics

🤖 Generated with Claude Code

The existing kimi provider only ever fetched FEATURE_CODING data, so
the user-facing label "Kimi" was misleading vs. Kimi K2 (single-model
API key) and Moonshot (developer platform balance). Renames the
Stream Deck action and provider name to "Kimi for Coding" while
keeping UUID and provider ID stable so installed buttons keep working.

Adds an OAuth fallback that activates when the Helper extension isn't
connected (or returns 401/403): reads the credential blob written by
`kimi login` at ~/.kimi/credentials/kimi-code.json, refreshes against
auth.kimi.com within 5 min of expiry, and reads
api.kimi.com/coding/v1/usages directly. Mirrors openusage's flow.

Closes a coverage gap noted in the openusage comparison.

Claude <noreply@anthropic.com>
…t scopes

Windows-only. internal/wsl enumerates running WSL distros via wsl.exe -l -q
--running, decodes the UTF-16LE output, and resolves each distro's home
under \wsl.localhost\<distro>\home\. Native non-Windows builds get a
no-op stub.

Each distro becomes a separate "machine": its local Claude/Codex cost
scans emit cost-today-wsl-<key> and cost-30d-wsl-<key> metric IDs in
addition to the existing cost-today / cost-30d for Windows. The PI
fetches the running-distro list once on open and inserts matching
entries into the metric dropdown ("Cost today (WSL: Debian)"), so users
can dedicate one button per scope rather than silently summing them.

No UI surface on non-Windows builds; on Windows with no WSL the dropdown
is identical to before. wsl.exe is gated on exec.LookPath so the feature
lights up only when WSL is actually present.

Claude <noreply@anthropic.com>
Regular Claude usage (claude.ai) counts toward the same quotas this tile
shows, so labeling the action specifically as "Claude Code" was
misleading — users would expect a Code-only metric and instead see
combined consumer + Code activity. The provider already returns "Claude"
internally; this just aligns the Stream Deck action label, README, and
docs site to match.

No code paths changed. Action UUID stays
io.github.anthonybaldwin.UsageButtons.claude so existing buttons keep
working.

Claude <noreply@anthropic.com>
The kimi.com membership product is just called "Kimi" now — the "for
Coding" suffix was a sub-brand qualifier from when the membership only
covered Kimi Code. The same dashboard and quotas drive the whole Kimi
membership today (Moderato through Vivace tiers cover Kimi Code +
Slides + Websites + Agent Swarm, etc.), so labeling the action "Kimi
for Coding" both understates what the tile shows and contradicts the
official kimi.com naming.

Action UUID stays io.github.anthonybaldwin.UsageButtons.kimi so existing
buttons keep working.

Claude <noreply@anthropic.com>
…hird-party origin

The kimi-k2.ai endpoint we hit 308-redirects to kimrel.com, whose own
footer states it "is not affiliated with, endorsed by, or sponsored by
Moonshot AI." Branding it as "Kimi K2" in the action picker implied
official Moonshot data when it's actually a third-party reseller's
credit counter — which would only ever return data for users with a
kimrel.com account, not a Moonshot key.

This rename keeps the provider intact (still useful for kimrel.com
users) while making the user-facing copy honest about where the data
comes from. The official Moonshot dev platform is already covered by
the separate Moonshot provider, which calls api.moonshot.ai directly.

Renames:
- Go package internal/providers/kimik2/ → internal/providers/kimrel/
- Action display name "Kimi K2" → "Kimrel"
- Tooltip + auth UI hint + error messages now flag the third-party
  status and point Moonshot users at the right action
- Preferred env var KIMREL_API_KEY (older KIMI_K2_API_KEY etc. still
  resolve for backcompat)

Stable for backward compatibility:
- Provider ID stays "kimi-k2" (referenced in saved button settings)
- Action UUID stays io.github.anthonybaldwin.UsageButtons.kimi-k2
- Settings field KimiK2Key (json: kimiK2Key) is unchanged so existing
  saved API keys still resolve

Claude <noreply@anthropic.com>
Kimrel was inheriting Lobe's Kimi mark (via the auto-generated icon
mapping) and a #4c00ff purple accent that read as Moonshot/Kimi-family
branding — both implied affiliation Kimrel doesn't actually have.

Branding now:
- Custom internal/icons/kimrel.go registers a plain bold sans-serif "K"
  glyph for the kimi-k2 provider ID; the file name sorts after
  lobe_generated.go so its init wins and a future lobe sync can't
  re-clobber it.
- scripts/sync-lobe-icons.go drops the kimi-k2 entry so the generator
  doesn't keep emitting Kimi's mark.
- Action SVGs (action-kimi-k2.svg, action-kimi-k2-key.svg) and the
  docs site's provider-icons/kimi-k2.svg redrawn with the same plain
  K shape.
- Brand color #64748b (slate-500), brand bg #1e293b (slate-800).
  Avoids Kimi orange, Moonshot blue, and the prior K2-promotional
  purple.

Provider ID, action UUID, and settings field stay stable for backcompat.

Claude <noreply@anthropic.com>
…xied fetches

Kimi migrated off cookie-based auth — the kimi-auth JWT cookie is no
longer set on kimi.com, and the apiv2 BillingService endpoints reject
cookie-only requests with REASON_INVALID_AUTH_TOKEN. Verified by
fetching from inside the kimi.com page itself: cookies-only returns
401, while adding Authorization: Bearer <localStorage.access_token>
returns 200 with full FEATURE_CODING usage data.

Mirrors the existing readDeepSeekPlatformToken pattern: when the
proxied URL hits a kimi.com host, augmentHeadersForOrigin queries any
open kimi.com tab via chrome.scripting.executeScript (MAIN world),
reads localStorage["access_token"], and injects it as the
Authorization header. Falls through silently if no kimi.com tab is
open — the Go side's OAuth fallback (`kimi login` creds) still kicks
in for that case.

Bumps extension version 0.8.1 → 0.8.2. After installing, reload the
extension at chrome://extensions and restart Stream Deck to pick up
the new bridge connection.

Claude <noreply@anthropic.com>
release.yml owns the version bump for both manifests. Leaving 0.8.1
here so the next release cut increments cleanly off the previous
shipped value.

Claude <noreply@anthropic.com>
The Stream Deck plugin manifest is on 0.8.0; the extension had drifted
to 0.8.1. release.yml will keep them stepping together going forward.

Claude <noreply@anthropic.com>
The action-picker sidebar in Stream Deck and the docs site provider
pill were both using a generic Heroicons crescent moon path
("M21 12.79A9 9 0 1 1 11.21 3..."), not the Moonshot brand mark Lobe
ships under moonshot.svg. genkeys was skipping the menu file when one
already existed AND lacked moonshot in its color map, so the original
placeholder never got refreshed.

Replace both action-moonshot.svg and action-moonshot-key.svg (plus
docs/provider-icons/moonshot.svg) with the Moonshot Lobe path. Add
moonshot to genkeys/providerColors so future re-runs keep the asset in
sync, and tighten AGENTS.md to require lobe-icons as the source of
truth for new provider glyphs.

Claude <noreply@anthropic.com>
The Anthropic admin auth block introduced in cd93140 ended with two
closing </div> tags on the same line, which closed #providerPanel
before the OpenAI / DeepSeek / … blocks and the entire "Defaults for
<provider>'s buttons" override section. Browsers recover by attaching
the orphaned content as siblings, so the middle tab rendered as just
the first ~16 auth panels (anthropic and earlier) — Gemini, Kimi,
DeepSeek, Moonshot, Kimrel, OpenClaw, etc. all looked empty because
their auth panel was outside the active panel, and so was the entire
provider-tier override UI.

Removed the stray </div> after authConfig-anthropic; added the missing
</div> at the end of authConfig-openai.

Verified post-fix: 35 auth-config panels + 11 override rows + 5
inverse-checkbox rows + the "Defaults for …" heading are all inside
#providerPanel as designed.

Claude <noreply@anthropic.com>
@anthonybaldwin anthonybaldwin merged commit dddd60c into main May 3, 2026
2 checks passed
@anthonybaldwin anthonybaldwin deleted the feat/kimi-oauth-fallback branch May 3, 2026 19:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant