@buckits/claude-statusline 1.0.0 → 2.0.1
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 +49 -16
- package/package.json +6 -3
- package/statusline.sh +213 -60
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @buckits/claude-statusline
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A beautiful 2-line dashboard statusline for Claude Code with gradient progress bar, compact threshold marker, git status indicators, and cost tracking.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -10,30 +10,62 @@ npx @buckits/claude-statusline
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
-
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
13
|
+
- **2-Line Dashboard Layout** - Clean separation of AI info and project info
|
|
14
|
+
- **Gradient Progress Bar** - 50 segments (4k tokens each) that smoothly transition green → yellow → orange → red
|
|
15
|
+
- **⚡ Compact Threshold Marker** - Red lightning bolt shows exactly where auto-compact triggers (78%)
|
|
16
|
+
- **Session Cost Tracking** - See your running cost in real-time
|
|
17
|
+
- **Git Status Indicators**:
|
|
18
|
+
- `✓` Green checkmark = clean (all committed)
|
|
19
|
+
- `●` Yellow dot = unstaged changes
|
|
20
|
+
- `✚` Green plus = staged changes ready to commit
|
|
21
|
+
- `●✚` Both = partial commit state
|
|
22
|
+
- **Ahead/Behind Tracking** - `↑5 ↓2` shows commits ahead/behind remote
|
|
23
|
+
- **Visual Icons** - 🤖 for AI line, 📁 for project line
|
|
18
24
|
|
|
19
25
|
## Screenshot
|
|
20
26
|
|
|
21
27
|
```
|
|
22
|
-
Opus 4.5 [
|
|
28
|
+
🤖 Opus 4.5 ($14.61) │ [████████████████████░░░░░░░░░░░░░░░░░░░⚡░░░░░░░░░░░] 80k/200k
|
|
29
|
+
📁 trellis POC ✓ → origin/POC ↑15
|
|
23
30
|
```
|
|
24
31
|
|
|
25
|
-
## What
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
|
31
|
-
|
|
|
32
|
+
## What Each Element Means
|
|
33
|
+
|
|
34
|
+
### Line 1 - AI Session Info
|
|
35
|
+
| Element | Description |
|
|
36
|
+
|---------|-------------|
|
|
37
|
+
| 🤖 | AI indicator |
|
|
38
|
+
| `Opus 4.5` | Current model (cyan) |
|
|
39
|
+
| `($14.61)` | Session cost (green) |
|
|
40
|
+
| `│` | Separator |
|
|
41
|
+
| `[███░░░⚡░░░]` | Context usage with compact threshold |
|
|
42
|
+
| `80k/200k` | Tokens used / total |
|
|
43
|
+
|
|
44
|
+
### Line 2 - Project Info
|
|
45
|
+
| Element | Description |
|
|
46
|
+
|---------|-------------|
|
|
47
|
+
| 📁 | Project indicator |
|
|
48
|
+
| `trellis` | Project name (cyan) |
|
|
49
|
+
| `POC` | Current branch (magenta) |
|
|
50
|
+
| `✓●✚` | Git status (clean/unstaged/staged) |
|
|
51
|
+
| `→` | Points to tracking branch |
|
|
52
|
+
| `origin/POC` | Remote tracking branch (blue) |
|
|
53
|
+
| `↑15` | Commits ahead (green) |
|
|
54
|
+
| `↓3` | Commits behind (red) |
|
|
55
|
+
|
|
56
|
+
## Progress Bar Colors
|
|
57
|
+
|
|
58
|
+
The bar gradient is calculated relative to the ⚡ threshold (not total capacity):
|
|
59
|
+
|
|
60
|
+
| Distance to ⚡ | Color |
|
|
61
|
+
|---------------|-------|
|
|
62
|
+
| Far (safe) | Bright green |
|
|
63
|
+
| Approaching | Yellow |
|
|
64
|
+
| Close | Orange |
|
|
65
|
+
| At threshold | Red |
|
|
32
66
|
|
|
33
67
|
## Manual Installation
|
|
34
68
|
|
|
35
|
-
If you prefer to install manually:
|
|
36
|
-
|
|
37
69
|
1. Copy `statusline.sh` to `~/.claude/statusline.sh`
|
|
38
70
|
2. Make it executable: `chmod +x ~/.claude/statusline.sh`
|
|
39
71
|
3. Add to `~/.claude/settings.json`:
|
|
@@ -51,6 +83,7 @@ If you prefer to install manually:
|
|
|
51
83
|
- Claude Code CLI
|
|
52
84
|
- `jq` (for JSON parsing)
|
|
53
85
|
- Bash
|
|
86
|
+
- Git (for git status features)
|
|
54
87
|
|
|
55
88
|
## License
|
|
56
89
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buckits/claude-statusline",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "2.0.1",
|
|
4
|
+
"description": "A beautiful 2-line dashboard statusline for Claude Code with gradient progress bar, compact threshold marker, git status indicators, and cost tracking",
|
|
5
5
|
"bin": {
|
|
6
|
-
"claude-statusline": "
|
|
6
|
+
"buckits-claude-statusline": "bin/install.js"
|
|
7
|
+
},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"postinstall": "node bin/install.js"
|
|
7
10
|
},
|
|
8
11
|
"files": [
|
|
9
12
|
"bin/",
|
package/statusline.sh
CHANGED
|
@@ -38,8 +38,8 @@ fi
|
|
|
38
38
|
[ "$percent" -lt 0 ] && percent=0
|
|
39
39
|
[ "$percent" -gt 100 ] && percent=100
|
|
40
40
|
|
|
41
|
-
# Progress bar settings
|
|
42
|
-
bar_width=
|
|
41
|
+
# Progress bar settings - 50 squares (4k tokens each for 200k context)
|
|
42
|
+
bar_width=50
|
|
43
43
|
filled=$((percent * bar_width / 100))
|
|
44
44
|
empty=$((bar_width - filled))
|
|
45
45
|
|
|
@@ -100,10 +100,64 @@ for ((i=0; i<empty; i++)); do
|
|
|
100
100
|
done
|
|
101
101
|
bar+="]"
|
|
102
102
|
|
|
103
|
-
# Get git
|
|
103
|
+
# Get git information if in a git repo
|
|
104
104
|
git_branch=""
|
|
105
|
+
git_remote=""
|
|
105
106
|
if [ -n "$cwd" ] && git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
|
|
106
107
|
git_branch=$(git -C "$cwd" branch --show-current 2>/dev/null)
|
|
108
|
+
|
|
109
|
+
# Get the upstream tracking branch
|
|
110
|
+
upstream=$(git -C "$cwd" rev-parse --abbrev-ref --symbolic-full-name @{upstream} 2>/dev/null)
|
|
111
|
+
if [ -n "$upstream" ]; then
|
|
112
|
+
# upstream will be in format like "origin/POC" or "origin/main"
|
|
113
|
+
git_remote="$upstream"
|
|
114
|
+
fi
|
|
115
|
+
|
|
116
|
+
# Get ahead/behind counts
|
|
117
|
+
git_ahead=""
|
|
118
|
+
git_behind=""
|
|
119
|
+
if [ -n "$upstream" ]; then
|
|
120
|
+
# Get number of commits ahead/behind
|
|
121
|
+
ahead_behind=$(git -C "$cwd" rev-list --left-right --count HEAD...$upstream 2>/dev/null)
|
|
122
|
+
if [ -n "$ahead_behind" ]; then
|
|
123
|
+
ahead=$(echo "$ahead_behind" | awk '{print $1}')
|
|
124
|
+
behind=$(echo "$ahead_behind" | awk '{print $2}')
|
|
125
|
+
[ "$ahead" -gt 0 ] && git_ahead="$ahead"
|
|
126
|
+
[ "$behind" -gt 0 ] && git_behind="$behind"
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Get git status (dirty/staged indicators)
|
|
131
|
+
git_status_indicator=""
|
|
132
|
+
if git -C "$cwd" rev-parse --git-dir >/dev/null 2>&1; then
|
|
133
|
+
porcelain=$(git -C "$cwd" status --porcelain 2>/dev/null)
|
|
134
|
+
|
|
135
|
+
has_unstaged=false
|
|
136
|
+
has_staged=false
|
|
137
|
+
|
|
138
|
+
if [ -n "$porcelain" ]; then
|
|
139
|
+
# Check for staged changes (first column not space)
|
|
140
|
+
if echo "$porcelain" | grep -q '^[MADRC]'; then
|
|
141
|
+
has_staged=true
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# Check for unstaged changes (second column not space, or untracked files)
|
|
145
|
+
if echo "$porcelain" | grep -q '^\?\?' || echo "$porcelain" | grep -q '^.[MD]'; then
|
|
146
|
+
has_unstaged=true
|
|
147
|
+
fi
|
|
148
|
+
fi
|
|
149
|
+
|
|
150
|
+
# Build status indicator
|
|
151
|
+
if [ "$has_unstaged" = true ] && [ "$has_staged" = true ]; then
|
|
152
|
+
git_status_indicator=$(printf "\033[1;33m●\033[1;32m✚\033[0m") # Both
|
|
153
|
+
elif [ "$has_unstaged" = true ]; then
|
|
154
|
+
git_status_indicator=$(printf "\033[1;33m●\033[0m") # Unstaged (yellow)
|
|
155
|
+
elif [ "$has_staged" = true ]; then
|
|
156
|
+
git_status_indicator=$(printf "\033[1;32m✚\033[0m") # Staged (green)
|
|
157
|
+
else
|
|
158
|
+
git_status_indicator=$(printf "\033[1;32m✓\033[0m") # Clean (green)
|
|
159
|
+
fi
|
|
160
|
+
fi
|
|
107
161
|
fi
|
|
108
162
|
|
|
109
163
|
# Get project name from directory
|
|
@@ -131,8 +185,49 @@ format_tokens() {
|
|
|
131
185
|
fi
|
|
132
186
|
}
|
|
133
187
|
|
|
188
|
+
# Format tokens without decimals (e.g., 72k/200k)
|
|
189
|
+
format_tokens_int() {
|
|
190
|
+
local tokens=$1
|
|
191
|
+
if [ "$tokens" -ge 1000000 ]; then
|
|
192
|
+
local millions=$((tokens / 1000000))
|
|
193
|
+
printf "%dM" "$millions"
|
|
194
|
+
elif [ "$tokens" -ge 1000 ]; then
|
|
195
|
+
local thousands=$((tokens / 1000))
|
|
196
|
+
printf "%dk" "$thousands"
|
|
197
|
+
else
|
|
198
|
+
echo "$tokens"
|
|
199
|
+
fi
|
|
200
|
+
}
|
|
201
|
+
|
|
134
202
|
used_fmt=$(format_tokens $used_tokens)
|
|
135
203
|
max_fmt=$(format_tokens $max_tokens)
|
|
204
|
+
used_fmt_int=$(format_tokens_int $used_tokens)
|
|
205
|
+
max_fmt_int=$(format_tokens_int $max_tokens)
|
|
206
|
+
|
|
207
|
+
# Extract cost information
|
|
208
|
+
cost_usd=$(echo "$input" | jq -r '.cost.total_cost_usd // empty')
|
|
209
|
+
cost_display=""
|
|
210
|
+
if [ -n "$cost_usd" ] && [ "$cost_usd" != "null" ]; then
|
|
211
|
+
# Format cost to 2 decimal places
|
|
212
|
+
cost_display=$(printf "\$%.2f" "$cost_usd")
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# Extract tools/skills/agents counts
|
|
216
|
+
skills_count=$(echo "$input" | jq -r '.context.skills // [] | length')
|
|
217
|
+
agents_count=$(echo "$input" | jq -r '.context.agents // [] | length')
|
|
218
|
+
mcp_tools_count=$(echo "$input" | jq -r '.context.mcp_tools // [] | length')
|
|
219
|
+
total_tools=$((skills_count + agents_count + mcp_tools_count))
|
|
220
|
+
tools_display=""
|
|
221
|
+
if [ "$total_tools" -gt 0 ]; then
|
|
222
|
+
tools_display=$(printf "🔧 %d" "$total_tools")
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# Extract background tasks (check for various possible field names)
|
|
226
|
+
bg_tasks=$(echo "$input" | jq -r '.background_tasks // .running_agents // .active_tasks // empty | length')
|
|
227
|
+
bg_display=""
|
|
228
|
+
if [ -n "$bg_tasks" ] && [ "$bg_tasks" != "null" ] && [ "$bg_tasks" -gt 0 ]; then
|
|
229
|
+
bg_display=$(printf "⏳ %d" "$bg_tasks")
|
|
230
|
+
fi
|
|
136
231
|
|
|
137
232
|
# Extract "until compact" percentage
|
|
138
233
|
# Auto-compact triggers at a threshold (appears to be around 78% usage / 22% remaining)
|
|
@@ -175,80 +270,138 @@ if [ -n "$until_compact" ] && [ "$until_compact" != "null" ] && [ "$until_compac
|
|
|
175
270
|
else
|
|
176
271
|
compact_color="38;5;196"
|
|
177
272
|
fi
|
|
178
|
-
compact_indicator=$(printf "⚡%d%% until compact" "$until_compact")
|
|
179
|
-
fi
|
|
180
273
|
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
|
|
274
|
+
# Calculate tokens until compact threshold
|
|
275
|
+
# Auto-compact threshold is 22% remaining (78% used)
|
|
276
|
+
# Tokens until compact = until_compact * context_window_size / 100
|
|
277
|
+
remaining_pct=$(echo "$input" | jq -r '.context_window.remaining_percentage // 0')
|
|
278
|
+
tokens_until_compact=$((until_compact * max_tokens / 100))
|
|
279
|
+
tokens_until_compact_fmt=$(format_tokens $tokens_until_compact)
|
|
184
280
|
|
|
185
|
-
#
|
|
186
|
-
|
|
187
|
-
|
|
281
|
+
# Build indicator with tokens primary (gradient color) and percentage in parens (dim)
|
|
282
|
+
compact_indicator_text=$(printf "⚡%s until compact" "$tokens_until_compact_fmt")
|
|
283
|
+
compact_indicator_pct=$(printf "(%d%%)" "$until_compact")
|
|
188
284
|
fi
|
|
189
285
|
|
|
190
|
-
#
|
|
191
|
-
|
|
286
|
+
# ==========================================
|
|
287
|
+
# 2-LINE DASHBOARD LAYOUT
|
|
288
|
+
# ==========================================
|
|
192
289
|
|
|
193
|
-
#
|
|
194
|
-
#
|
|
195
|
-
|
|
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")
|
|
290
|
+
# LINE 1: Model + Context
|
|
291
|
+
# Format: Opus 4.5 ($12.01) [███████░░░░░░░░⚡░░░░░] 74k/200k
|
|
292
|
+
line1=""
|
|
198
293
|
|
|
199
|
-
#
|
|
200
|
-
if [ -n "$
|
|
201
|
-
|
|
202
|
-
status+=" $(printf "\033[${compact_color}m")${compact_indicator}$(printf "\033[0m")"
|
|
294
|
+
# Robot icon and model name in cyan
|
|
295
|
+
if [ -n "$model" ]; then
|
|
296
|
+
line1+=$(printf "🤖 \033[1;36m%s\033[0m" "$model")
|
|
203
297
|
fi
|
|
204
298
|
|
|
205
|
-
#
|
|
206
|
-
if [ -n "$
|
|
207
|
-
|
|
299
|
+
# Add cost after model name (bright green)
|
|
300
|
+
if [ -n "$cost_display" ]; then
|
|
301
|
+
line1+=$(printf " \033[1;32m(%s)\033[0m" "$cost_display")
|
|
208
302
|
fi
|
|
209
303
|
|
|
210
|
-
#
|
|
211
|
-
|
|
212
|
-
status+=$(printf " \033[1;34m%s\033[0m" "$project_name")
|
|
213
|
-
fi
|
|
304
|
+
# Add subtle separator between cost and progress bar
|
|
305
|
+
line1+=$(printf " \033[2;37m│\033[0m")
|
|
214
306
|
|
|
215
|
-
#
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
307
|
+
# Build progress bar for line 1
|
|
308
|
+
# Calculate compact threshold position (78% of bar = 22% remaining)
|
|
309
|
+
AUTO_COMPACT_THRESHOLD=22
|
|
310
|
+
compact_threshold_pct=$((100 - AUTO_COMPACT_THRESHOLD)) # 78%
|
|
311
|
+
threshold_position=$((compact_threshold_pct * bar_width / 100))
|
|
219
312
|
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
mcp_tokens=$(echo "$input" | jq -r '.context.mcp_tokens // 0')
|
|
313
|
+
# Build unified progress bar with per-bar gradient toward threshold
|
|
314
|
+
unified_bar="["
|
|
315
|
+
unified_rightmost_color="38;5;46" # Default green
|
|
224
316
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
317
|
+
for ((i=0; i<bar_width; i++)); do
|
|
318
|
+
if [ "$i" -eq "$threshold_position" ]; then
|
|
319
|
+
# Insert red lightning bolt threshold marker
|
|
320
|
+
unified_bar+=$(printf "\033[0;31m⚡\033[0m")
|
|
321
|
+
fi
|
|
229
322
|
|
|
230
|
-
|
|
231
|
-
|
|
323
|
+
if [ "$i" -lt "$filled" ]; then
|
|
324
|
+
# Calculate color for this specific bar position
|
|
325
|
+
# Gradient from green (position 0) to red (threshold position)
|
|
326
|
+
if [ "$threshold_position" -gt 0 ]; then
|
|
327
|
+
bar_position_pct=$((i * 100 / threshold_position))
|
|
328
|
+
else
|
|
329
|
+
bar_position_pct=0
|
|
330
|
+
fi
|
|
232
331
|
|
|
233
|
-
#
|
|
234
|
-
if [ "$
|
|
235
|
-
|
|
236
|
-
|
|
332
|
+
# Map position percentage to gradient colors
|
|
333
|
+
if [ "$bar_position_pct" -le 20 ]; then
|
|
334
|
+
bar_color="38;5;46" # Bright green
|
|
335
|
+
elif [ "$bar_position_pct" -le 40 ]; then
|
|
336
|
+
bar_color="38;5;118" # Green-yellow
|
|
337
|
+
elif [ "$bar_position_pct" -le 60 ]; then
|
|
338
|
+
bar_color="38;5;154" # Yellow-green
|
|
339
|
+
elif [ "$bar_position_pct" -le 70 ]; then
|
|
340
|
+
bar_color="38;5;226" # Yellow
|
|
341
|
+
elif [ "$bar_position_pct" -le 80 ]; then
|
|
342
|
+
bar_color="38;5;220" # Light orange
|
|
343
|
+
elif [ "$bar_position_pct" -le 90 ]; then
|
|
344
|
+
bar_color="38;5;214" # Orange
|
|
345
|
+
elif [ "$bar_position_pct" -le 95 ]; then
|
|
346
|
+
bar_color="38;5;208" # Orange-red
|
|
347
|
+
else
|
|
348
|
+
bar_color="38;5;196" # Red
|
|
349
|
+
fi
|
|
237
350
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
fi
|
|
351
|
+
unified_rightmost_color=$bar_color
|
|
352
|
+
unified_bar+=$(printf "\033[${bar_color}m█\033[0m")
|
|
353
|
+
else
|
|
354
|
+
unified_bar+="░"
|
|
355
|
+
fi
|
|
356
|
+
done
|
|
357
|
+
|
|
358
|
+
unified_bar+="]"
|
|
359
|
+
|
|
360
|
+
# Add progress bar and tokens to line 1
|
|
361
|
+
line1+=$(printf " %s \033[${unified_rightmost_color}m%s\033[0m\033[1;36m/%s\033[0m" "$unified_bar" "$used_fmt_int" "$max_fmt_int")
|
|
362
|
+
|
|
363
|
+
# LINE 2: Project/Git Info
|
|
364
|
+
# Format: 📁 trellis POC → origin/POC ↑11
|
|
365
|
+
line2=""
|
|
243
366
|
|
|
244
|
-
#
|
|
245
|
-
if [ "$
|
|
246
|
-
|
|
247
|
-
status2+=$(printf "\033[1;34mMCP: %d (%s)\033[0m" "$mcp_tools_count" "$mcp_tokens_fmt")
|
|
367
|
+
# Folder icon and project name in cyan
|
|
368
|
+
if [ -n "$project_name" ]; then
|
|
369
|
+
line2+=$(printf "📁 \033[1;36m%s\033[0m" "$project_name")
|
|
248
370
|
fi
|
|
249
371
|
|
|
250
|
-
#
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
372
|
+
# Git branch and tracking
|
|
373
|
+
if [ -n "$git_branch" ]; then
|
|
374
|
+
[ -n "$line2" ] && line2+=" "
|
|
375
|
+
|
|
376
|
+
# Branch in magenta
|
|
377
|
+
line2+=$(printf "\033[1;35m%s\033[0m" "$git_branch")
|
|
378
|
+
|
|
379
|
+
# Git status indicator (after branch name)
|
|
380
|
+
if [ -n "$git_status_indicator" ]; then
|
|
381
|
+
line2+=$(printf " %s" "$git_status_indicator")
|
|
382
|
+
fi
|
|
383
|
+
|
|
384
|
+
# Arrow and tracking
|
|
385
|
+
line2+=$(printf " \033[2;37m→\033[0m")
|
|
386
|
+
|
|
387
|
+
if [ -n "$git_remote" ]; then
|
|
388
|
+
# Tracking branch in blue
|
|
389
|
+
line2+=$(printf " \033[1;34m%s\033[0m" "$git_remote")
|
|
390
|
+
|
|
391
|
+
# Ahead/behind indicators
|
|
392
|
+
if [ -n "$git_ahead" ] || [ -n "$git_behind" ]; then
|
|
393
|
+
line2+=" "
|
|
394
|
+
[ -n "$git_ahead" ] && line2+=$(printf "\033[0;32m↑%s\033[0m" "$git_ahead")
|
|
395
|
+
if [ -n "$git_behind" ]; then
|
|
396
|
+
[ -n "$git_ahead" ] && line2+=" "
|
|
397
|
+
line2+=$(printf "\033[0;31m↓%s\033[0m" "$git_behind")
|
|
398
|
+
fi
|
|
399
|
+
fi
|
|
400
|
+
else
|
|
401
|
+
line2+=$(printf " \033[2;37m(no upstream)\033[0m")
|
|
402
|
+
fi
|
|
254
403
|
fi
|
|
404
|
+
|
|
405
|
+
# Output the 2-line dashboard
|
|
406
|
+
echo "$line1"
|
|
407
|
+
echo "$line2"
|