Documentation
¶
Overview ¶
Package anthropicapi implements the ports.PlanUsageSource interface by calling Anthropic's OAuth-protected /api/oauth/usage endpoint with the access token that Claude Code CLI stores locally.
Auth source priority on macOS:
- Keychain service "Claude Code-credentials" (account = current user)
- ~/.claude/.credentials.json (file fallback)
On non-Darwin platforms only the file source is consulted.
The package is intentionally self-contained: no third-party deps, no CGo; stdlib net/http and os/exec only.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrCredentialsNotFound = errors.New("anthropicapi: credentials not found")
ErrCredentialsNotFound is returned by loaders when neither source had credentials. The package-level Fetch path translates this to ports.ErrPlanUsageUnavailable.
var ErrInvalidGrant = errors.New("anthropicapi: invalid_grant — re-authentication required")
ErrInvalidGrant is the terminal refresh failure: the refresh_token has been revoked or expired beyond recovery. Translated to ports.ErrPlanUsageAuth at the package boundary.
Functions ¶
func HumanTier ¶
HumanTier maps the raw rateLimitTier string ("max_5x", "pro", "team_max", "ultra_pro", ...) into a short human label. Unknown values are title-cased verbatim.
Mapping rules (most-specific first):
- "max" or "max_<x>" → "Max" / "Max <x>" (preserve the multiplier)
- contains "ultra" → "Ultra"
- contains "team" → "Team"
- contains "enterprise" → "Enterprise"
- contains "max" → "Max" (fallback for things like "team_max")
- contains "pro" → "Pro"
func SaveCredentials ¶
func SaveCredentials(c Credentials) error
SaveCredentials writes refreshed credentials back to the file location so other clyde processes (and a long-running clyde session) can pick up the new tokens.
It is ONLY called when the credentials were read from the file in the first place (credSource == sourceFile). Keychain is strictly read-only from clyde: when tokens originate in the Keychain we never refresh and never write here, because writing the file copy would be ineffective (the next read is Keychain-first on macOS) and rotating the Keychain-shared refresh token could log the user out of the Claude Code CLI. See the refresh policy in client.go.
Best-effort: errors from the write are returned so callers can decide whether to surface them, but the in-memory Credentials remain valid.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client implements ports.PlanUsageSource by combining:
- Credentials loading (file + Keychain)
- OAuth refresh when the access token is expired or rejected
- GET /api/oauth/usage with the Bearer token
A single Client instance is safe for concurrent use; the credentials cache + refresh path are guarded by a mutex.
func NewClient ¶
func NewClient() *Client
NewClient returns a Client with sensible defaults — a 10s timeout HTTP client and the system clock.
func NewClientWithDeps ¶
NewClientWithDeps returns a Client with custom HTTP client + clock — the hook tests use to inject httptest.Server URLs and a deterministic clock.
func (*Client) Fetch ¶
Fetch implements ports.PlanUsageSource. It returns the current plan-quota snapshot, refreshing the access token transparently if needed.
Translation rules (adapter → port):
- ErrCredentialsNotFound → ports.ErrPlanUsageUnavailable
- ErrInvalidGrant → ports.ErrPlanUsageAuth
- HTTP 401 after refresh → ports.ErrPlanUsageAuth
- everything else → wrapped raw error
type Credentials ¶
type Credentials struct {
AccessToken string
RefreshToken string
ExpiresAt time.Time
Scopes []string
RateLimitTier string
}
Credentials is the OAuth state Claude Code persists.
Fields mirror the on-disk schema:
{
"claudeAiOauth": {
"accessToken": "sk-ant-oat...",
"refreshToken": "...",
"expiresAt": 1704067200000, // ms epoch
"scopes": ["user:profile","user:inference"],
"rateLimitTier": "max_5x"
}
}
func LoadCredentials ¶
func LoadCredentials() (Credentials, error)
LoadCredentials reads OAuth state from Keychain (preferred on macOS) or the ~/.claude/.credentials.json file fallback.
Returns ErrCredentialsNotFound when neither source has credentials.