feat(ecc2): add token/cost meter widget (#775)

- TokenMeter widget using ratatui Gauge with color gradient (green->yellow->red)
- Budget fields (cost_budget_usd, token_budget) in Config
- Aggregate cost display in status bar
- Warning state at 80%+ budget consumption
- Tests for gradient, config fallback, and meter rendering
This commit is contained in:
Affaan Mustafa
2026-03-23 03:46:25 -07:00
parent e7d827548c
commit d7bcc92007
6 changed files with 577 additions and 42 deletions

View File

@@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
pub db_path: PathBuf,
pub worktree_root: PathBuf,
@@ -11,6 +12,8 @@ pub struct Config {
pub session_timeout_secs: u64,
pub heartbeat_interval_secs: u64,
pub default_agent: String,
pub cost_budget_usd: f64,
pub token_budget: u64,
pub theme: Theme,
}
@@ -31,6 +34,8 @@ impl Default for Config {
session_timeout_secs: 3600,
heartbeat_interval_secs: 30,
default_agent: "claude".to_string(),
cost_budget_usd: 10.0,
token_budget: 500_000,
theme: Theme::Dark,
}
}
@@ -52,3 +57,36 @@ impl Config {
}
}
}
#[cfg(test)]
mod tests {
use super::Config;
#[test]
fn default_includes_positive_budget_thresholds() {
let config = Config::default();
assert!(config.cost_budget_usd > 0.0);
assert!(config.token_budget > 0);
}
#[test]
fn missing_budget_fields_fall_back_to_defaults() {
let legacy_config = r#"
db_path = "/tmp/ecc2.db"
worktree_root = "/tmp/ecc-worktrees"
max_parallel_sessions = 8
max_parallel_worktrees = 6
session_timeout_secs = 3600
heartbeat_interval_secs = 30
default_agent = "claude"
theme = "Dark"
"#;
let config: Config = toml::from_str(legacy_config).unwrap();
let defaults = Config::default();
assert_eq!(config.cost_budget_usd, defaults.cost_budget_usd);
assert_eq!(config.token_budget, defaults.token_budget);
}
}