@winston.wan/burn-your-money 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/README.md +19 -4
- package/bash.exe.stackdump +7 -7
- package/docs/images/where_is_my_money.png +0 -0
- package/install.js +53 -243
- package/package.json +29 -33
- package/src/statusline.js +264 -0
- package/src/token-history.js +234 -0
- package/uninstall.js +2 -3
- package/bin/burn-your-money +0 -402
- package/fix-git-bash.ps1 +0 -154
- package/install.sh +0 -271
- package/src/statusline.sh +0 -250
- package/src/token-history.sh +0 -268
package/install.sh
DELETED
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Burn Your Money - 一键安装脚本
|
|
3
|
-
# 用法: curl -fsSL https://raw.githubusercontent.com/winston-wwzhen/burn-your-money/main/install.sh | bash
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
# 颜色定义
|
|
8
|
-
RED='\033[0;31m'
|
|
9
|
-
GREEN='\033[0;32m'
|
|
10
|
-
YELLOW='\033[1;33m'
|
|
11
|
-
BLUE='\033[0;34m'
|
|
12
|
-
PURPLE='\033[0;35m'
|
|
13
|
-
CYAN='\033[0;36m'
|
|
14
|
-
NC='\033[0m' # No Color
|
|
15
|
-
|
|
16
|
-
# 打印带颜色的消息
|
|
17
|
-
print_header() {
|
|
18
|
-
echo ""
|
|
19
|
-
echo -e "${PURPLE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
20
|
-
echo -e "${PURPLE} $1${NC}"
|
|
21
|
-
echo -e "${PURPLE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
22
|
-
echo ""
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
print_step() {
|
|
26
|
-
echo -e "${CYAN}▶ $1${NC}"
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
print_success() {
|
|
30
|
-
echo -e "${GREEN}✓ $1${NC}"
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
print_warning() {
|
|
34
|
-
echo -e "${YELLOW}⚠ $1${NC}"
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
print_error() {
|
|
38
|
-
echo -e "${RED}✗ $1${NC}"
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
# 显示 Logo
|
|
42
|
-
show_logo() {
|
|
43
|
-
echo ""
|
|
44
|
-
echo -e "${RED}"
|
|
45
|
-
echo " ██╗ ██╗███████╗██████╗ ██████╗ ███████╗██████╗ ██████╗ "
|
|
46
|
-
echo " ██║ ██║██╔════╝██╔══██╗██╔═══██╗██╔════╝██╔══██╗██╔══██╗"
|
|
47
|
-
echo " ██║ █╗ ██║█████╗ ██████╔╝██║ ██║█████╗ ██████╔╝██║ ██║"
|
|
48
|
-
echo " ██║███╗██║██╔══╝ ██╔══██╗██║ ██║██╔══╝ ██╔══██╗██║ ██║"
|
|
49
|
-
echo " ╚███╔███╔╝███████╗██████╔╝╚██████╔╝███████╗██████╔╝██████╔╝"
|
|
50
|
-
echo " ╚══╝╚══╝ ╚══════╝╚═════╝ ╚═════╝ ╚══════╝╚═════╝ ╚═════╝ "
|
|
51
|
-
echo ""
|
|
52
|
-
echo -e "${CYAN} 💸 Burn Your Money - 看着你的钱包燃烧${NC}"
|
|
53
|
-
echo ""
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
# 检查依赖
|
|
57
|
-
check_dependencies() {
|
|
58
|
-
print_step "检查依赖..."
|
|
59
|
-
|
|
60
|
-
# 检查 jq
|
|
61
|
-
if ! command -v jq &> /dev/null; then
|
|
62
|
-
print_error "jq 未安装!"
|
|
63
|
-
echo ""
|
|
64
|
-
echo "请先安装 jq:"
|
|
65
|
-
echo " Ubuntu/Debian: sudo apt-get install jq"
|
|
66
|
-
echo " macOS: brew install jq"
|
|
67
|
-
echo " Arch: sudo pacman -S jq"
|
|
68
|
-
echo ""
|
|
69
|
-
exit 1
|
|
70
|
-
fi
|
|
71
|
-
print_success "jq 已安装"
|
|
72
|
-
|
|
73
|
-
# 检查 Claude Code
|
|
74
|
-
if ! command -v claude &> /dev/null; then
|
|
75
|
-
print_warning "Claude Code 未找到"
|
|
76
|
-
else
|
|
77
|
-
CLAUDE_VERSION=$(claude --version 2>/dev/null || echo "unknown")
|
|
78
|
-
print_success "Claude Code 版本: $CLAUDE_VERSION"
|
|
79
|
-
fi
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
# 创建目录结构
|
|
83
|
-
create_directories() {
|
|
84
|
-
print_step "创建目录结构..."
|
|
85
|
-
|
|
86
|
-
mkdir -p ~/.claude/scripts
|
|
87
|
-
mkdir -p ~/.claude/cache
|
|
88
|
-
|
|
89
|
-
print_success "目录已创建"
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
# 从 GitHub 下载文件
|
|
93
|
-
download_file() {
|
|
94
|
-
local url="$1"
|
|
95
|
-
local dest="$2"
|
|
96
|
-
local max_retries=3
|
|
97
|
-
local retry=0
|
|
98
|
-
|
|
99
|
-
while [ $retry -lt $max_retries ]; do
|
|
100
|
-
if curl -fsSL "$url" -o "$dest" 2>/dev/null; then
|
|
101
|
-
return 0
|
|
102
|
-
fi
|
|
103
|
-
retry=$((retry + 1))
|
|
104
|
-
if [ $retry -lt $max_retries ]; then
|
|
105
|
-
sleep 1
|
|
106
|
-
fi
|
|
107
|
-
done
|
|
108
|
-
return 1
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
# 安装脚本文件
|
|
112
|
-
install_scripts() {
|
|
113
|
-
print_step "安装脚本文件..."
|
|
114
|
-
|
|
115
|
-
# 获取脚本目录
|
|
116
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
117
|
-
|
|
118
|
-
# 检查本地文件是否存在
|
|
119
|
-
local use_remote=false
|
|
120
|
-
if [ ! -f "$SCRIPT_DIR/src/statusline.sh" ] || [ ! -f "$SCRIPT_DIR/src/token-history.sh" ]; then
|
|
121
|
-
print_warning "本地脚本文件不存在,从 GitHub 下载..."
|
|
122
|
-
use_remote=true
|
|
123
|
-
fi
|
|
124
|
-
|
|
125
|
-
# GitHub 原始文件 URL 基础路径
|
|
126
|
-
local BASE_URL="https://raw.githubusercontent.com/winston-wwzhen/burn-your-money/main"
|
|
127
|
-
|
|
128
|
-
# 安装 statusline.sh
|
|
129
|
-
if [ "$use_remote" = true ]; then
|
|
130
|
-
print_step "下载 statusline.sh..."
|
|
131
|
-
if download_file "$BASE_URL/src/statusline.sh" ~/.claude/statusline.sh; then
|
|
132
|
-
chmod +x ~/.claude/statusline.sh
|
|
133
|
-
print_success "statusline.sh 已下载并安装"
|
|
134
|
-
else
|
|
135
|
-
print_error "下载 statusline.sh 失败,请检查网络连接"
|
|
136
|
-
exit 1
|
|
137
|
-
fi
|
|
138
|
-
else
|
|
139
|
-
cp "$SCRIPT_DIR/src/statusline.sh" ~/.claude/statusline.sh
|
|
140
|
-
chmod +x ~/.claude/statusline.sh
|
|
141
|
-
print_success "statusline.sh 已安装"
|
|
142
|
-
fi
|
|
143
|
-
|
|
144
|
-
# 安装 token-history.sh
|
|
145
|
-
mkdir -p ~/.claude/scripts
|
|
146
|
-
if [ "$use_remote" = true ]; then
|
|
147
|
-
print_step "下载 token-history.sh..."
|
|
148
|
-
if download_file "$BASE_URL/src/token-history.sh" ~/.claude/scripts/token-history.sh; then
|
|
149
|
-
chmod +x ~/.claude/scripts/token-history.sh
|
|
150
|
-
print_success "token-history.sh 已下载并安装"
|
|
151
|
-
else
|
|
152
|
-
print_error "下载 token-history.sh 失败,请检查网络连接"
|
|
153
|
-
exit 1
|
|
154
|
-
fi
|
|
155
|
-
else
|
|
156
|
-
cp "$SCRIPT_DIR/src/token-history.sh" ~/.claude/scripts/token-history.sh
|
|
157
|
-
chmod +x ~/.claude/scripts/token-history.sh
|
|
158
|
-
print_success "token-history.sh 已安装"
|
|
159
|
-
fi
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
# 配置 settings.json
|
|
163
|
-
configure_settings() {
|
|
164
|
-
print_step "配置 Claude Code..."
|
|
165
|
-
|
|
166
|
-
SETTINGS_FILE="$HOME/.claude/settings.json"
|
|
167
|
-
|
|
168
|
-
# 如果文件不存在,创建一个
|
|
169
|
-
if [ ! -f "$SETTINGS_FILE" ]; then
|
|
170
|
-
echo "{}" > "$SETTINGS_FILE"
|
|
171
|
-
fi
|
|
172
|
-
|
|
173
|
-
# 使用 jq 添加 statusline 配置
|
|
174
|
-
if command -v jq &> /dev/null; then
|
|
175
|
-
tmp_file=$(mktemp)
|
|
176
|
-
jq '.statusLine = {"type": "command", "command": "~/.claude/statusline.sh"}' "$SETTINGS_FILE" > "$tmp_file"
|
|
177
|
-
mv "$tmp_file" "$SETTINGS_FILE"
|
|
178
|
-
print_success "settings.json 已更新"
|
|
179
|
-
else
|
|
180
|
-
print_warning "无法自动更新 settings.json,请手动添加:"
|
|
181
|
-
echo ""
|
|
182
|
-
echo '{
|
|
183
|
-
"statusLine": {
|
|
184
|
-
"type": "command",
|
|
185
|
-
"command": "~/.claude/statusline.sh"
|
|
186
|
-
}
|
|
187
|
-
}'
|
|
188
|
-
echo ""
|
|
189
|
-
fi
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
# 测试安装
|
|
193
|
-
test_installation() {
|
|
194
|
-
print_step "测试安装..."
|
|
195
|
-
|
|
196
|
-
# 测试 statusline 脚本
|
|
197
|
-
test_json='{
|
|
198
|
-
"model": {"display_name": "Test"},
|
|
199
|
-
"context_window": {
|
|
200
|
-
"total_input_tokens": 10000,
|
|
201
|
-
"total_output_tokens": 2000,
|
|
202
|
-
"context_window_size": 200000,
|
|
203
|
-
"used_percentage": 6,
|
|
204
|
-
"remaining_percentage": 94
|
|
205
|
-
},
|
|
206
|
-
"cost": {"total_cost_usd": 0.05}
|
|
207
|
-
}'
|
|
208
|
-
|
|
209
|
-
if output=$(echo "$test_json" | ~/.claude/statusline.sh 2>/dev/null); then
|
|
210
|
-
print_success "statusline 脚本工作正常"
|
|
211
|
-
echo " 输出: $output"
|
|
212
|
-
else
|
|
213
|
-
print_error "statusline 脚本测试失败"
|
|
214
|
-
return 1
|
|
215
|
-
fi
|
|
216
|
-
|
|
217
|
-
# 测试 token-history 脚本
|
|
218
|
-
if ~/.claude/scripts/token-history.sh summary > /dev/null 2>&1; then
|
|
219
|
-
print_success "token-history 脚本工作正常"
|
|
220
|
-
else
|
|
221
|
-
print_warning "token-history 脚本测试失败(可能没有历史数据)"
|
|
222
|
-
fi
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
# 显示完成信息
|
|
226
|
-
show_completion() {
|
|
227
|
-
print_header "安装完成!"
|
|
228
|
-
|
|
229
|
-
echo -e "${GREEN}Burn Your Money 已成功安装!${NC}"
|
|
230
|
-
echo ""
|
|
231
|
-
echo "📝 已安装的文件:"
|
|
232
|
-
echo " • ~/.claude/statusline.sh"
|
|
233
|
-
echo " • ~/.claude/scripts/token-history.sh"
|
|
234
|
-
echo ""
|
|
235
|
-
echo "🔧 已更新配置:"
|
|
236
|
-
echo " • ~/.claude/settings.json"
|
|
237
|
-
echo ""
|
|
238
|
-
echo -e "${YELLOW}下一步:${NC}"
|
|
239
|
-
echo " 1. 重启 Claude Code"
|
|
240
|
-
echo " 2. 观察状态栏是否显示 Token 信息"
|
|
241
|
-
echo ""
|
|
242
|
-
echo -e "${CYAN}如果状态栏没有显示,请检查:${NC}"
|
|
243
|
-
echo " • Claude Code 版本是否 >= 2.1.6"
|
|
244
|
-
echo " • 运行: claude --version"
|
|
245
|
-
echo ""
|
|
246
|
-
echo -e "${PURPLE}反馈与支持:${NC}"
|
|
247
|
-
echo " • GitHub: https://github.com/winston-wwzhen/burn-your-money"
|
|
248
|
-
echo " • Issues: https://github.com/winston-wwzhen/burn-your-money/issues"
|
|
249
|
-
echo ""
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
# 主函数
|
|
253
|
-
main() {
|
|
254
|
-
show_logo
|
|
255
|
-
|
|
256
|
-
print_header "开始安装 Burn Your Money..."
|
|
257
|
-
|
|
258
|
-
check_dependencies
|
|
259
|
-
create_directories
|
|
260
|
-
install_scripts
|
|
261
|
-
configure_settings
|
|
262
|
-
test_installation
|
|
263
|
-
|
|
264
|
-
show_completion
|
|
265
|
-
|
|
266
|
-
echo -e "${GREEN}开始烧钱吧!🔥💸${NC}"
|
|
267
|
-
echo ""
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
# 运行主函数
|
|
271
|
-
main
|
package/src/statusline.sh
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Burn Your Money - Claude Code 状态栏脚本
|
|
3
|
-
# 格式:[模型] 今日:token 费用 🔥速度 | 总计:token 费用
|
|
4
|
-
|
|
5
|
-
# 设置 jq 命令路径(支持自定义安装的 jq)
|
|
6
|
-
if [ -n "$JQ_PATH" ]; then
|
|
7
|
-
JQ_CMD="$JQ_PATH"
|
|
8
|
-
elif [ -f "$HOME/.claude/bin/jq.exe" ]; then
|
|
9
|
-
JQ_CMD="$HOME/.claude/bin/jq.exe"
|
|
10
|
-
elif [ -f "$HOME/.claude/bin/jq" ]; then
|
|
11
|
-
JQ_CMD="$HOME/.claude/bin/jq"
|
|
12
|
-
else
|
|
13
|
-
JQ_CMD="jq"
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
# 验证 jq 是否可用
|
|
17
|
-
if ! command -v "$JQ_CMD" >/dev/null 2>&1; then
|
|
18
|
-
# jq 不可用,返回简单错误信息
|
|
19
|
-
printf "[BurnYourMoney] Error: jq not found. Run: npm install -g @winston.wan/burn-your-money"
|
|
20
|
-
exit 0
|
|
21
|
-
fi
|
|
22
|
-
|
|
23
|
-
# 配置文件
|
|
24
|
-
CONFIG_FILE="$HOME/.claude/burn-your-money-config.json"
|
|
25
|
-
SESSION_STATE="$HOME/.claude/cache/session-state.json"
|
|
26
|
-
TODAY_STATE="$HOME/.claude/cache/today-state.json"
|
|
27
|
-
HISTORY_CACHE="$HOME/.claude/cache/history-cache.json"
|
|
28
|
-
|
|
29
|
-
# 初始化配置
|
|
30
|
-
init_config() {
|
|
31
|
-
if [ ! -f "$CONFIG_FILE" ]; then
|
|
32
|
-
$JQ_CMD -n '{
|
|
33
|
-
theme: "fire",
|
|
34
|
-
alert_daily: 10.0,
|
|
35
|
-
alert_weekly: 50.0,
|
|
36
|
-
show_burn_rate: true,
|
|
37
|
-
show_eta: true,
|
|
38
|
-
show_trend: false
|
|
39
|
-
}' > "$CONFIG_FILE"
|
|
40
|
-
fi
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
# 1. 批量读取配置 (One JQ pass)
|
|
44
|
-
init_config
|
|
45
|
-
if [ -f "$CONFIG_FILE" ]; then
|
|
46
|
-
# 使用 eval 批量赋值变量
|
|
47
|
-
eval $("$JQ_CMD" -r '@sh "THEME=\(.theme // "fire") ALERT_DAILY=\(.alert_daily // 10) SHOW_BURN_RATE=\(.show_burn_rate // true)"' "$CONFIG_FILE" 2>/dev/null)
|
|
48
|
-
else
|
|
49
|
-
THEME="fire"
|
|
50
|
-
ALERT_DAILY=10
|
|
51
|
-
SHOW_BURN_RATE=true
|
|
52
|
-
fi
|
|
53
|
-
|
|
54
|
-
# 主题颜色定义
|
|
55
|
-
case "$THEME" in
|
|
56
|
-
fire) TODAY_COLOR="0;31"; COST_COLOR="0;31"; BURN_COLOR="0;31" ;;
|
|
57
|
-
ocean) TODAY_COLOR="0;34"; COST_COLOR="0;36"; BURN_COLOR="0;36" ;;
|
|
58
|
-
forest) TODAY_COLOR="0;32"; COST_COLOR="0;33"; BURN_COLOR="0;32" ;;
|
|
59
|
-
golden) TODAY_COLOR="0;33"; COST_COLOR="0;33"; BURN_COLOR="1;33" ;;
|
|
60
|
-
*) TODAY_COLOR="0;36"; COST_COLOR="0;34"; BURN_COLOR="0;31" ;;
|
|
61
|
-
esac
|
|
62
|
-
|
|
63
|
-
# 格式化函数 (纯 Bash/Awk 实现,无外部进程调用)
|
|
64
|
-
format_number() {
|
|
65
|
-
local num=$1
|
|
66
|
-
if [ "$num" -ge 1000000000 ]; then awk "BEGIN {printf \"%.1fB\", $num/1000000000}";
|
|
67
|
-
elif [ "$num" -ge 1000000 ]; then awk "BEGIN {printf \"%.1fM\", $num/1000000}";
|
|
68
|
-
elif [ "$num" -ge 1000 ]; then awk "BEGIN {printf \"%.1fK\", $num/1000}";
|
|
69
|
-
else echo "$num"; fi
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
format_cost() {
|
|
73
|
-
awk "BEGIN {printf \"\$%.2f\", $1}"
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
format_burn_rate() {
|
|
77
|
-
local rate=$1
|
|
78
|
-
if [ "$rate" -ge 1000 ]; then awk "BEGIN {printf \"%.1fK tok/s\", $rate/1000}";
|
|
79
|
-
else awk "BEGIN {printf \"%.0f tok/s\", $rate}"; fi
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
# 2. 核心数据解析 (One JQ pass from stdin)
|
|
83
|
-
# 将 stdin 存入临时文件(避免大 JSON 管道卡顿)
|
|
84
|
-
TEMP_JSON=$(mktemp)
|
|
85
|
-
trap "rm -f $TEMP_JSON" EXIT
|
|
86
|
-
cat > "$TEMP_JSON"
|
|
87
|
-
|
|
88
|
-
# 一次性提取所有需要的字段
|
|
89
|
-
# 注意:使用 @sh 确保字符串安全引用
|
|
90
|
-
eval $("$JQ_CMD" -r '
|
|
91
|
-
@sh "model_name=\(.model.display_name // "Unknown")
|
|
92
|
-
session_id=\(.session_id // "default")
|
|
93
|
-
input=\(.context_window.total_input_tokens // 0)
|
|
94
|
-
output=\(.context_window.total_output_tokens // 0)
|
|
95
|
-
cache=\(.context_window.current_usage.cache_read_input_tokens // 0)
|
|
96
|
-
current_cost=\(.cost.total_cost_usd // 0)"
|
|
97
|
-
' "$TEMP_JSON" 2>/dev/null)
|
|
98
|
-
|
|
99
|
-
# 计算当前会话 Token 总量
|
|
100
|
-
current_session_tokens=$((input + output + cache))
|
|
101
|
-
|
|
102
|
-
# 3. 燃烧速度计算 (Burn Rate)
|
|
103
|
-
current_time=$(date +%s)
|
|
104
|
-
start_time_cache=0
|
|
105
|
-
|
|
106
|
-
# 读取 Session State (尽可能不做写入,除非是新 Session)
|
|
107
|
-
if [ -f "$SESSION_STATE" ]; then
|
|
108
|
-
eval $("$JQ_CMD" -r '@sh "cached_id=\(.session_id // "") cached_time=\(.start_time // 0)"' "$SESSION_STATE" 2>/dev/null)
|
|
109
|
-
else
|
|
110
|
-
cached_id=""
|
|
111
|
-
cached_time=0
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
if [ "$cached_id" = "$session_id" ] && [ "$cached_time" -ne 0 ]; then
|
|
115
|
-
start_time_cache=$cached_time
|
|
116
|
-
else
|
|
117
|
-
# New session detected - 使用原子写入
|
|
118
|
-
start_time_cache=$current_time
|
|
119
|
-
SESSION_STATE_TMP="${SESSION_STATE}.tmp.$$"
|
|
120
|
-
$JQ_CMD -n --arg id "$session_id" --arg time "$current_time" '{session_id: $id, start_time: ($time | tonumber)}' > "$SESSION_STATE_TMP" 2>/dev/null && mv "$SESSION_STATE_TMP" "$SESSION_STATE"
|
|
121
|
-
fi
|
|
122
|
-
|
|
123
|
-
elapsed=$((current_time - start_time_cache))
|
|
124
|
-
burn_rate=0
|
|
125
|
-
if [ "$elapsed" -gt 0 ] && [ "$current_session_tokens" -gt 0 ]; then
|
|
126
|
-
burn_rate=$(awk "BEGIN {printf \"%.0f\", ${current_session_tokens} / ${elapsed}}")
|
|
127
|
-
fi
|
|
128
|
-
|
|
129
|
-
# 4. 历史数据缓存 (每 30 秒刷新)
|
|
130
|
-
# 确保 cache 目录存在
|
|
131
|
-
mkdir -p "$(dirname "$HISTORY_CACHE")" 2>/dev/null
|
|
132
|
-
|
|
133
|
-
now=$(date +%s)
|
|
134
|
-
cache_age=999999
|
|
135
|
-
if [ -f "$HISTORY_CACHE" ]; then
|
|
136
|
-
# Portable modification time check
|
|
137
|
-
if [ "$(uname)" = "Darwin" ]; then
|
|
138
|
-
cache_time=$(stat -f %m "$HISTORY_CACHE" 2>/dev/null || echo 0)
|
|
139
|
-
else
|
|
140
|
-
cache_time=$(stat -c %Y "$HISTORY_CACHE" 2>/dev/null || echo 0)
|
|
141
|
-
fi
|
|
142
|
-
cache_age=$((now - cache_time))
|
|
143
|
-
else
|
|
144
|
-
echo '{}' > "$HISTORY_CACHE"
|
|
145
|
-
fi
|
|
146
|
-
|
|
147
|
-
# 如果缓存太旧,并在后台刷新(虽然后台刷新可能在 statusline 不合适,但我们可以同步调用历史脚本)
|
|
148
|
-
# 为了性能,这里我们仍然做同步调用,但减少频率
|
|
149
|
-
if [ $cache_age -gt 30 ]; then
|
|
150
|
-
# 重新生成历史数据
|
|
151
|
-
~/.claude/scripts/token-history.sh summary > "$HISTORY_CACHE" 2>/dev/null
|
|
152
|
-
fi
|
|
153
|
-
|
|
154
|
-
# 读取历史总计 (One pass)
|
|
155
|
-
eval $("$JQ_CMD" -r '@sh "history_total_tokens=\(.total_tokens_all // 0) history_total_cost=\(.total_cost // 0)"' "$HISTORY_CACHE" 2>/dev/null)
|
|
156
|
-
|
|
157
|
-
# 5. 今日数据持久化 (One-pass Read & Write)
|
|
158
|
-
# 逻辑:读取旧状态 -> 计算差值 -> 写入新状态
|
|
159
|
-
today_date=$(date +%Y-%m-%d)
|
|
160
|
-
|
|
161
|
-
if [ -f "$TODAY_STATE" ]; then
|
|
162
|
-
eval $("$JQ_CMD" -r '@sh "saved_date=\(.date // "") saved_tokens=\(.tokens // 0) saved_cost=\(.cost // 0) last_session_tokens=\(.last_session_tokens // 0) last_session_cost=\(.last_session_cost // 0)"' "$TODAY_STATE" 2>/dev/null)
|
|
163
|
-
else
|
|
164
|
-
saved_date=""
|
|
165
|
-
saved_tokens=0
|
|
166
|
-
saved_cost=0
|
|
167
|
-
last_session_tokens=0
|
|
168
|
-
last_session_cost=0
|
|
169
|
-
fi
|
|
170
|
-
|
|
171
|
-
if [ "$saved_date" != "$today_date" ]; then
|
|
172
|
-
# 新的一天,重置累计数据
|
|
173
|
-
saved_tokens=0
|
|
174
|
-
saved_cost=0
|
|
175
|
-
last_session_tokens=0
|
|
176
|
-
last_session_cost=0
|
|
177
|
-
fi
|
|
178
|
-
|
|
179
|
-
# 计算增量
|
|
180
|
-
token_increment=$((current_session_tokens - last_session_tokens))
|
|
181
|
-
if [ "$token_increment" -lt 0 ]; then token_increment=0; fi # 防御性编程
|
|
182
|
-
|
|
183
|
-
# 浮点数增量计算
|
|
184
|
-
cost_increment=$(awk "BEGIN {print ($current_cost - $last_session_cost < 0 ? 0 : $current_cost - $last_session_cost)}")
|
|
185
|
-
|
|
186
|
-
# 计算新的今日累计
|
|
187
|
-
new_today_tokens=$((saved_tokens + token_increment))
|
|
188
|
-
new_today_cost=$(awk "BEGIN {printf \"%.5f\", $saved_cost + $cost_increment}")
|
|
189
|
-
|
|
190
|
-
# 写入新状态 (一次性写入,使用原子写入避免并发问题)
|
|
191
|
-
# 先写入临时文件,然后重命名,确保原子性
|
|
192
|
-
TODAY_STATE_TMP="${TODAY_STATE}.tmp.$$"
|
|
193
|
-
$JQ_CMD -n \
|
|
194
|
-
--arg date "$today_date" \
|
|
195
|
-
--arg tokens "$new_today_tokens" \
|
|
196
|
-
--arg cost "$new_today_cost" \
|
|
197
|
-
--arg last_sess_tok "$current_session_tokens" \
|
|
198
|
-
--arg last_sess_cost "$current_cost" \
|
|
199
|
-
'{
|
|
200
|
-
date: $date,
|
|
201
|
-
tokens: ($tokens|tonumber),
|
|
202
|
-
cost: ($cost|tonumber),
|
|
203
|
-
last_session_tokens: ($last_sess_tok|tonumber),
|
|
204
|
-
last_session_cost: ($last_sess_cost|tonumber)
|
|
205
|
-
}' > "$TODAY_STATE_TMP" 2>/dev/null && mv "$TODAY_STATE_TMP" "$TODAY_STATE"
|
|
206
|
-
|
|
207
|
-
# 6. 最终计算与显示
|
|
208
|
-
total_tokens_all=$((history_total_tokens + current_session_tokens))
|
|
209
|
-
total_cost_all=$(awk "BEGIN {print $history_total_cost + $current_cost}")
|
|
210
|
-
|
|
211
|
-
# 警报检查
|
|
212
|
-
is_alert=false
|
|
213
|
-
if awk "BEGIN {exit !($new_today_cost >= $ALERT_DAILY)}"; then
|
|
214
|
-
is_alert=true
|
|
215
|
-
fi
|
|
216
|
-
|
|
217
|
-
# 构建输出字符串
|
|
218
|
-
output=""
|
|
219
|
-
|
|
220
|
-
# [Model]
|
|
221
|
-
if [ "$is_alert" = true ]; then
|
|
222
|
-
output+="\\033[1;31m[${model_name}]\\033[0m "
|
|
223
|
-
else
|
|
224
|
-
output+="\\033[0;90m[${model_name}]\\033[0m "
|
|
225
|
-
fi
|
|
226
|
-
|
|
227
|
-
# Today
|
|
228
|
-
d_today_tokens=$(format_number $new_today_tokens)
|
|
229
|
-
d_today_cost=$(format_cost $new_today_cost)
|
|
230
|
-
|
|
231
|
-
if [ "$new_today_tokens" -gt 0 ]; then
|
|
232
|
-
output+="\\033[${TODAY_COLOR}m今日:${d_today_tokens}\\033[0m "
|
|
233
|
-
output+="\\033[${COST_COLOR}m${d_today_cost}\\033[0m "
|
|
234
|
-
else
|
|
235
|
-
output+="\\033[0;90m今日:0\\033[0m \\033[0;90m\$0.00\\033[0m "
|
|
236
|
-
fi
|
|
237
|
-
|
|
238
|
-
# Burn Rate
|
|
239
|
-
if [ "$SHOW_BURN_RATE" = "true" ] && [ "$burn_rate" -gt 0 ]; then
|
|
240
|
-
d_burn=$(format_burn_rate $burn_rate)
|
|
241
|
-
output+="\\033[${BURN_COLOR}m🔥${d_burn}\\033[0m "
|
|
242
|
-
fi
|
|
243
|
-
|
|
244
|
-
# Total
|
|
245
|
-
d_total_tokens=$(format_number $total_tokens_all)
|
|
246
|
-
d_total_cost=$(format_cost $total_cost_all)
|
|
247
|
-
output+="| \\033[0;90m总计:${d_total_tokens}\\033[0m \\033[0;90m${d_total_cost}\\033[0m "
|
|
248
|
-
|
|
249
|
-
# Print final result
|
|
250
|
-
printf "%b" "$output"
|