cmd-usage 0.7.0

Live Command Code (commandcode.ai) usage dashboard: credits, 5-hour and weekly windows, plan limits. Watch mode or one-shot.
Documentation
// The docs catalogue: what a model costs and what it is allowed, per product.
//
// Generated by `scripts/extract-zen.ts` (run `bun scripts/extract-zen.ts`) from
// OpenCode's own docs sources, so the numbers move with upstream instead of
// living in code. Go carries a monthly dollar limit per model and the documented
// window split; Zen is pay-as-you-go, so it has rates but no limits.
use serde::Deserialize;

// Re-exported from `cmduse-core` so the path stays inside its own crate (a
// `include_str!` reaching outside is fine locally and fatal at `cargo publish`).
const RAW: &str = cmduse_core::ZEN_JSON;

#[derive(Debug, Clone, Deserialize)]
pub struct RateVariant {
    pub peak: Option<String>,
    #[serde(rename = "tierMaxTokens")]
    pub tier_max_tokens: Option<u64>,
    #[serde(rename = "tierMinTokens")]
    pub tier_min_tokens: Option<u64>,
    pub input: f64,
    pub output: f64,
    #[serde(rename = "cacheRead")]
    pub cache_read: f64,
    #[serde(rename = "cacheWrite")]
    pub cache_write: f64,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Model {
    pub id: String,
    pub name: String,
    #[serde(rename = "monthlyLimit")]
    pub monthly_limit: Option<f64>,
    pub variants: Vec<RateVariant>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct WindowShare {
    #[serde(rename = "fiveHour")]
    pub five_hour: f64,
    pub weekly: f64,
    pub monthly: f64,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Plans {
    #[serde(rename = "priceUsd")]
    pub price_usd: f64,
    #[serde(rename = "windowShare")]
    pub window_share: WindowShare,
    pub models: Vec<Model>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Zen {
    pub models: Vec<Model>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct Catalog {
    #[serde(rename = "extractedAt")]
    pub extracted_at: String,
    pub go: Plans,
    pub zen: Zen,
}

/// Parsed once; the file is a compile-time constant.
pub fn catalog() -> Catalog {
    serde_json::from_str(RAW)
        .expect("core/zen.json is generated; regenerate with scripts/extract-zen.ts")
}

impl Catalog {
    /// Monthly dollar limit for a `opencode-go` model id, if the docs list one.
    pub fn go_limit(&self, model_id: &str) -> Option<f64> {
        self.go
            .models
            .iter()
            .find(|m| m.id == model_id)
            .and_then(|m| m.monthly_limit)
    }
}

/// Suggested cap for a rolling window, from the documented share of the limit.
pub fn window_cap(limit: f64, share: f64) -> f64 {
    limit * share
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn catalogue_parses_and_carries_limits() {
        let c = catalog();
        assert!(c.go.models.len() > 20, "go models: {}", c.go.models.len());
        assert!(!c.zen.models.is_empty());
        assert_eq!(c.go_limit("deepseek-v4.1-flash"), Some(60.0));
        assert_eq!(c.go_limit("nope-not-a-model"), None);
    }

    #[test]
    fn window_split_matches_the_docs() {
        let c = catalog();
        assert_eq!(c.go.window_share.five_hour, 0.2);
        assert_eq!(c.go.window_share.weekly, 0.5);
        assert_eq!(c.go.window_share.monthly, 1.0);
        assert_eq!(window_cap(60.0, c.go.window_share.five_hour), 12.0);
    }

    #[test]
    fn tiered_and_peak_variants_are_kept() {
        let c = catalog();
        let qwen =
            c.go.models
                .iter()
                .find(|m| m.id == "qwen3.7-plus")
                .expect("qwen3.7-plus");
        assert_eq!(qwen.variants.len(), 2);
        assert!(qwen
            .variants
            .iter()
            .any(|v| v.tier_max_tokens == Some(256_000)));
        let deepseek =
            c.go.models
                .iter()
                .find(|m| m.id == "deepseek-v4-flash")
                .expect("deepseek");
        assert!(deepseek
            .variants
            .iter()
            .any(|v| v.peak.as_deref() == Some("peak")));
    }
}