Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions cmd/plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,11 @@ var (
globalSettingsSeen bool

autoRegisterOnce sync.Once
// metricMigrationLogOnce gates the first-run summary log emitted
// when a saved button's metric ID is rewritten by metricIDAliases.
// One log per plugin launch is enough — subsequent migrations are
// silent.
metricMigrationLogOnce sync.Once
)

func globalSettingsLoaded() bool {
Expand Down Expand Up @@ -409,6 +414,24 @@ func handleWillAppear(conn *streamdeck.Connection, ev streamdeck.Event) {
}
}

// Stale metricID migration. Rewrites pinned KeySettings.MetricID
// when an alias maps it to a new ID — keeps reads consistent (the
// alias map handles read-side lookups too) but persists the new
// value so PI dropdowns and downstream tooling see the canonical
// name. Logs one summary on the first migration per plugin
// launch; subsequent rebinds stay silent.
if ks.MetricID != "" {
if migrated := migrateMetricID(providerID, ks.MetricID); migrated != ks.MetricID {
old := ks.MetricID
ks.MetricID = migrated
raw, _ := json.Marshal(ks)
conn.SetSettings(ev.Context, raw)
metricMigrationLogOnce.Do(func() {
conn.Logf("metricID migration: %s/%s → %s (rebinding stale buttons silently)", providerID, old, migrated)
})
}
}

// If an update is pending, show the update face.
if !settings.SkipUpdateCheckEnabled() && update.IsAvailable() {
now := time.Now()
Expand Down Expand Up @@ -1701,6 +1724,14 @@ var metricIDAliases = map[string]map[string]string{
"alibaba": {
"opus-percent": "monthly-percent",
},
// Mistral renamed "session-percent" → "monthly-cost" when it grew
// from a single MTD-cost metric to a 13-metric inventory in v0.9.
// The legacy ID was Claude-flavored and misled users into thinking
// it was a quota percent — the surfaced number was always raw EUR
// spend. See plans/mistral-tier-coverage.md.
"mistral": {
"session-percent": "monthly-cost",
},
}

// migrateMetricID returns the current metric ID for a (provider,
Expand Down
3 changes: 3 additions & 0 deletions cmd/plugin/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ func TestMigrateMetricID(t *testing.T) {
{"alibaba opus → monthly", "alibaba", "opus-percent", "monthly-percent"},
{"alibaba session unchanged", "alibaba", "session-percent", "session-percent"},
{"alibaba weekly unchanged", "alibaba", "weekly-percent", "weekly-percent"},
{"mistral session → monthly-cost", "mistral", "session-percent", "monthly-cost"},
{"mistral monthly-cost passthrough", "mistral", "monthly-cost", "monthly-cost"},
{"mistral weekly unchanged", "mistral", "weekly-percent", "weekly-percent"},
{"claude passthrough", "claude", "session-percent", "session-percent"},
{"claude opus passthrough", "claude", "weekly-opus-percent", "weekly-opus-percent"},
{"unknown provider passthrough", "unknown", "opus-percent", "opus-percent"},
Expand Down
2 changes: 1 addition & 1 deletion docs/PROVIDERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ account or API response includes that quota lane.
| Kimrel | Kimrel API key from the Provider tab or `KIMREL_API_KEY` (older `KIMI_K2_API_KEY` / `KIMI_API_KEY` / `KIMI_KEY` still resolve). Kimrel (kimrel.com, formerly kimi-k2.ai) is an **independent third-party reseller** of Kimi K2 model access — not affiliated with, endorsed by, or sponsored by Moonshot AI. Use the Moonshot provider for the official Moonshot dev platform. | Credits remaining. |
| Kiro | `kiro-cli`; run `kiro-cli login` first. | Monthly credits remaining %, bonus credits remaining %. |
| MiniMax | MiniMax API key from the Provider tab / `MINIMAX_API_KEY`, or Usage Buttons Helper from `minimax.io`. Optional region override: `MINIMAX_REGION`. | Coding prompts remaining %. |
| Mistral | Usage Buttons Helper from `admin.mistral.ai`. | Monthly billing usage. |
| Mistral | Usage Buttons Helper from `admin.mistral.ai`. | Monthly billing usage (total), per-category spend (completion / OCR / audio / connectors / RAG libraries / fine-tuning / Vibe), input / output / cached input tokens MTD, distinct completion models used, days until billing reset. Currency from response is preserved verbatim — typically EUR. |
| Moonshot (Kimi platform) | Moonshot API key from the Provider tab or `MOONSHOT_API_KEY` / `KIMI_PLATFORM_API_KEY`. Optional China-region host override: `MOONSHOT_API_HOST=https://api.moonshot.cn`. | Available balance ($), voucher balance ($), cash balance ($). Distinct from the Kimi provider (per-user CLI quotas) and Kimrel (third-party reseller credits) — Moonshot is the org-wide paid developer API balance. |
| Ollama | Usage Buttons Helper from the signed-in Ollama web session. | Session usage remaining %, session pace (burn rate), weekly usage remaining %, weekly pace (burn rate). |
| OpenAI | OpenAI admin API key (`sk-admin-…`) from the Provider tab or `OPENAI_ADMIN_API_KEY` (kept namespaced so it doesn't shadow the SDK-standard `OPENAI_API_KEY`). Org admins only — personal `sk-` keys are rejected by the admin endpoints. | Org spend today (UTC, $), yesterday ($), last 7 days ($), month-to-date ($), last 30 days ($), 7-day burn rate ($/day), projected month total ($). Distinct from the Codex provider (per-user session/weekly window from ChatGPT OAuth) — this is the org-wide cost view. |
Expand Down
Loading