Skip to content
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
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [0.8.1] - 2026-03-23

### Fixed
- Dashboard focus sidebar: usage stats no longer flash and disappear. The
`/focus` endpoint now omits `usage` from the response unless `?usage=1` is
explicitly requested, preventing the fast 2s poll from overwriting real
token counts with zeros.

## [0.8.0] - 2026-03-23

### Added
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "tutti"
version = "0.8.0"
version = "0.8.1"
edition = "2024" # intentional: codebase uses Rust 2024 let-chain syntax
description = "Multi-agent orchestration CLI — your agents, all together"
license = "MIT"
Expand Down
71 changes: 39 additions & 32 deletions src/cli/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1091,18 +1091,21 @@ fn agent_focus_data(
// Usage stats — expensive filesystem scan (~10s on large projects).
// Only compute when ?usage=1 is passed. The dashboard requests this
// on a slower 30s cadence, not on every 2s terminal poll.
let usage_data = if query.get("usage").map(|v| v == "1").unwrap_or(false) {
let include_usage = query.get("usage").map(|v| v == "1").unwrap_or(false);
let usage_data = if include_usage {
let since = chrono::Utc::now() - chrono::Duration::days(7);
crate::usage::scan_workspace_usage(
&target.project_root,
&target.config.workspace.name,
since,
Some(
crate::usage::scan_workspace_usage(
&target.project_root,
&target.config.workspace.name,
since,
)
.ok()
.and_then(|wu| wu.by_agent.get(agent_name).cloned())
.unwrap_or_default(),
)
.ok()
.and_then(|wu| wu.by_agent.get(agent_name).cloned())
.unwrap_or_default()
} else {
crate::usage::AggregatedUsage::default()
None
};

// Git diff — resolve worktree and run git diff
Expand Down Expand Up @@ -1135,29 +1138,33 @@ fn agent_focus_data(
(String::new(), 0, 0, 0)
};

Ok(api_ok(
"agent.focus",
json!({
"workspace": workspace,
"agent": agent_name,
"session": session,
"running": running,
"terminal": terminal_output,
"context_pct": context_pct,
"usage": {
"input_tokens": usage_data.total.input_tokens,
"output_tokens": usage_data.total.output_tokens,
"cache_read": usage_data.total.cache_read_input_tokens,
"cache_write": usage_data.total.cache_creation_input_tokens,
},
"diff": {
"text": diff_text,
"files_changed": files_changed,
"insertions": insertions,
"deletions": deletions,
}
}),
))
let mut focus_data = json!({
"workspace": workspace,
"agent": agent_name,
"session": session,
"running": running,
"terminal": terminal_output,
"context_pct": context_pct,
"diff": {
"text": diff_text,
"files_changed": files_changed,
"insertions": insertions,
"deletions": deletions,
}
});

// Only include usage when explicitly requested — prevents the fast poll
// from overwriting real usage data with zeros on the client side
if let Some(usage) = usage_data {
focus_data["usage"] = json!({
"input_tokens": usage.total.input_tokens,
"output_tokens": usage.total.output_tokens,
"cache_read": usage.total.cache_read_input_tokens,
"cache_write": usage.total.cache_creation_input_tokens,
});
}

Ok(api_ok("agent.focus", focus_data))
}

fn parse_diff_stat(stat: &str) -> (usize, usize, usize) {
Expand Down
Loading