claude-code-status-line 1.2.9

A configurable status line for Claude Code with powerline arrows, context tracking, and quota monitoring
Documentation
use crate::colors::SectionColors;
use crate::utils::visible_len;
use serde::{Deserialize, Serialize};

#[derive(Clone, PartialEq, Debug)]
pub enum SectionKind {
    Generic,
    QuotaCompact(String),
    QuotaDetailed(String),
    ContextCompact,
    ContextDetailed,
}

#[derive(Clone)]
pub struct Section {
    pub kind: SectionKind,
    pub content: String,
    pub priority: u16,         // Lower number = higher priority (0 = always show)
    pub colors: SectionColors, // Per-section colors
    pub width: usize,          // Cached visible width (excluding padding/separators)
}

impl Section {
    pub fn with_kind(
        kind: SectionKind,
        content: String,
        priority: u16,
        colors: SectionColors,
    ) -> Self {
        let width = visible_len(&content);
        Section {
            kind,
            content,
            priority,
            colors,
            width,
        }
    }

    pub fn new(content: String, priority: u16, colors: SectionColors) -> Self {
        Self::with_kind(SectionKind::Generic, content, priority, colors)
    }

    pub fn new_quota_compact(
        label: &str,
        content: String,
        priority: u16,
        colors: SectionColors,
    ) -> Self {
        Self::with_kind(
            SectionKind::QuotaCompact(label.to_string()),
            content,
            priority,
            colors,
        )
    }

    pub fn new_quota_detailed(
        label: &str,
        content: String,
        priority: u16,
        colors: SectionColors,
    ) -> Self {
        Self::with_kind(
            SectionKind::QuotaDetailed(label.to_string()),
            content,
            priority,
            colors,
        )
    }

    pub fn new_context_compact(content: String, priority: u16, colors: SectionColors) -> Self {
        Self::with_kind(SectionKind::ContextCompact, content, priority, colors)
    }

    pub fn new_context_detailed(content: String, priority: u16, colors: SectionColors) -> Self {
        Self::with_kind(SectionKind::ContextDetailed, content, priority, colors)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ContextAccuracy {
    Exact,
    Estimated,
}

/// Context usage information (used for display formatting)
pub struct ContextUsageInfo {
    pub percentage: f64,
    pub current_usage_tokens: u64,
    pub context_window_size: Option<u64>,
    pub accuracy: ContextAccuracy,
}

#[derive(Debug, Deserialize, Clone)]
pub struct ClaudeInput {
    pub cwd: Option<String>,
    pub workspace: Option<Workspace>,
    pub model: Option<Model>,
    pub context_window: Option<ContextWindow>,
    pub cost: Option<Cost>,
    pub output_style: Option<OutputStyle>,
    pub worktree: Option<Worktree>,
    pub version: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Workspace {
    pub current_dir: Option<String>,
    pub project_dir: Option<String>,
    pub added_dirs: Option<Vec<String>>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Model {
    pub id: Option<String>,
    pub display_name: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct OutputStyle {
    pub name: Option<String>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct ContextWindow {
    pub context_window_size: Option<u64>,
    pub total_input_tokens: Option<u64>,
    pub total_output_tokens: Option<u64>,
    pub current_usage: Option<CurrentUsage>,
    pub used_percentage: Option<f64>,
    pub remaining_percentage: Option<f64>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct CurrentUsage {
    pub input_tokens: Option<u64>,
    #[serde(alias = "_output_tokens")]
    pub output_tokens: Option<u64>,
    pub cache_creation_input_tokens: Option<u64>,
    pub cache_read_input_tokens: Option<u64>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Cost {
    pub total_cost_usd: Option<f64>,
    pub total_duration_ms: Option<u64>,
    pub total_api_duration_ms: Option<u64>,
    pub total_lines_added: Option<u64>,
    pub total_lines_removed: Option<u64>,
}

#[derive(Debug, Deserialize, Clone)]
pub struct Worktree {
    pub name: Option<String>,
    pub path: Option<String>,
    pub branch: Option<String>,
    pub original_cwd: Option<String>,
    pub original_branch: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct QuotaResponse {
    pub five_hour: Option<QuotaLimit>,
    pub seven_day: Option<QuotaLimit>,
}

#[derive(Debug, Deserialize)]
pub struct ApiErrorResponse {
    pub error: ApiErrorBody,
}

#[derive(Debug, Deserialize)]
pub struct ApiErrorBody {
    #[serde(rename = "type")]
    pub error_type: Option<String>,
    pub message: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct QuotaLimit {
    pub utilization: f64,
    pub resets_at: Option<String>,
}

#[derive(Debug, Deserialize)]
pub struct KeychainCredentials {
    #[serde(rename = "claudeAiOauth")]
    pub claude_ai_oauth: Option<OAuthCredentials>,
}

#[derive(Debug, Deserialize)]
pub struct OAuthCredentials {
    #[serde(rename = "accessToken")]
    pub access_token: String,
}

// Quota data structure
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
pub struct QuotaData {
    pub five_hour_pct: Option<f64>,
    pub five_hour_resets_at: Option<String>,
    pub seven_day_pct: Option<f64>,
    pub seven_day_resets_at: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CachedQuota {
    pub timestamp: u64,
    pub data: QuotaData,
}

#[derive(Debug, Default, Serialize, Deserialize, Clone)]
pub struct QuotaCacheState {
    pub last_success_at: Option<u64>,
    pub last_success_data: Option<QuotaData>,
    pub next_retry_at: Option<u64>,
    pub last_error_kind: Option<String>,
    pub retry_after_secs: Option<u64>,
    pub refresh_in_progress_until: Option<u64>,
}

#[derive(Debug, PartialEq)]
pub struct GitInfo {
    pub branch: String,
    pub is_dirty: bool,
    pub repo_name: Option<String>,
    pub lines_added: usize,
    pub lines_removed: usize,
}