feat: add configuration system with pricing tables and plan detection
Implement the configuration layer that supports the entire cost estimation pipeline: - config/config.go: TOML-based config at ~/.config/cburn/config.toml (XDG-compliant) with sections for general preferences, Admin API credentials, budget tracking, appearance, and per-model pricing overrides. Supports Load/Save with sensible defaults (30-day window, subagents included, Flexoki Dark theme). Admin API key resolution checks ANTHROPIC_ADMIN_KEY env var first, falling back to the config file. - config/pricing.go: Hardcoded pricing table for 8 Claude model variants (Opus 4/4.1/4.5/4.6, Sonnet 4/4.5/4.6, Haiku 3.5/4.5) with per-million-token rates across 5 billing dimensions: input, output, cache_write_5m, cache_write_1h, cache_read, plus long- context overrides (>200K tokens). NormalizeModelName strips date suffixes (e.g., "claude-opus-4-5-20251101" -> "claude-opus-4-5"). CalculateCost and CalculateCacheSavings compute per-call USD costs by multiplying token counts against the pricing table. - config/plan.go: DetectPlan reads ~/.claude/.claude.json to determine the billing plan type. Maps "stripe_subscription" to the Max plan ($200/mo ceiling), everything else to Pro ($100/mo). Used by the budget tab for plan-relative spend visualization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
40
internal/config/plan.go
Normal file
40
internal/config/plan.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// PlanInfo holds detected Claude subscription plan info.
|
||||
type PlanInfo struct {
|
||||
BillingType string
|
||||
PlanCeiling float64
|
||||
}
|
||||
|
||||
// DetectPlan reads ~/.claude/.claude.json to determine the billing plan.
|
||||
func DetectPlan(claudeDir string) PlanInfo {
|
||||
path := filepath.Join(claudeDir, ".claude.json")
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return PlanInfo{PlanCeiling: 200} // default to Max plan
|
||||
}
|
||||
|
||||
var raw struct {
|
||||
BillingType string `json:"billingType"`
|
||||
}
|
||||
if err := json.Unmarshal(data, &raw); err != nil {
|
||||
return PlanInfo{PlanCeiling: 200}
|
||||
}
|
||||
|
||||
info := PlanInfo{BillingType: raw.BillingType}
|
||||
|
||||
switch raw.BillingType {
|
||||
case "stripe_subscription":
|
||||
info.PlanCeiling = 200 // Max plan default
|
||||
default:
|
||||
info.PlanCeiling = 100 // Pro plan default
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
Reference in New Issue
Block a user