Files
ai-setup/home-configs/claude/statusline-command.sh
Виталий Никитенко 6c7324bfd8 fix: статусная строка — DeepSeek per-request стоимость вместо статичного баланса
DeepSeek: накопленная стоимость сессии по DeepSeek-ценам (V4: $0.55/$2.19, V3: $0.27/$1.10)
Anthropic/Kimi/прочие: рейт-лимиты (5h, 7d) без долларов
Все: заполнение контекста (ctx%)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 07:51:52 +03:00

149 lines
5.2 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
input=$(cat)
cwd=$(echo "$input" | jq -r '.cwd')
model=$(echo "$input" | jq -r '.model.display_name // empty')
model_id=$(echo "$input" | jq -r '.model.id // empty')
session_id=$(echo "$input" | jq -r '.session_id // empty')
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
week_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
week_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
ctx_pct=$(echo "$input" | jq -r '.context_window.used_percentage // empty')
branch=$(git -C "$cwd" --no-optional-locks symbolic-ref --short HEAD 2>/dev/null)
short_cwd="${cwd/#$HOME/\~}"
printf "\033[00;37m%s\033[00m" "$short_cwd"
[ -n "$branch" ] && printf " \033[00;37m[%s]\033[00m" "$branch"
[ -n "$model" ] && printf " \033[38;5;173m%s\033[00m" "$model"
# --- Накопленная стоимость DeepSeek (per-request) ---
COST_FILE="$HOME/.cache/ai-setup/deepseek_cost_state"
if [[ "$model_id" == *deepseek* ]] && [ -n "$session_id" ]; then
# Цены DeepSeek за 1M токенов
case "$model_id" in
*deepseek-v4*|*deepseek-reasoner*)
inp_p=0.55; out_p=2.19; cc_p=0.55; cr_p=0.14 ;;
*deepseek-chat*|*deepseek-v3*|*deepseek*)
inp_p=0.27; out_p=1.10; cc_p=0.27; cr_p=0.07 ;;
*)
inp_p=0.27; out_p=1.10; cc_p=0.27; cr_p=0.07 ;;
esac
usage=$(echo "$input" | jq -r '.context_window.current_usage // empty')
if [ -n "$usage" ] && [ "$usage" != "null" ]; then
in_tok=$(echo "$usage" | jq -r '.input_tokens // 0')
out_tok=$(echo "$usage" | jq -r '.output_tokens // 0')
cc_tok=$(echo "$usage" | jq -r '.cache_creation_input_tokens // 0')
cr_tok=$(echo "$usage" | jq -r '.cache_read_input_tokens // 0')
last_cost=$(echo "scale=10; ($in_tok * $inp_p + $out_tok * $out_p + $cc_tok * $cc_p + $cr_tok * $cr_p) / 1000000" | bc -l)
# Читаем накопленное
if [ -f "$COST_FILE" ]; then
existing=$(grep "^${session_id}|" "$COST_FILE" 2>/dev/null | tail -1)
fi
if [ -n "$existing" ]; then
IFS='|' read -r sid old_in old_out old_cc old_cr old_total <<< "$existing"
if [ "$old_in" = "$in_tok" ] && [ "$old_out" = "$out_tok" ] && [ "$old_cc" = "$cc_tok" ] && [ "$old_cr" = "$cr_tok" ]; then
accumulated="$old_total"
else
accumulated=$(echo "scale=6; $old_total + $last_cost" | bc -l)
fi
else
accumulated="$last_cost"
fi
mkdir -p "$(dirname "$COST_FILE")"
grep -v "^${session_id}|" "$COST_FILE" 2>/dev/null > "$COST_FILE.tmp" || true
echo "${session_id}|${in_tok}|${out_tok}|${cc_tok}|${cr_tok}|${accumulated}" >> "$COST_FILE.tmp"
mv "$COST_FILE.tmp" "$COST_FILE" 2>/dev/null
deepseek_cost="$accumulated"
else
if [ -f "$COST_FILE" ]; then
existing=$(grep "^${session_id}|" "$COST_FILE" 2>/dev/null | tail -1)
if [ -n "$existing" ]; then
IFS='|' read -r sid _ _ _ _ total <<< "$existing"
deepseek_cost="$total"
fi
fi
fi
cost_int=$(printf '%.0f' "$deepseek_cost" 2>/dev/null)
if [ "$cost_int" -gt 0 ] 2>/dev/null; then
printf " \033[00;35m\$%.2f\033[00m" "$deepseek_cost"
fi
fi
# Форматирует оставшееся время до сброса лимита
fmt_remaining() {
local reset_ts="$1"
local now
now=$(date +%s)
local diff=$(( reset_ts - now ))
[ "$diff" -le 0 ] && echo "скоро" && return
local d=$(( diff / 86400 ))
local h=$(( (diff % 86400) / 3600 ))
local m=$(( (diff % 3600) / 60 ))
if [ "$d" -gt 0 ]; then
echo "${d}д${h}ч"
elif [ "$h" -gt 0 ]; then
echo "${h}ч${m}м"
else
echo "${m}м"
fi
}
# Возвращает ANSI-цвет по проценту: зелёный <40%, жёлтый 40-60%, красный >=60%
pct_color() {
local pct="$1"
if [ "$pct" -lt 40 ]; then
printf '\033[00;32m'
elif [ "$pct" -lt 60 ]; then
printf '\033[00;33m'
else
printf '\033[00;31m'
fi
}
# Рейт-лимиты для Anthropic / Kimi / прочих (НЕ DeepSeek)
if [[ "$model_id" != *deepseek* ]]; then
if [ -n "$five_pct" ] && [ -n "$five_reset" ]; then
five_int=$(printf '%.0f' "$five_pct")
remaining=$(fmt_remaining "$five_reset")
color=$(pct_color "$five_int")
printf " %s%s:%s%%\033[00m" "$color" "$remaining" "$five_int"
fi
if [ -n "$week_pct" ] && [ -n "$week_reset" ]; then
week_int=$(printf '%.0f' "$week_pct")
remaining=$(fmt_remaining "$week_reset")
color=$(pct_color "$week_int")
printf " %s%s:%s%%\033[00m" "$color" "$remaining" "$week_int"
fi
fi
if [ -n "$ctx_pct" ]; then
ctx_int=$(printf '%.0f' "$ctx_pct")
color=$(pct_color "$ctx_int")
printf " %sctx:%s%%\033[00m" "$color" "$ctx_int"
# Звуковой сигнал при первом достижении 60%
alert_file="$HOME/.cache/ai-setup/ctx_alert_state"
if [ "$ctx_int" -ge 60 ]; then
if [ ! -f "$alert_file" ] || [ "$(cat "$alert_file")" != "alerted" ]; then
mkdir -p "$HOME/.cache/ai-setup"
echo "alerted" > "$alert_file"
(timeout 1s paplay /usr/share/sounds/freedesktop/stereo/alarm-clock-elapsed.oga 2>/dev/null; true) &
fi
elif [ "$ctx_int" -lt 50 ]; then
rm -f "$alert_file" 2>/dev/null
fi
fi
exit 0