@buckits/claude-statusline 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -0
- package/bin/install.js +50 -0
- package/package.json +28 -0
- package/statusline.sh +254 -0
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @buckits/claude-statusline
|
|
2
|
+
|
|
3
|
+
A gradient color statusline for Claude Code featuring a visual progress bar that transitions from green to red as your context fills up.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx @buckits/claude-statusline
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Gradient Progress Bar** - Visual bar that smoothly transitions green → yellow → orange → red as context fills
|
|
14
|
+
- **Color-coded Token Count** - Used tokens match the progress gradient color
|
|
15
|
+
- **Auto-compact Indicator** - Shows `⚡X% until compact` with color warnings (green when safe, red when critical)
|
|
16
|
+
- **Git Integration** - Displays current branch name
|
|
17
|
+
- **Project Name** - Shows current working directory name
|
|
18
|
+
|
|
19
|
+
## Screenshot
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
Opus 4.5 [████████████░░░░░░░░] 98.2k/200.0k ⚡15% until compact main my-project
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## What it looks like
|
|
26
|
+
|
|
27
|
+
| Context Usage | Progress Bar Color | Compact Indicator |
|
|
28
|
+
|---------------|-------------------|-------------------|
|
|
29
|
+
| 0-33% | Green | Green (25%+) |
|
|
30
|
+
| 34-66% | Yellow/Orange | Yellow (15-24%) |
|
|
31
|
+
| 67-100% | Orange/Red | Red (< 4%) |
|
|
32
|
+
|
|
33
|
+
## Manual Installation
|
|
34
|
+
|
|
35
|
+
If you prefer to install manually:
|
|
36
|
+
|
|
37
|
+
1. Copy `statusline.sh` to `~/.claude/statusline.sh`
|
|
38
|
+
2. Make it executable: `chmod +x ~/.claude/statusline.sh`
|
|
39
|
+
3. Add to `~/.claude/settings.json`:
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"status_line": {
|
|
44
|
+
"script": "/home/YOUR_USERNAME/.claude/statusline.sh"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Requirements
|
|
50
|
+
|
|
51
|
+
- Claude Code CLI
|
|
52
|
+
- `jq` (for JSON parsing)
|
|
53
|
+
- Bash
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
package/bin/install.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const CLAUDE_DIR = path.join(os.homedir(), '.claude');
|
|
8
|
+
const SETTINGS_FILE = path.join(CLAUDE_DIR, 'settings.json');
|
|
9
|
+
const STATUSLINE_DEST = path.join(CLAUDE_DIR, 'statusline.sh');
|
|
10
|
+
const STATUSLINE_SRC = path.join(__dirname, '..', 'statusline.sh');
|
|
11
|
+
|
|
12
|
+
console.log('\n🎨 Installing @buckits/claude-statusline...\n');
|
|
13
|
+
|
|
14
|
+
// Ensure ~/.claude directory exists
|
|
15
|
+
if (!fs.existsSync(CLAUDE_DIR)) {
|
|
16
|
+
console.log('📁 Creating ~/.claude directory...');
|
|
17
|
+
fs.mkdirSync(CLAUDE_DIR, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Copy statusline.sh
|
|
21
|
+
console.log('📄 Copying statusline.sh...');
|
|
22
|
+
fs.copyFileSync(STATUSLINE_SRC, STATUSLINE_DEST);
|
|
23
|
+
fs.chmodSync(STATUSLINE_DEST, '755');
|
|
24
|
+
|
|
25
|
+
// Update settings.json
|
|
26
|
+
console.log('⚙️ Updating settings.json...');
|
|
27
|
+
let settings = {};
|
|
28
|
+
|
|
29
|
+
if (fs.existsSync(SETTINGS_FILE)) {
|
|
30
|
+
try {
|
|
31
|
+
const content = fs.readFileSync(SETTINGS_FILE, 'utf8');
|
|
32
|
+
settings = JSON.parse(content);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
console.warn('⚠️ Could not parse existing settings.json, creating new one');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Set the status_line configuration
|
|
39
|
+
settings.status_line = settings.status_line || {};
|
|
40
|
+
settings.status_line.script = STATUSLINE_DEST;
|
|
41
|
+
|
|
42
|
+
fs.writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
43
|
+
|
|
44
|
+
console.log('\n✅ Installation complete!\n');
|
|
45
|
+
console.log('Your Claude Code statusline now features:');
|
|
46
|
+
console.log(' • Gradient progress bar (green → yellow → orange → red)');
|
|
47
|
+
console.log(' • Color-coded token count matching progress');
|
|
48
|
+
console.log(' • Auto-compact countdown with color warnings');
|
|
49
|
+
console.log(' • Git branch and project name display');
|
|
50
|
+
console.log('\nRestart Claude Code to see the new statusline.\n');
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@buckits/claude-statusline",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A gradient color statusline for Claude Code with progress bar, token counts, and auto-compact indicator",
|
|
5
|
+
"bin": {
|
|
6
|
+
"claude-statusline": "./bin/install.js"
|
|
7
|
+
},
|
|
8
|
+
"files": [
|
|
9
|
+
"bin/",
|
|
10
|
+
"statusline.sh"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"claude",
|
|
14
|
+
"claude-code",
|
|
15
|
+
"statusline",
|
|
16
|
+
"cli",
|
|
17
|
+
"terminal"
|
|
18
|
+
],
|
|
19
|
+
"author": "Buckits",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/Buckits/claude-statusline"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=14"
|
|
27
|
+
}
|
|
28
|
+
}
|
package/statusline.sh
ADDED
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Claude Code Status Line Script
|
|
4
|
+
# Read JSON input from stdin
|
|
5
|
+
|
|
6
|
+
input=$(cat)
|
|
7
|
+
|
|
8
|
+
# Extract values from JSON
|
|
9
|
+
cwd=$(echo "$input" | jq -r '.workspace.current_dir // .cwd // empty')
|
|
10
|
+
model=$(echo "$input" | jq -r '.model.display_name // empty')
|
|
11
|
+
|
|
12
|
+
# Extract token information from context_window
|
|
13
|
+
# The actual context usage includes cache tokens from prompt caching
|
|
14
|
+
total_input=$(echo "$input" | jq -r '.context_window.total_input_tokens // 0')
|
|
15
|
+
total_output=$(echo "$input" | jq -r '.context_window.total_output_tokens // 0')
|
|
16
|
+
cache_read=$(echo "$input" | jq -r '.context_window.current_usage.cache_read_input_tokens // 0')
|
|
17
|
+
|
|
18
|
+
# Total used = input + output + cached tokens being used
|
|
19
|
+
used_tokens=$((total_input + total_output + cache_read))
|
|
20
|
+
max_tokens=$(echo "$input" | jq -r '.context_window.context_window_size // 200000')
|
|
21
|
+
|
|
22
|
+
# Use the pre-calculated percentage if available (more accurate)
|
|
23
|
+
percent_precalc=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
|
|
24
|
+
if [ -n "$percent_precalc" ]; then
|
|
25
|
+
percent=$percent_precalc
|
|
26
|
+
# Recalculate used_tokens from percentage for display accuracy
|
|
27
|
+
used_tokens=$((max_tokens * percent / 100))
|
|
28
|
+
else
|
|
29
|
+
# Fallback: calculate percentage from tokens
|
|
30
|
+
if [ "$max_tokens" -gt 0 ] 2>/dev/null; then
|
|
31
|
+
percent=$((used_tokens * 100 / max_tokens))
|
|
32
|
+
else
|
|
33
|
+
percent=0
|
|
34
|
+
fi
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Clamp percent to 0-100
|
|
38
|
+
[ "$percent" -lt 0 ] && percent=0
|
|
39
|
+
[ "$percent" -gt 100 ] && percent=100
|
|
40
|
+
|
|
41
|
+
# Progress bar settings
|
|
42
|
+
bar_width=20
|
|
43
|
+
filled=$((percent * bar_width / 100))
|
|
44
|
+
empty=$((bar_width - filled))
|
|
45
|
+
|
|
46
|
+
# Get color for a specific bar position (0 to bar_width-1)
|
|
47
|
+
# Each bar position gets its own color based on progression
|
|
48
|
+
get_bar_color_for_position() {
|
|
49
|
+
local pos=$1
|
|
50
|
+
local total=$2
|
|
51
|
+
# Calculate percentage for this specific bar position
|
|
52
|
+
local bar_pct=$((pos * 100 / total))
|
|
53
|
+
|
|
54
|
+
if [ "$bar_pct" -le 33 ]; then
|
|
55
|
+
# Green range: 0-33%
|
|
56
|
+
# Bright green (46) → yellow-green (154) → green (34)
|
|
57
|
+
if [ "$bar_pct" -le 16 ]; then
|
|
58
|
+
echo "38;5;46" # Bright green
|
|
59
|
+
elif [ "$bar_pct" -le 25 ]; then
|
|
60
|
+
echo "38;5;118" # Green-yellow
|
|
61
|
+
else
|
|
62
|
+
echo "38;5;154" # Yellow-green
|
|
63
|
+
fi
|
|
64
|
+
elif [ "$bar_pct" -le 66 ]; then
|
|
65
|
+
# Orange range: 34-66%
|
|
66
|
+
# Yellow (226) → orange (214) → dark orange (208)
|
|
67
|
+
local adj_pct=$((bar_pct - 33))
|
|
68
|
+
if [ "$adj_pct" -le 11 ]; then
|
|
69
|
+
echo "38;5;226" # Yellow
|
|
70
|
+
elif [ "$adj_pct" -le 22 ]; then
|
|
71
|
+
echo "38;5;220" # Light orange
|
|
72
|
+
else
|
|
73
|
+
echo "38;5;214" # Orange
|
|
74
|
+
fi
|
|
75
|
+
else
|
|
76
|
+
# Red range: 67-100%
|
|
77
|
+
# Orange-red (208) → red (196) → dark red (160)
|
|
78
|
+
local adj_pct=$((bar_pct - 66))
|
|
79
|
+
if [ "$adj_pct" -le 11 ]; then
|
|
80
|
+
echo "38;5;208" # Orange-red
|
|
81
|
+
elif [ "$adj_pct" -le 22 ]; then
|
|
82
|
+
echo "38;5;202" # Red-orange
|
|
83
|
+
else
|
|
84
|
+
echo "38;5;196" # Bright red
|
|
85
|
+
fi
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# Build progress bar with gradient colors
|
|
90
|
+
# Track the color of the rightmost filled bar for the percentage text
|
|
91
|
+
bar="["
|
|
92
|
+
rightmost_color="38;5;46" # Default to bright green
|
|
93
|
+
for ((i=0; i<filled; i++)); do
|
|
94
|
+
bar_color=$(get_bar_color_for_position $i $bar_width)
|
|
95
|
+
rightmost_color=$bar_color # Keep updating to track the last one
|
|
96
|
+
bar+=$(printf "\033[${bar_color}m█\033[0m")
|
|
97
|
+
done
|
|
98
|
+
for ((i=0; i<empty; i++)); do
|
|
99
|
+
bar+="░"
|
|
100
|
+
done
|
|
101
|
+
bar+="]"
|
|
102
|
+
|
|
103
|
+
# Get git branch if in a git repo
|
|
104
|
+
git_branch=""
|
|
105
|
+
if [ -n "$cwd" ] && git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
|
|
106
|
+
git_branch=$(git -C "$cwd" branch --show-current 2>/dev/null)
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# Get project name from directory
|
|
110
|
+
project_name=""
|
|
111
|
+
if [ -n "$cwd" ]; then
|
|
112
|
+
project_name=$(basename "$cwd")
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Format tokens for display (e.g., 45.2k/200k)
|
|
116
|
+
format_tokens() {
|
|
117
|
+
local tokens=$1
|
|
118
|
+
# Use pure bash arithmetic to avoid bc dependency
|
|
119
|
+
if [ "$tokens" -ge 1000000 ]; then
|
|
120
|
+
local millions=$((tokens / 1000000))
|
|
121
|
+
local remainder=$((tokens % 1000000))
|
|
122
|
+
local decimal=$((remainder / 100000))
|
|
123
|
+
printf "%d.%dM" "$millions" "$decimal"
|
|
124
|
+
elif [ "$tokens" -ge 1000 ]; then
|
|
125
|
+
local thousands=$((tokens / 1000))
|
|
126
|
+
local remainder=$((tokens % 1000))
|
|
127
|
+
local decimal=$((remainder / 100))
|
|
128
|
+
printf "%d.%dk" "$thousands" "$decimal"
|
|
129
|
+
else
|
|
130
|
+
echo "$tokens"
|
|
131
|
+
fi
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
used_fmt=$(format_tokens $used_tokens)
|
|
135
|
+
max_fmt=$(format_tokens $max_tokens)
|
|
136
|
+
|
|
137
|
+
# Extract "until compact" percentage
|
|
138
|
+
# Auto-compact triggers at a threshold (appears to be around 78% usage / 22% remaining)
|
|
139
|
+
# The "until compact" value = remaining_percentage - threshold_remaining
|
|
140
|
+
# If threshold is 22%, and you have 24% remaining, then until_compact = 24% - 22% = 2%
|
|
141
|
+
|
|
142
|
+
# First check if there's an explicit field (unlikely but worth checking)
|
|
143
|
+
until_compact=$(echo "$input" | jq -r '.context_window.until_compact // .context_window.until_auto_compact // empty')
|
|
144
|
+
|
|
145
|
+
if [ -z "$until_compact" ]; then
|
|
146
|
+
# Calculate based on auto-compact threshold
|
|
147
|
+
# Auto-compact threshold appears to be 22% remaining (78% used)
|
|
148
|
+
AUTO_COMPACT_THRESHOLD=22
|
|
149
|
+
|
|
150
|
+
remaining_pct=$(echo "$input" | jq -r '.context_window.remaining_percentage // 0')
|
|
151
|
+
|
|
152
|
+
if [ "$remaining_pct" -gt "$AUTO_COMPACT_THRESHOLD" ]; then
|
|
153
|
+
until_compact=$((remaining_pct - AUTO_COMPACT_THRESHOLD))
|
|
154
|
+
else
|
|
155
|
+
# Already past threshold or at it
|
|
156
|
+
until_compact=0
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
compact_indicator=""
|
|
161
|
+
compact_color="38;5;46"
|
|
162
|
+
if [ -n "$until_compact" ] && [ "$until_compact" != "null" ] && [ "$until_compact" != "0" ]; then
|
|
163
|
+
if [ "$until_compact" -ge 25 ]; then
|
|
164
|
+
compact_color="38;5;46"
|
|
165
|
+
elif [ "$until_compact" -ge 20 ]; then
|
|
166
|
+
compact_color="38;5;154"
|
|
167
|
+
elif [ "$until_compact" -ge 15 ]; then
|
|
168
|
+
compact_color="38;5;226"
|
|
169
|
+
elif [ "$until_compact" -ge 10 ]; then
|
|
170
|
+
compact_color="38;5;220"
|
|
171
|
+
elif [ "$until_compact" -ge 7 ]; then
|
|
172
|
+
compact_color="38;5;214"
|
|
173
|
+
elif [ "$until_compact" -ge 4 ]; then
|
|
174
|
+
compact_color="38;5;208"
|
|
175
|
+
else
|
|
176
|
+
compact_color="38;5;196"
|
|
177
|
+
fi
|
|
178
|
+
compact_indicator=$(printf "⚡%d%% until compact" "$until_compact")
|
|
179
|
+
fi
|
|
180
|
+
|
|
181
|
+
# Build the status line in requested order:
|
|
182
|
+
# Model Name | Progress bar with % | Tokens | Git branch | Project name
|
|
183
|
+
status=""
|
|
184
|
+
|
|
185
|
+
# 1. Model name (cyan)
|
|
186
|
+
if [ -n "$model" ]; then
|
|
187
|
+
status+=$(printf "\033[1;36m%s\033[0m" "$model")
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
# 2. Progress bar
|
|
191
|
+
status+=$(printf " %s" "$bar")
|
|
192
|
+
|
|
193
|
+
# 3. Tokens with gradient color on used, cyan on total
|
|
194
|
+
# Used tokens get gradient color matching progress bar (low=green, high=red)
|
|
195
|
+
# The rightmost_color already has the gradient based on current usage
|
|
196
|
+
# Slash and max tokens use cyan to match model name
|
|
197
|
+
status+=$(printf " \033[${rightmost_color}m%s\033[1;36m/%s\033[0m" "$used_fmt" "$max_fmt")
|
|
198
|
+
|
|
199
|
+
# 3.5. Remaining context percentage (gradient color)
|
|
200
|
+
if [ -n "$compact_indicator" ]; then
|
|
201
|
+
# Don't use printf %s with the indicator as it contains % characters
|
|
202
|
+
status+=" $(printf "\033[${compact_color}m")${compact_indicator}$(printf "\033[0m")"
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
# 4. Git branch (magenta)
|
|
206
|
+
if [ -n "$git_branch" ]; then
|
|
207
|
+
status+=$(printf " \033[1;35m %s\033[0m" "$git_branch")
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
# 5. Project name (blue)
|
|
211
|
+
if [ -n "$project_name" ]; then
|
|
212
|
+
status+=$(printf " \033[1;34m%s\033[0m" "$project_name")
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# Extract context information for second line
|
|
216
|
+
skills_count=$(echo "$input" | jq -r '[.context.skills // [] | length] | .[0] // 0')
|
|
217
|
+
agents_count=$(echo "$input" | jq -r '[.context.agents // [] | length] | .[0] // 0')
|
|
218
|
+
mcp_tools_count=$(echo "$input" | jq -r '[.context.mcp_tools // [] | length] | .[0] // 0')
|
|
219
|
+
|
|
220
|
+
# Extract token counts for context items
|
|
221
|
+
skills_tokens=$(echo "$input" | jq -r '.context.skills_tokens // 0')
|
|
222
|
+
agents_tokens=$(echo "$input" | jq -r '.context.agents_tokens // 0')
|
|
223
|
+
mcp_tokens=$(echo "$input" | jq -r '.context.mcp_tokens // 0')
|
|
224
|
+
|
|
225
|
+
# Format tokens for context items
|
|
226
|
+
skills_tokens_fmt=$(format_tokens $skills_tokens)
|
|
227
|
+
agents_tokens_fmt=$(format_tokens $agents_tokens)
|
|
228
|
+
mcp_tokens_fmt=$(format_tokens $mcp_tokens)
|
|
229
|
+
|
|
230
|
+
# Build second line with context information
|
|
231
|
+
status2=""
|
|
232
|
+
|
|
233
|
+
# Skills (yellow)
|
|
234
|
+
if [ "$skills_count" -gt 0 ]; then
|
|
235
|
+
status2+=$(printf "\033[1;33mSkills: %d (%s)\033[0m" "$skills_count" "$skills_tokens_fmt")
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
# Agents (green)
|
|
239
|
+
if [ "$agents_count" -gt 0 ]; then
|
|
240
|
+
[ -n "$status2" ] && status2+=" "
|
|
241
|
+
status2+=$(printf "\033[1;32mAgents: %d (%s)\033[0m" "$agents_count" "$agents_tokens_fmt")
|
|
242
|
+
fi
|
|
243
|
+
|
|
244
|
+
# MCP Tools (blue)
|
|
245
|
+
if [ "$mcp_tools_count" -gt 0 ]; then
|
|
246
|
+
[ -n "$status2" ] && status2+=" "
|
|
247
|
+
status2+=$(printf "\033[1;34mMCP: %d (%s)\033[0m" "$mcp_tools_count" "$mcp_tokens_fmt")
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# Output the status lines
|
|
251
|
+
echo "$status"
|
|
252
|
+
if [ -n "$status2" ]; then
|
|
253
|
+
echo "$status2"
|
|
254
|
+
fi
|