providers

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 3, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Active-metric registry: tracks which (provider, metric) pairs have at least one Stream Deck button currently bound to them, with a short grace window so a profile-switch (which fires willDisappear → willAppear in rapid succession) doesn't flap the fetch shape between two adjacent polls.

The cache layer reads ActiveFor(providerID) and threads the result into FetchContext.ActiveMetricIDs so multi-endpoint providers can skip work whose results aren't displayed anywhere.

Package providers defines the provider interface, snapshot types, and the provider registry.

Index

Constants

View Source
const (
	// MinTTL matches the shortest user-selectable poll interval.
	// Any poll within this window reuses the snapshot.
	MinTTL = 5 * time.Minute

	// TransientTTL caps how long a snapshot in a self-resolving
	// state (pairing-pending, bot-blocked) is reused before re-fetch.
	// Short enough that a user who just approved a device pairing or
	// cleared a CAPTCHA in their browser sees the state flip without
	// having to press the Stream Deck button — long enough that we
	// don't hammer the upstream during a stuck transient period.
	TransientTTL = 30 * time.Second

	// CooldownDuration is how long to stop hitting an API after an
	// upstream error.
	CooldownDuration = 10 * time.Minute

	// ManualCooldown is the minimum gap between user-initiated
	// (force=true) refreshes per provider. Prevents button-mashing from
	// hammering upstream APIs. 30s is responsive enough for deliberate
	// retries but limits a frustrated user to ~2 req/min.
	ManualCooldown = 30 * time.Second

	// StaleTTL is how long missing metrics are preserved from a previous
	// snapshot. After this window a permanently failed sub-fetch (e.g.
	// expired cookie) stops carrying forward stale data so the button
	// can show a setup/error state instead.
	StaleTTL = 30 * time.Minute

	// PersistentTTL bounds how long a snapshot survives process restarts.
	// This smooths normal Stream Deck / computer restarts without showing
	// week-old usage after a long absence.
	PersistentTTL = 24 * time.Hour
)

Variables

View Source
var ActiveGracePeriod = 30 * time.Second

ActiveGracePeriod is how long a (provider, metric) pair lingers in the active set after its MarkInactive call. Sized to absorb a Stream Deck profile switch (which fires willDisappear immediately followed by willAppear from the new profile) so the next poll's FetchContext.ActiveMetricIDs is identical across the switch.

Independent of provider-tier MinTTL — the grace window only governs whether a metric stays in the active set, not when fetches happen.

View Source
var LogSink func(msg string)

LogSink is called for cache observability. Set by the plugin at init. Dispatch is asynchronous (see cacheLog), so the sink does not need to be non-blocking — but callers should not assume log lines arrive strictly before subsequent code runs.

Functions

func ActiveFor added in v0.8.0

func ActiveFor(providerID string) []string

ActiveFor returns the sorted, deduped set of metric IDs currently bound for the given provider — including count-zero entries still in their grace window. Returns nil when the provider has never had any bound metrics (not an empty slice — `nil` carries the explicit "fetch everything" semantics defined on FetchContext).

Lazily evicts count-zero entries past their grace window so the inner maps don't accumulate stale records for long-running sessions where users repeatedly bind/unbind buttons.

func ClearCache

func ClearCache(providerID string)

ClearCache removes cached data for a provider (or all if id is "").

func ClearRuntimeCache added in v0.6.3

func ClearRuntimeCache(providerID string)

ClearRuntimeCache removes only in-memory cached data for a provider (or all providers if id is ""), preserving restart-surviving snapshots.

func CopilotAppsPath added in v0.7.3

func CopilotAppsPath() string

CopilotAppsPath returns the GitHub Copilot apps.json path.

func CopilotHostsPath added in v0.7.3

func CopilotHostsPath() string

CopilotHostsPath returns the GitHub Copilot hosts.json path.

func MarkActive added in v0.8.0

func MarkActive(providerID, metricID string)

MarkActive records that one bound button is now displaying (providerID, metricID). Safe to call repeatedly — duplicates count. No-op if either argument is empty.

func MarkInactive added in v0.8.0

func MarkInactive(providerID, metricID string)

MarkInactive decrements the bound-button count for (providerID, metricID). When the count drops to zero, the entry enters a grace window and is removed from ActiveFor results ActiveGracePeriod later. No-op if either argument is empty or no matching MarkActive call was made.

func Register

func Register(p Provider)

Register adds a provider to the global registry.

func ResetActiveRegistry added in v0.8.0

func ResetActiveRegistry()

ResetActiveRegistry clears the registry. Test-only — production code should never call this; the registry is process-lifetime.

func StartCredentialWatcher added in v0.5.0

func StartCredentialWatcher()

StartCredentialWatcher starts a background goroutine that polls known provider credential files and clears the matching provider's cache entry when the file changes. The next scheduled poll then fetches fresh data instead of waiting up to MinTTL for the timer to advance.

Safe to call more than once — the watcher is a singleton.

Types

type FetchContext

type FetchContext struct {
	PollIntervalMs int64
	Force          bool
	// ActiveMetricIDs is the sorted, deduped set of metric IDs that at
	// least one currently-bound Stream Deck button is displaying for
	// this provider. Providers MAY use it to skip endpoints whose data
	// doesn't contribute to any listed metric — saves quota on multi-
	// endpoint providers (Perplexity, Gemini, Vertex, Cursor, Claude)
	// for users who only bind a subset of their available metrics.
	//
	// Semantics:
	//   nil           — fetch everything (cold start, force-refresh,
	//                   or any context where the active set isn't known)
	//   non-nil empty — no buttons bound; cache normally won't call
	//                   Fetch in this state, but if it does, the
	//                   provider may return an empty snapshot
	//   non-nil set   — provider may skip work for metrics not listed
	//
	// Providers that ignore this field continue to work — the refactor
	// is opt-in per provider, so adding it here is a no-op for the
	// existing fleet.
	ActiveMetricIDs []string
}

FetchContext provides context to a provider's Fetch method.

type GetSnapshotOptions

type GetSnapshotOptions struct {
	Force bool
}

GetSnapshotOptions configures a cache lookup.

type MetricValue

type MetricValue struct {
	ID              string   `json:"id"`
	Label           string   `json:"label"`
	Name            string   `json:"name,omitempty"`
	Value           any      `json:"value"` // number or string
	NumericValue    *float64 `json:"numericValue,omitempty"`
	NumericUnit     string   `json:"numericUnit,omitempty"`     // "percent"|"dollars"|"cents"|"count"
	NumericGoodWhen string   `json:"numericGoodWhen,omitempty"` // "high"|"low"
	NumericMax      *float64 `json:"numericMax,omitempty"`
	Unit            string   `json:"unit,omitempty"`
	Ratio           *float64 `json:"ratio,omitempty"`     // 0..1
	Direction       string   `json:"direction,omitempty"` // "up"|"down"|"right"|"left"
	ResetInSeconds  *float64 `json:"resetInSeconds,omitempty"`
	Caption         string   `json:"caption,omitempty"`
	RawCount        *int     `json:"rawCount,omitempty"`
	RawMax          *int     `json:"rawMax,omitempty"`
	UpdatedAt       string   `json:"updatedAt,omitempty"`
	Stale           *bool    `json:"stale,omitempty"`
}

MetricValue represents a single usage metric from a provider.

func PaceMetric added in v0.3.0

func PaceMetric(in PaceInput) *MetricValue

PaceMetric computes a linear-burn-rate pace metric.

Returns nil if the input is degenerate (zero window, no elapsed time).

The metric value shows the delta between actual and expected usage:

  • Positive value = reserve (used less than expected — good)
  • Negative value = deficit (used more than expected — bad)

Pace metrics intentionally do NOT set a Ratio: mapping ±N% delta onto a 0..1 fill bar produces a "half-filled tile" at 0% that reads like a percent meter at 50% and confuses everyone. The signed value + caption ("On pace" / "Reserve" / "Deficit") carries the signal without a misleading fill.

func (MetricValue) NumericVal

func (m MetricValue) NumericVal() float64

NumericVal returns the numeric value or 0.

func (MetricValue) RatioVal

func (m MetricValue) RatioVal() float64

RatioVal returns the ratio or -1 if not set.

type MockProvider

type MockProvider struct{}

MockProvider generates deterministic sine-wave data for development.

func (MockProvider) BrandBg added in v0.3.0

func (MockProvider) BrandBg() string

BrandBg returns the background color used on button faces.

func (MockProvider) BrandColor

func (MockProvider) BrandColor() string

BrandColor returns the accent color used on button faces.

func (MockProvider) Fetch

Fetch returns a synthetic Snapshot driven by time-based sine waves.

func (MockProvider) ID

func (MockProvider) ID() string

ID returns the provider identifier used by the registry.

func (MockProvider) MetricIDs

func (MockProvider) MetricIDs() []string

MetricIDs enumerates the metrics this provider emits.

func (MockProvider) Name

func (MockProvider) Name() string

Name returns the human-readable provider name.

type PaceInput added in v0.3.0

type PaceInput struct {
	MetricID       string        // e.g. "session-pace", "weekly-pace"
	Label          string        // e.g. "Session", "Weekly"
	Name           string        // e.g. "Session pace"
	UsedPercent    float64       // 0-100, how much has been consumed
	WindowDuration time.Duration // total window length
	ResetIn        time.Duration // time remaining until reset
}

PaceInput is the data a provider passes to compute a pace metric.

type Provider

type Provider interface {
	ID() string
	Name() string
	BrandColor() string
	BrandBg() string
	MetricIDs() []string
	Fetch(ctx FetchContext) (Snapshot, error)
}

Provider is the interface every usage-data source implements.

func Get

func Get(id string) Provider

Get returns a provider by ID, or nil.

type Snapshot

type Snapshot struct {
	ProviderID   string        `json:"providerId"`
	ProviderName string        `json:"providerName"`
	Source       string        `json:"source"` // "mock"|"oauth"|"web"|"cli"|"cache"
	Metrics      []MetricValue `json:"metrics"`
	Status       string        `json:"status,omitempty"`
	Error        string        `json:"error,omitempty"`
}

Snapshot is the result of a single provider fetch.

func GetSnapshot

func GetSnapshot(p Provider, opts GetSnapshotOptions) Snapshot

GetSnapshot returns a provider snapshot, using the cache when possible. Guarantees at most one in-flight fetch per provider.

func PeekSnapshotState added in v0.5.0

func PeekSnapshotState(providerID string) (*Snapshot, time.Time)

PeekSnapshotState returns the last rendered snapshot and its fetch time without triggering a new fetch. Prefers e.result so stale/error faces produced on the last fetch are preserved across minute redraws; falls back to e.snapshot when no fetch has run.

Directories

Path Synopsis
Package abacus implements the Abacus AI usage provider.
Package abacus implements the Abacus AI usage provider.
Package alibaba implements the Alibaba Coding Plan usage provider.
Package alibaba implements the Alibaba Coding Plan usage provider.
Package amp implements the Amp usage provider.
Package amp implements the Amp usage provider.
Package antigravity implements the Antigravity local language-server quota provider.
Package antigravity implements the Antigravity local language-server quota provider.
Package augment implements the Augment usage provider.
Package augment implements the Augment usage provider.
Package claude implements the Claude OAuth API usage provider.
Package claude implements the Claude OAuth API usage provider.
Package codex implements the Codex OAuth API usage provider.
Package codex implements the Codex OAuth API usage provider.
Package cookieaux holds provider-facing helpers for the browser fetch-proxy path.
Package cookieaux holds provider-facing helpers for the browser fetch-proxy path.
Package copilot implements the GitHub Copilot usage provider.
Package copilot implements the GitHub Copilot usage provider.
Package cursor implements the Cursor usage provider.
Package cursor implements the Cursor usage provider.
Package factory implements the Factory Droid usage provider.
Package factory implements the Factory Droid usage provider.
Package gemini implements the Gemini CLI OAuth usage provider.
Package gemini implements the Gemini CLI OAuth usage provider.
Package grok implements the Grok (xAI) usage provider.
Package grok implements the Grok (xAI) usage provider.
Package hermesagent implements the Hermes Agent self-hosted dashboard provider (NousResearch/hermes-agent on GitHub).
Package hermesagent implements the Hermes Agent self-hosted dashboard provider (NousResearch/hermes-agent on GitHub).
Package jetbrains implements the JetBrains AI local quota provider.
Package jetbrains implements the JetBrains AI local quota provider.
Package kilo implements the Kilo usage provider.
Package kilo implements the Kilo usage provider.
Package kimi implements the Kimi usage provider.
Package kimi implements the Kimi usage provider.
Package kimik2 implements the Kimi K2 credits provider.
Package kimik2 implements the Kimi K2 credits provider.
Package kiro implements the Kiro usage provider.
Package kiro implements the Kiro usage provider.
Package minimax implements the MiniMax coding-plan usage provider.
Package minimax implements the MiniMax coding-plan usage provider.
Package mistral implements the Mistral billing usage provider.
Package mistral implements the Mistral billing usage provider.
Package nousresearch implements the Nous Research portal usage provider (the public hermes.nousresearch.com / portal.nousresearch.com product).
Package nousresearch implements the Nous Research portal usage provider (the public hermes.nousresearch.com / portal.nousresearch.com product).
Package ollama implements the Ollama usage provider.
Package ollama implements the Ollama usage provider.
Device pairing for the OpenClaw provider.
Device pairing for the OpenClaw provider.
Package opencode implements the OpenCode usage provider.
Package opencode implements the OpenCode usage provider.
Package opencodego implements the OpenCode Go usage provider.
Package opencodego implements the OpenCode Go usage provider.
Package openrouter implements the OpenRouter API usage provider.
Package openrouter implements the OpenRouter API usage provider.
Package perplexity implements the Perplexity usage provider.
Package perplexity implements the Perplexity usage provider.
Package providerutil contains small helpers shared by quota-style providers.
Package providerutil contains small helpers shared by quota-style providers.
Package synthetic implements the Synthetic usage provider.
Package synthetic implements the Synthetic usage provider.
Package vertexai implements the Google Vertex AI quota provider.
Package vertexai implements the Google Vertex AI quota provider.
Package warp implements the Warp AI usage provider.
Package warp implements the Warp AI usage provider.
Package zai implements the z.ai usage provider.
Package zai implements the z.ai usage provider.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL