Skip to content
This repository was archived by the owner on Jul 30, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions crates/tokscale-cli/src/tui/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use super::data::{

/// Cache staleness threshold: 5 minutes (matches TS implementation)
const CACHE_STALE_THRESHOLD_MS: u64 = 5 * 60 * 1000;
const CACHE_SCHEMA_VERSION: u32 = 7;
const CACHE_SCHEMA_VERSION: u32 = 8;

/// Get the cache directory path
/// Uses `~/.cache/tokscale/` to match TypeScript implementation for cache sharing
Expand Down Expand Up @@ -1224,7 +1224,7 @@ mod tests {
fs::write(
&cache_path,
r#"{
"schemaVersion": 7,
"schemaVersion": 8,
"timestamp": 9999999999999,
"enabledClients": ["claude", "cursor"],
"includeSynthetic": false,
Expand Down Expand Up @@ -1254,11 +1254,11 @@ mod tests {
},
"cost": 1.25,
"models": [[
"claude-sonnet-4-5",
"claude-sonnet-4",
{
"provider": "anthropic",
"displayName": "claude-sonnet-4-5",
"colorKey": "claude-sonnet-4-5",
"displayName": "claude-sonnet-4",
"colorKey": "claude-sonnet-4",
"tokens": {
"input": 10,
"output": 5,
Expand All @@ -1282,11 +1282,11 @@ mod tests {
},
"cost": 2.0,
"models": [[
"claude-sonnet-4-5",
"claude-sonnet-4",
{
"provider": "anthropic",
"displayName": "claude-sonnet-4-5",
"colorKey": "claude-sonnet-4-5",
"displayName": "claude-sonnet-4",
"colorKey": "claude-sonnet-4",
"tokens": {
"input": 20,
"output": 10,
Expand Down Expand Up @@ -1315,7 +1315,7 @@ mod tests {
CacheResult::Fresh(data) => {
assert_eq!(data.daily[0].source_breakdown.len(), 2);
let cursor = data.daily[0].source_breakdown.get("cursor").unwrap();
let model = cursor.models.get("claude-sonnet-4-5").unwrap();
let model = cursor.models.get("claude-sonnet-4").unwrap();
assert_eq!(model.provider, "anthropic");
assert_eq!(model.tokens.total(), 30);
}
Expand Down Expand Up @@ -1506,7 +1506,7 @@ mod tests {
fs::write(
&legacy_path,
r#"{
"schemaVersion": 7,
"schemaVersion": 8,
"timestamp": 9999999999999,
"enabledClients": ["claude"],
"includeSynthetic": false,
Expand Down
29 changes: 13 additions & 16 deletions crates/tokscale-cli/src/tui/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1674,7 +1674,7 @@ mod tests {
assert_eq!(usage.models.len(), 1);
assert_eq!(usage.models[0].workspace_key.as_deref(), Some("/repo-a"));
assert_eq!(usage.models[0].workspace_label.as_deref(), Some("repo-a"));
assert_eq!(usage.models[0].model, "claude-sonnet-4-5");
assert_eq!(usage.models[0].model, "claude-sonnet-4");
assert_eq!(usage.models[0].client, "claude, qwen");
assert_eq!(usage.models[0].session_count, 2);
assert_eq!(usage.models[0].cost, 4.0);
Expand Down Expand Up @@ -1803,8 +1803,8 @@ mod tests {
assert_eq!(
daily_display_names,
vec![
"repo-a / claude-sonnet-4-5".to_string(),
"repo-b / claude-sonnet-4-5".to_string()
"repo-a / claude-sonnet-4".to_string(),
"repo-b / claude-sonnet-4".to_string()
]
);
}
Expand Down Expand Up @@ -1855,8 +1855,8 @@ mod tests {
assert_eq!(
display_names,
vec![
"demo / claude-sonnet-4-5".to_string(),
"demo / claude-sonnet-4-5".to_string()
"demo / claude-sonnet-4".to_string(),
"demo / claude-sonnet-4".to_string()
]
);
}
Expand Down Expand Up @@ -1906,21 +1906,18 @@ mod tests {
let claude = usage.daily[0].source_breakdown.get("claude").unwrap();
assert_eq!(claude.models.len(), 2);

let anthropic_key = "anthropic:claude-sonnet-4-5";
let copilot_key = "github-copilot:claude-sonnet-4-5";
let anthropic_key = "anthropic:claude-sonnet-4";
let copilot_key = "github-copilot:claude-sonnet-4";
let anthropic_model = claude.models.get(anthropic_key).unwrap();
assert_eq!(
anthropic_model.display_name,
"anthropic / claude-sonnet-4-5"
);
assert_eq!(anthropic_model.display_name, "anthropic / claude-sonnet-4");
assert_eq!(anthropic_model.provider, "anthropic");
assert_eq!(anthropic_model.tokens.total(), 15);
assert_eq!(anthropic_model.messages, 1);

let copilot_model = claude.models.get(copilot_key).unwrap();
assert_eq!(
copilot_model.display_name,
"github-copilot / claude-sonnet-4-5"
"github-copilot / claude-sonnet-4"
);
assert_eq!(copilot_model.provider, "github-copilot");
assert_eq!(copilot_model.tokens.total(), 30);
Expand Down Expand Up @@ -1974,15 +1971,15 @@ mod tests {
let claude = usage.daily[0].source_breakdown.get("claude").unwrap();
assert_eq!(claude.cost, 1.0);
assert_eq!(claude.models.len(), 1);
let claude_model = claude.models.get("claude-sonnet-4-5").unwrap();
assert_eq!(claude_model.display_name, "claude-sonnet-4-5");
let claude_model = claude.models.get("claude-sonnet-4").unwrap();
assert_eq!(claude_model.display_name, "claude-sonnet-4");
assert_eq!(claude_model.tokens.total(), 15);

let cursor = usage.daily[0].source_breakdown.get("cursor").unwrap();
assert_eq!(cursor.cost, 2.0);
assert_eq!(cursor.models.len(), 1);
let cursor_model = cursor.models.get("claude-sonnet-4-5").unwrap();
assert_eq!(cursor_model.display_name, "claude-sonnet-4-5");
let cursor_model = cursor.models.get("claude-sonnet-4").unwrap();
assert_eq!(cursor_model.display_name, "claude-sonnet-4");
assert_eq!(cursor_model.tokens.total(), 30);
}

Expand Down
32 changes: 32 additions & 0 deletions crates/tokscale-cli/src/tui/ui/widgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,13 @@ fn get_single_provider_display_name(provider: &str) -> String {
"google" => "Google".to_string(),
"cursor" => "Cursor".to_string(),
"deepseek" => "DeepSeek".to_string(),
s if s.starts_with("zai") || s.starts_with("zhipu") => "Z.AI".to_string(),
s if s.starts_with("xiaomi") => "XiaoMi".to_string(),
s if s.starts_with("minimax") => "MiniMax".to_string(),
s if s == "kimi-code" || s == "kimi-for-coding" => "Kimi".to_string(),
s if s.starts_with("doubao") => "Doubao".to_string(),
s if s.starts_with("alibaba") => "Alibaba".to_string(),
s if s.starts_with("tencent") || s.starts_with("tecent") => "Tencent".to_string(),
"xai" => "xAI".to_string(),
"meta" => "Meta".to_string(),
"mistral" => "Mistral".to_string(),
Expand Down Expand Up @@ -365,6 +372,31 @@ mod tests {
);
}

#[test]
fn provider_display_formats_coding_plan_aliases() {
let cases = [
("zai", "Z.AI"),
("zai-coding-plan", "Z.AI"),
("zai-coding-pln", "Z.AI"),
("zhipuai-coding-plan", "Z.AI"),
("zhipu", "Z.AI"),
("xiaomi-token-plan-cn", "XiaoMi"),
("xiaomi-token-plan-sgp", "XiaoMi"),
("minimax-code-cn", "MiniMax"),
("minimax-cn-coding-plan", "MiniMax"),
("kimi-code", "Kimi"),
("kimi-for-coding", "Kimi"),
("doubao-coding-plan", "Doubao"),
("alibaba-coding-plan-cn", "Alibaba"),
("tencent-coding-plan", "Tencent"),
("tecent-coding-plan", "Tencent"),
];

for (provider, expected) in cases {
assert_eq!(get_provider_display_name(provider), expected);
}
}

#[test]
fn client_display_formats_each_segment_in_merged_list() {
assert_eq!(
Expand Down
Loading