feat: add environment sections, visual enhancements, enhanced tools/beads, and /clear detection
The feature layer that builds on the new infrastructure modules. Adds
4 new environment-aware sections, rewrites the tools/beads/turns sections,
introduces gradient sparklines and block-style context bars, and wires
/clear detection into the main binary.
New sections (4):
cloud_profile — Shows active cloud provider profile from env vars
($AWS_PROFILE, $CLOUDSDK_CORE_PROJECT, $AZURE_SUBSCRIPTION_ID).
Provider-specific coloring (AWS orange, GCP blue, Azure blue).
k8s_context — Parses kubeconfig for current-context and namespace.
Minimal YAML scanning (no yaml dependency). 30s TTL cache.
Shows "context/namespace" with split coloring.
python_env — Detects active virtualenv ($VIRTUAL_ENV) or conda
($CONDA_DEFAULT_ENV, excluding "base"). Shows just the env name.
toolchain — Detects Rust (rust-toolchain.toml) and Node.js (.nvmrc,
.node-version) versions. Compares expected vs actual ($RUSTUP_TOOLCHAIN,
$NODE_VERSION) and highlights mismatches in yellow.
Tools section rewrite:
Progressive disclosure based on terminal width:
- Narrow: just the count ("245")
- Medium: count + last tool name ("245 tools (Bash)")
- Wide: per-tool color-coded breakdown ("245 tools (Bash: 84/Read: 35/...)")
Adaptive width budgeting: breakdown reduces tool count until it fits
within 1/3 of terminal width. Color palette priority: config > terminal
ANSI palette (via OSC 4) > built-in Dracula palette.
Beads section rewrite:
Switched from `br ready --json` to `br stats --json` to show all
statuses. Now renders multi-status breakdown: "3 ready 1 wip 2 open"
with per-status visibility toggles in config.
Turns section:
Falls back to transcript-derived turn count when cost.total_turns is
absent. Requires at least one data source to render (vanishes when
no session data exists at all).
Visual enhancements:
trend.rs:
- append_delta(): tracks rate-of-change (delta between cumulative
samples) so sparklines show burn intensity, not monotonic growth
- sparkline(): now renders exactly `width` chars with left-padding
for missing data. Baseline (space) vs flatline (lowest bar) chars.
- sparkline_colored(): per-character gradient coloring via colorgrad,
returns (raw, ansi) tuple for layout compatibility.
context_bar.rs:
- Block style: Unicode full-block fill + light-shade empty chars
- Per-character green->yellow->red gradient for block style
- Classic style preserved (= and - chars) with single threshold color
- Configurable fill_char/empty_char overrides
context_trend + cost_trend:
Switched to append_delta for rate-based sparklines. Gradient coloring
with green->yellow->red via sparkline_colored().
format.rs:
Background color support via resolve_background(). Accepts named
colors, hex, and palette refs. Applied as ANSI bg wrap around section
output, preserving foreground colors.
layout/mod.rs:
- Separator styles: text (default), powerline (Nerd Font), arrow
(Unicode), none (spaces). Powerline auto-falls-back to arrow when
glyphs disabled.
- Placeholder support: when an enabled section returns None (no data),
substitutes a configurable placeholder character (default: box-draw)
to maintain layout stability during justify/flex.
Section refinements:
cost, cost_velocity, token_velocity, duration, tokens_raw — now show
zero/baseline values instead of hiding entirely. This prevents layout
jumps when sessions start or after /clear.
context_usage — uses current_usage fields (input_tokens +
cache_creation + cache_read) for precise token counts instead of
percentage-derived estimates. Shows one decimal place on percentage.
metrics.rs — prefers total_api_duration_ms over total_duration_ms for
velocity calculations (active processing vs wall clock with idle time).
Cache efficiency now divides by total input (not just cache tokens).
Config additions (config.rs):
SeparatorStyle enum (text/powerline/arrow/none), BarStyle enum
(classic/block), gradient toggle on trends + context_bar, background
and placeholder on SectionBase, tools breakdown config (show_breakdown,
top_n, palette), 4 new section structs.
Main binary (/clear detection + wiring):
detect_clear() — watches for significant context usage drops (>15%
to <5%, >20pp drop) to identify /clear. On detection: saves transcript
offset so derived stats only count post-clear entries, flushes trend
caches for fresh sparklines.
resolve_transcript_stats() — cached transcript parsing with 5s TTL,
respects clear offset, skipped when cost already has tool counts.
resolve_terminal_palette() — cached palette detection with 1h TTL.
Debug: CLAUDE_STATUSLINE_DEBUG env var dumps raw input JSON to
/tmp/claude-statusline-input.json. dump-state now includes input data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -45,6 +45,7 @@ impl Default for LayoutValue {
|
||||
#[serde(default)]
|
||||
pub struct GlobalConfig {
|
||||
pub separator: String,
|
||||
pub separator_style: SeparatorStyle,
|
||||
pub justify: JustifyMode,
|
||||
pub vcs: String,
|
||||
pub width: Option<u16>,
|
||||
@@ -75,6 +76,7 @@ impl Default for GlobalConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
separator: " | ".into(),
|
||||
separator_style: SeparatorStyle::Text,
|
||||
justify: JustifyMode::Left,
|
||||
vcs: "auto".into(),
|
||||
width: None,
|
||||
@@ -121,6 +123,24 @@ pub enum ColorMode {
|
||||
Never,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "kebab-case")]
|
||||
pub enum SeparatorStyle {
|
||||
#[default]
|
||||
Text,
|
||||
Powerline,
|
||||
Arrow,
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum BarStyle {
|
||||
Classic,
|
||||
#[default]
|
||||
Block,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct Breakpoints {
|
||||
@@ -172,6 +192,8 @@ pub struct SectionBase {
|
||||
pub pad: Option<u16>,
|
||||
pub align: Option<String>,
|
||||
pub color: Option<String>,
|
||||
pub background: Option<String>,
|
||||
pub placeholder: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for SectionBase {
|
||||
@@ -186,6 +208,8 @@ impl Default for SectionBase {
|
||||
pad: None,
|
||||
align: None,
|
||||
color: None,
|
||||
background: None,
|
||||
placeholder: Some("\u{2500}".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,6 +243,10 @@ pub struct Sections {
|
||||
pub time: TimeSection,
|
||||
pub output_style: SectionBase,
|
||||
pub hostname: SectionBase,
|
||||
pub cloud_profile: SectionBase,
|
||||
pub k8s_context: CachedSection,
|
||||
pub python_env: SectionBase,
|
||||
pub toolchain: SectionBase,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
@@ -356,6 +384,10 @@ pub struct ContextBarSection {
|
||||
#[serde(flatten)]
|
||||
pub base: SectionBase,
|
||||
pub bar_width: u16,
|
||||
pub bar_style: BarStyle,
|
||||
pub gradient: bool,
|
||||
pub fill_char: Option<String>,
|
||||
pub empty_char: Option<String>,
|
||||
pub thresholds: Thresholds,
|
||||
}
|
||||
|
||||
@@ -369,6 +401,10 @@ impl Default for ContextBarSection {
|
||||
..Default::default()
|
||||
},
|
||||
bar_width: 10,
|
||||
bar_style: BarStyle::Block,
|
||||
gradient: true,
|
||||
fill_char: None,
|
||||
empty_char: None,
|
||||
thresholds: Thresholds {
|
||||
warn: 50.0,
|
||||
danger: 70.0,
|
||||
@@ -492,6 +528,7 @@ pub struct TrendSection {
|
||||
#[serde(flatten)]
|
||||
pub base: SectionBase,
|
||||
pub width: u8,
|
||||
pub gradient: bool,
|
||||
}
|
||||
|
||||
impl Default for TrendSection {
|
||||
@@ -502,6 +539,7 @@ impl Default for TrendSection {
|
||||
..Default::default()
|
||||
},
|
||||
width: 8,
|
||||
gradient: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -512,6 +550,7 @@ pub struct ContextTrendSection {
|
||||
#[serde(flatten)]
|
||||
pub base: SectionBase,
|
||||
pub width: u8,
|
||||
pub gradient: bool,
|
||||
pub thresholds: Thresholds,
|
||||
}
|
||||
|
||||
@@ -523,6 +562,7 @@ impl Default for ContextTrendSection {
|
||||
..Default::default()
|
||||
},
|
||||
width: 8,
|
||||
gradient: true,
|
||||
thresholds: Thresholds::default(),
|
||||
}
|
||||
}
|
||||
@@ -534,6 +574,13 @@ pub struct ToolsSection {
|
||||
#[serde(flatten)]
|
||||
pub base: SectionBase,
|
||||
pub show_last_name: bool,
|
||||
/// Show per-tool breakdown (e.g., "Bash:84 Read:35 Edit:34").
|
||||
pub show_breakdown: bool,
|
||||
/// Max number of tools to show in breakdown (0 = all).
|
||||
pub top_n: usize,
|
||||
/// Rotating color palette for tool names (hex strings, e.g. "#8be9fd").
|
||||
/// Falls back to built-in Dracula palette when empty.
|
||||
pub palette: Vec<String>,
|
||||
pub ttl: u64,
|
||||
}
|
||||
|
||||
@@ -546,6 +593,9 @@ impl Default for ToolsSection {
|
||||
..Default::default()
|
||||
},
|
||||
show_last_name: true,
|
||||
show_breakdown: true,
|
||||
top_n: 7,
|
||||
palette: Vec::new(),
|
||||
ttl: 2,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user