skill-statusline 2.1.1 → 2.2.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/bin/cli.js +929 -929
- package/bin/cli.js.bak +837 -0
- package/bin/statusline.sh +139 -121
- package/lib/core.sh +408 -382
- package/lib/helpers.sh +119 -81
- package/package.json +52 -52
package/bin/statusline.sh
CHANGED
|
@@ -1,121 +1,139 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# skill-statusline v2.0 — Entry point
|
|
3
|
-
# Delegates to modular v2 engine if installed, falls back to v1 inline
|
|
4
|
-
|
|
5
|
-
STATUSLINE_DIR="${HOME}/.claude/statusline"
|
|
6
|
-
|
|
7
|
-
if [ -f "${STATUSLINE_DIR}/core.sh" ]; then
|
|
8
|
-
# v2: modular engine with themes, layouts, accurate context
|
|
9
|
-
exec bash "${STATUSLINE_DIR}/core.sh"
|
|
10
|
-
fi
|
|
11
|
-
|
|
12
|
-
# ── v1 fallback (inline legacy script) ──
|
|
13
|
-
# This runs if only statusline-command.sh was copied without the statusline/ directory
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
[
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# skill-statusline v2.0 — Entry point
|
|
3
|
+
# Delegates to modular v2 engine if installed, falls back to v1 inline
|
|
4
|
+
|
|
5
|
+
STATUSLINE_DIR="${HOME}/.claude/statusline"
|
|
6
|
+
|
|
7
|
+
if [ -f "${STATUSLINE_DIR}/core.sh" ]; then
|
|
8
|
+
# v2: modular engine with themes, layouts, accurate context
|
|
9
|
+
exec bash "${STATUSLINE_DIR}/core.sh"
|
|
10
|
+
fi
|
|
11
|
+
|
|
12
|
+
# ── v1 fallback (inline legacy script) ──
|
|
13
|
+
# This runs if only statusline-command.sh was copied without the statusline/ directory
|
|
14
|
+
|
|
15
|
+
# Safety: kill script after 3 seconds to prevent hangs
|
|
16
|
+
_sl_cleanup() { exit 0; }
|
|
17
|
+
trap '_sl_cleanup' ALRM 2>/dev/null
|
|
18
|
+
( sleep 3 && kill -ALRM $$ 2>/dev/null ) &
|
|
19
|
+
_SL_WD_PID=$!
|
|
20
|
+
|
|
21
|
+
# Read stdin with protection against missing pipe
|
|
22
|
+
if [ -t 0 ]; then
|
|
23
|
+
kill "$_SL_WD_PID" 2>/dev/null; wait "$_SL_WD_PID" 2>/dev/null
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
input=$(timeout 2 cat 2>/dev/null || cat 2>/dev/null)
|
|
27
|
+
if [ -z "$input" ]; then
|
|
28
|
+
kill "$_SL_WD_PID" 2>/dev/null; wait "$_SL_WD_PID" 2>/dev/null
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
json_val() {
|
|
33
|
+
echo "$input" | grep -o "\"$1\"[[:space:]]*:[[:space:]]*\"[^\"]*\"" | head -1 | sed 's/.*:.*"\(.*\)"/\1/'
|
|
34
|
+
}
|
|
35
|
+
json_num() {
|
|
36
|
+
echo "$input" | grep -o "\"$1\"[[:space:]]*:[[:space:]]*[0-9.]*" | head -1 | sed 's/.*:[[:space:]]*//'
|
|
37
|
+
}
|
|
38
|
+
to_fwd() {
|
|
39
|
+
echo "$1" | tr '\\' '/' | sed 's|//\+|/|g'
|
|
40
|
+
}
|
|
41
|
+
rpad() {
|
|
42
|
+
local str="$1" w="$2"
|
|
43
|
+
local plain
|
|
44
|
+
plain=$(printf '%b' "$str" | sed $'s/\033\\[[0-9;]*m//g')
|
|
45
|
+
local vlen=${#plain}
|
|
46
|
+
local need=$(( w - vlen ))
|
|
47
|
+
printf '%b' "$str"
|
|
48
|
+
[ "$need" -gt 0 ] && printf "%${need}s" ""
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
RST='\033[0m'; BOLD='\033[1m'
|
|
52
|
+
CYAN='\033[38;2;6;182;212m'; PURPLE='\033[38;2;168;85;247m'
|
|
53
|
+
GREEN='\033[38;2;34;197;94m'; YELLOW='\033[38;2;245;158;11m'
|
|
54
|
+
RED='\033[38;2;239;68;68m'; ORANGE='\033[38;2;251;146;60m'
|
|
55
|
+
WHITE='\033[38;2;228;228;231m'; PINK='\033[38;2;236;72;153m'
|
|
56
|
+
SEP_C='\033[38;2;55;55;62m'; DIM_BAR='\033[38;2;40;40;45m'
|
|
57
|
+
|
|
58
|
+
cwd=$(json_val "current_dir")
|
|
59
|
+
[ -z "$cwd" ] && cwd=$(json_val "cwd")
|
|
60
|
+
if [ -z "$cwd" ]; then dir_label="~"; clean_cwd=""
|
|
61
|
+
else
|
|
62
|
+
clean_cwd=$(to_fwd "$cwd")
|
|
63
|
+
dir_label=$(echo "$clean_cwd" | awk -F'/' '{if(NF>3) print $(NF-2)"/"$(NF-1)"/"$NF; else if(NF>2) print $(NF-1)"/"$NF; else print $0}')
|
|
64
|
+
[ -z "$dir_label" ] && dir_label="~"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
model_display=$(json_val "display_name"); model_id=$(json_val "id")
|
|
68
|
+
[ -z "$model_display" ] && model_display="unknown"
|
|
69
|
+
model_ver=""; [ -n "$model_id" ] && model_ver=$(echo "$model_id" | sed -n 's/.*-\([0-9]*\)-\([0-9]*\)$/\1.\2/p')
|
|
70
|
+
if [ -n "$model_ver" ] && ! echo "$model_display" | grep -q '[0-9]'; then model_full="${model_display} ${model_ver}"; else model_full="$model_display"; fi
|
|
71
|
+
|
|
72
|
+
pct=$(json_num "used_percentage"); [ -z "$pct" ] && pct="0"; pct=$(echo "$pct" | cut -d. -f1)
|
|
73
|
+
if [ "$pct" -gt 75 ] 2>/dev/null; then CTX_CLR="$RED"
|
|
74
|
+
elif [ "$pct" -gt 40 ] 2>/dev/null; then CTX_CLR="$ORANGE"
|
|
75
|
+
else CTX_CLR="$WHITE"; fi
|
|
76
|
+
BAR_WIDTH=40; filled=$(( pct * BAR_WIDTH / 100 )); [ "$filled" -gt "$BAR_WIDTH" ] && filled=$BAR_WIDTH
|
|
77
|
+
empty=$(( BAR_WIDTH - filled )); bar_filled=""; bar_empty=""
|
|
78
|
+
i=0; while [ $i -lt $filled ]; do bar_filled="${bar_filled}█"; i=$((i+1)); done
|
|
79
|
+
i=0; while [ $i -lt $empty ]; do bar_empty="${bar_empty}░"; i=$((i+1)); done
|
|
80
|
+
ctx_bar="${CTX_CLR}${bar_filled}${RST}${DIM_BAR}${bar_empty}${RST} ${CTX_CLR}${pct}%${RST}"
|
|
81
|
+
|
|
82
|
+
branch="no-git"; gh_user=""; gh_repo=""; git_dirty=""
|
|
83
|
+
if [ -n "$clean_cwd" ]; then
|
|
84
|
+
branch=$(timeout 2 git --no-optional-locks -C "$clean_cwd" symbolic-ref --short HEAD 2>/dev/null)
|
|
85
|
+
[ -z "$branch" ] && branch=$(timeout 2 git --no-optional-locks -C "$clean_cwd" rev-parse --short HEAD 2>/dev/null)
|
|
86
|
+
if [ -n "$branch" ]; then
|
|
87
|
+
remote_url=$(timeout 2 git --no-optional-locks -C "$clean_cwd" remote get-url origin 2>/dev/null)
|
|
88
|
+
if [ -n "$remote_url" ]; then
|
|
89
|
+
gh_user=$(echo "$remote_url" | sed 's|.*github\.com[:/]\([^/]*\)/.*|\1|'); [ "$gh_user" = "$remote_url" ] && gh_user=""
|
|
90
|
+
gh_repo=$(echo "$remote_url" | sed 's|.*/\([^/]*\)\.git$|\1|; s|.*/\([^/]*\)$|\1|'); [ "$gh_repo" = "$remote_url" ] && gh_repo=""
|
|
91
|
+
fi
|
|
92
|
+
timeout 2 git --no-optional-locks -C "$clean_cwd" diff --cached --quiet 2>/dev/null || git_dirty="${GREEN}+${RST}"
|
|
93
|
+
timeout 2 git --no-optional-locks -C "$clean_cwd" diff --quiet 2>/dev/null || git_dirty="${git_dirty}${YELLOW}~${RST}"
|
|
94
|
+
fi
|
|
95
|
+
[ -z "$branch" ] && branch="no-git"
|
|
96
|
+
fi
|
|
97
|
+
[ -n "$gh_repo" ] && gh_label="${gh_user}/${gh_repo}/${branch}" || gh_label="$branch"
|
|
98
|
+
|
|
99
|
+
cost_raw=$(json_num "total_cost_usd")
|
|
100
|
+
if [ -z "$cost_raw" ] || [ "$cost_raw" = "0" ]; then cost_label='$0.00'
|
|
101
|
+
else cost_label=$(awk -v c="$cost_raw" 'BEGIN { if (c < 0.01) printf "$%.4f", c; else printf "$%.2f", c }'); fi
|
|
102
|
+
|
|
103
|
+
total_in=$(json_num "total_input_tokens"); total_out=$(json_num "total_output_tokens")
|
|
104
|
+
[ -z "$total_in" ] && total_in="0"; [ -z "$total_out" ] && total_out="0"
|
|
105
|
+
fmt_tok() { awk -v t="$1" 'BEGIN { if (t >= 1000000) printf "%.1fM", t/1000000; else if (t >= 1000) printf "%.0fk", t/1000; else printf "%d", t }'; }
|
|
106
|
+
tok_in=$(fmt_tok "$total_in"); tok_out=$(fmt_tok "$total_out")
|
|
107
|
+
tok_total=$(awk -v i="$total_in" -v o="$total_out" 'BEGIN { printf "%d", i + o }')
|
|
108
|
+
token_label="${tok_in} + ${tok_out} = $(fmt_tok "$tok_total")"
|
|
109
|
+
|
|
110
|
+
skill_label="Idle"
|
|
111
|
+
if [ -n "$clean_cwd" ]; then
|
|
112
|
+
search_path="$clean_cwd"
|
|
113
|
+
while [ -n "$search_path" ] && [ "$search_path" != "/" ]; do
|
|
114
|
+
proj_hash=$(echo "$search_path" | sed 's|^/\([a-zA-Z]\)/|\U\1--|; s|^[A-Z]:/|&|; s|:/|--|; s|/|-|g')
|
|
115
|
+
proj_dir="$HOME/.claude/projects/${proj_hash}"
|
|
116
|
+
if [ -d "$proj_dir" ]; then tpath=$(ls -t "$proj_dir"/*.jsonl 2>/dev/null | head -1); [ -n "$tpath" ] && break; fi
|
|
117
|
+
search_path=$(echo "$search_path" | sed 's|/[^/]*$||')
|
|
118
|
+
done
|
|
119
|
+
if [ -n "$tpath" ] && [ -f "$tpath" ]; then
|
|
120
|
+
last_tool=$(tail -50 "$tpath" 2>/dev/null | grep -o '"type":"tool_use","id":"[^"]*","name":"[^"]*"' | tail -1 | sed 's/.*"name":"\([^"]*\)".*/\1/')
|
|
121
|
+
if [ -n "$last_tool" ]; then
|
|
122
|
+
case "$last_tool" in
|
|
123
|
+
Task) skill_label="Agent" ;; Read) skill_label="Read" ;; Write) skill_label="Write" ;;
|
|
124
|
+
Edit) skill_label="Edit" ;; Glob) skill_label="Search(Files)" ;; Grep) skill_label="Search(Content)" ;;
|
|
125
|
+
Bash) skill_label="Terminal" ;; WebSearch) skill_label="Web Search" ;; *) skill_label="$last_tool" ;;
|
|
126
|
+
esac
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
fi
|
|
130
|
+
|
|
131
|
+
C1=38; S=$(printf '%b' " ${SEP_C}│${RST} ")
|
|
132
|
+
printf ' '; rpad "${PINK}Skill:${RST} ${PINK}${skill_label}${RST}" "$C1"; printf '%b' "$S"; printf '%b\n' "${WHITE}GitHub:${RST} ${WHITE}${gh_label}${RST}${git_dirty}"
|
|
133
|
+
printf ' '; rpad "${PURPLE}Model:${RST} ${PURPLE}${BOLD}${model_full}${RST}" "$C1"; printf '%b' "$S"; printf '%b\n' "${CYAN}Dir:${RST} ${CYAN}${dir_label}${RST}"
|
|
134
|
+
printf ' '; rpad "${YELLOW}Tokens:${RST} ${YELLOW}${token_label}${RST}" "$C1"; printf '%b' "$S"; printf '%b\n' "${GREEN}Cost:${RST} ${GREEN}${cost_label}${RST}"
|
|
135
|
+
printf ' '; printf '%b' "${CTX_CLR}Context:${RST} ${ctx_bar}"
|
|
136
|
+
|
|
137
|
+
# Cleanup watchdog
|
|
138
|
+
kill "$_SL_WD_PID" 2>/dev/null
|
|
139
|
+
wait "$_SL_WD_PID" 2>/dev/null
|