@winston.wan/burn-your-money 2.1.1 → 2.1.2

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 CHANGED
@@ -11,9 +11,7 @@
11
11
 
12
12
  ## 📸 效果预览
13
13
 
14
- ```
15
- [Claude 3.5 Sonnet] 今日:78.2K $0.47 🔥1.2K tok/s | 总计:285.1M $20.12
16
- ```
14
+ ![预览](docs/images/where_is_my_money.png)
17
15
 
18
16
  ---
19
17
 
@@ -147,7 +145,7 @@ burn-your-money total # 总计统计
147
145
  如果现实太过沉重:
148
146
 
149
147
  ```bash
150
- npm uninstall -g @winston.wan/burn-your-money
148
+ npm uninstall -g "@winston.wan/burn-your-money"
151
149
  ```
152
150
 
153
151
  然后重启 Claude Code。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@winston.wan/burn-your-money",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "💸 Burn Your Money - 实时显示 Claude Code 的 token 消耗,看着你的钱包燃烧!",
5
5
  "main": "src/statusline.sh",
6
6
  "bin": {
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "scripts": {
10
10
  "postinstall": "node install.js",
11
- "uninstall": "node uninstall.js",
11
+ "preuninstall": "node uninstall.js",
12
12
  "test": "bash ./test.sh"
13
13
  },
14
14
  "repository": {
package/src/statusline.sh CHANGED
@@ -1,250 +1,250 @@
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"
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"
@@ -1,268 +1,268 @@
1
- #!/bin/bash
2
- # Burn Your Money - Token 历史统计脚本
3
- # 从 stats-cache.json 读取历史数据,返回今日/本周/本月统计
4
-
5
- set -e
6
-
7
- # 设置 jq 命令路径(支持自定义安装的 jq)
8
- if [ -n "$JQ_PATH" ]; then
9
- JQ_CMD="$JQ_PATH"
10
- elif [ -f "$HOME/.claude/bin/jq.exe" ]; then
11
- JQ_CMD="$HOME/.claude/bin/jq.exe"
12
- elif [ -f "$HOME/.claude/bin/jq" ]; then
13
- JQ_CMD="$HOME/.claude/bin/jq"
14
- else
15
- JQ_CMD="jq"
16
- fi
17
-
18
- # 验证 jq 是否可用
19
- if ! command -v "$JQ_CMD" >/dev/null 2>&1; then
20
- echo "Error: jq not found. Please install jq first:"
21
- echo " Windows: npm install -g @winston.wan/burn-your-money"
22
- echo " macOS: brew install jq"
23
- echo " Linux: sudo apt-get install jq"
24
- exit 1
25
- fi
26
-
27
- # 文件路径
28
- STATS_CACHE="$HOME/.claude/stats-cache.json"
29
- TODAY=$(date +%Y-%m-%d)
30
- CURRENT_MONTH=$(date +%Y-%m)
31
- LAST_MONTH=$(date -d "1 month ago" +%Y-%m 2>/dev/null || python3 -c "from datetime import datetime; print((datetime.now().replace(day=1) - __import__('datetime').timedelta(days=1)).strftime('%Y-%m'))")
32
-
33
- # 获取本周一的日期
34
- get_week_start() {
35
- local day_of_week=$(date +%u) # 1=Monday, 7=Sunday
36
- local days_to_subtract=$((day_of_week - 1))
37
- date -d "$days_to_subtract days ago" +%Y-%m-%d 2>/dev/null || \
38
- python3 -c "from datetime import datetime, timedelta; d = datetime.now() - timedelta(days=$(date +%u) - 1); print(d.strftime('%Y-%m-%d'))"
39
- }
40
-
41
- # 获取本月第一天
42
- get_month_start() {
43
- date +%Y-%m-01
44
- }
45
-
46
- WEEK_START=$(get_week_start)
47
- MONTH_START=$(get_month_start)
48
- LAST_MONTH_START=$(date -d "$LAST_MONTH-01" +%Y-%m-%d 2>/dev/null || echo "$LAST_MONTH-01")
49
-
50
- # 从 stats-cache.json 读取统计数据
51
- read_stats() {
52
- if [ ! -f "$STATS_CACHE" ]; then
53
- "$JQ_CMD" -n '{
54
- today_tokens:0,today_cost:0,
55
- week_tokens:0,week_cost:0,
56
- month_tokens:0,month_cost:0,
57
- last_month_tokens:0,last_month_cost:0,
58
- total_tokens_all:0,total_cost:0,
59
- daily_data: []
60
- }'
61
- return
62
- fi
63
-
64
- # 获取今日 token:总计 - 历史每日总和(排除今天)
65
- # 修改:聚合所有模型的 input 和 output tokens
66
- local total_io_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[] | (.inputTokens + .outputTokens)] | add // 0' 2>/dev/null || echo "0")
67
-
68
- # 修改:聚合每日数据中所有模型的 token
69
- local history_sum=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date != \"$TODAY\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
70
- local today_data=$((total_io_tokens - history_sum))
71
- [ "$today_data" -lt 0 ] && today_data=0
72
-
73
- # 本周 token(排除今天,用上面的 today_data)
74
- local week_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date >= \"$WEEK_START\" and .date != \"$TODAY\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
75
- week_tokens=$((week_tokens + today_data))
76
-
77
- # 本月 token
78
- local month_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date >= \"$MONTH_START\" and .date != \"$TODAY\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
79
- month_tokens=$((month_tokens + today_data))
80
-
81
- # 上月 token
82
- local last_month_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date >= \"$LAST_MONTH_START\" and .date < \"$MONTH_START\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
83
-
84
- # 计算全部历史费用(使用 jq 进行精确计算,避免 awk 大数字精度问题)
85
- # 修改:聚合所有模型的 usage
86
- local total_input=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[].inputTokens // 0] | add // 0' 2>/dev/null || echo "0")
87
- local total_output=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[].outputTokens // 0] | add // 0' 2>/dev/null || echo "0")
88
- local total_cache_read=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[].cacheReadInputTokens // 0] | add // 0' 2>/dev/null || echo "0")
89
-
90
- # 估算总费用 (简单按 3/15/0.3 规则,虽然不同模型费率不同,但作为估算足够)
91
- # 如果要精确需针对模型 loop,这里简化为聚合
92
- local total_cost=$(cat "$STATS_CACHE" | $JQ_CMD -r '
93
- [.modelUsage[]] | map(
94
- ((.inputTokens // 0) / 1000000 * 3) +
95
- ((.outputTokens // 0) / 1000000 * 15) +
96
- ((.cacheReadInputTokens // 0) / 1000000 * 0.3)
97
- ) | add | floor * 100 / 100
98
- ' 2>/dev/null || echo "0")
99
-
100
- # 总 token 数量(包含 cache)
101
- local total_tokens_all=$((total_input + total_output + total_cache_read))
102
-
103
- # 计算各周期费用(按比例分摊)
104
- local week_cost="0.00"
105
- local month_cost="0.00"
106
- local last_month_cost="0.00"
107
- local today_cost="0.00"
108
-
109
- if [ "$total_io_tokens" != "0" ] && [ "$total_io_tokens" != "" ]; then
110
- week_cost=$(awk "BEGIN {printf \"%.2f\", ${week_tokens} / ${total_io_tokens} * ${total_cost}}")
111
- month_cost=$(awk "BEGIN {printf \"%.2f\", ${month_tokens} / ${total_io_tokens} * ${total_cost}}")
112
- if [ "$last_month_tokens" -gt 0 ]; then
113
- last_month_cost=$(awk "BEGIN {printf \"%.2f\", ${last_month_tokens} / ${total_io_tokens} * ${total_cost}}")
114
- fi
115
- else
116
- week_cost=$total_cost
117
- month_cost=$total_cost
118
- fi
119
-
120
- if [ "$week_tokens" != "0" ] && [ "$week_tokens" != "" ]; then
121
- today_cost=$(awk "BEGIN {printf \"%.2f\", ${today_data} / ${week_tokens} * ${week_cost}}")
122
- fi
123
-
124
- # 获取每日数据(用于趋势图)
125
- # 修改:聚合每日所有模型的 tokens
126
- local daily_data=$(cat "$STATS_CACHE" | $JQ_CMD -c "[.dailyModelTokens[-7:][] | {date: .date, tokens: ([.tokensByModel[]] | add // 0)}]" 2>/dev/null || echo "[]")
127
-
128
- # 输出 JSON
129
- "$JQ_CMD" -n \
130
- --arg today_tokens "$today_data" \
131
- --arg today_cost "$today_cost" \
132
- --arg week_tokens "$week_tokens" \
133
- --arg week_cost "$week_cost" \
134
- --arg month_tokens "$month_tokens" \
135
- --arg month_cost "$month_cost" \
136
- --arg last_month_tokens "$last_month_tokens" \
137
- --arg last_month_cost "$last_month_cost" \
138
- --arg total_tokens_all "$total_tokens_all" \
139
- --arg total_cost "$total_cost" \
140
- --argjson daily_data "$daily_data" \
141
- '{
142
- today_tokens: ($today_tokens | tonumber),
143
- today_cost: ($today_cost | tonumber),
144
- week_tokens: ($week_tokens | tonumber),
145
- week_cost: ($week_cost | tonumber),
146
- month_tokens: ($month_tokens | tonumber),
147
- month_cost: ($month_cost | tonumber),
148
- last_month_tokens: ($last_month_tokens | tonumber),
149
- last_month_cost: ($last_month_cost | tonumber),
150
- total_tokens_all: ($total_tokens_all | tonumber),
151
- total_cost: ($total_cost | tonumber),
152
- daily_data: $daily_data
153
- }'
154
- }
155
-
156
- # 生成 ASCII 趋势图
157
- generate_trend() {
158
- local data="$1"
159
- local max_tokens=0
160
-
161
- # 找到最大值
162
- for row in $(echo "$data" | $JQ_CMD -r '.[].tokens'); do
163
- if [ "$row" -gt "$max_tokens" ]; then
164
- max_tokens=$row
165
- fi
166
- done
167
-
168
- # 生成图表
169
- echo ""
170
- echo "📊 过去 7 天 Token 趋势:"
171
- echo ""
172
-
173
- local count=0
174
- for entry in $(echo "$data" | $JQ_CMD -c '.[]'); do
175
- local date=$(echo "$entry" | $JQ_CMD -r '.date' | cut -c 6-)
176
- local tokens=$(echo "$entry" | $JQ_CMD -r '.tokens')
177
-
178
- # 计算条形长度
179
- if [ "$max_tokens" -gt 0 ]; then
180
- local bars=$(awk "BEGIN {printf \"%.0f\", $tokens / $max_tokens * 20}")
181
- else
182
- local bars=0
183
- fi
184
-
185
- # 生成条形
186
- local bar=""
187
- for i in $(seq 1 20); do
188
- if [ "$i" -le "$bars" ]; then
189
- bar+="█"
190
- else
191
- bar+="░"
192
- fi
193
- done
194
-
195
- # 格式化 token 数量
196
- local tokens_display=$(echo "$tokens" | awk '{
197
- if ($1 >= 1000000) printf "%.1fM", $1/1000000
198
- else if ($1 >= 1000) printf "%.1fK", $1/1000
199
- else printf "%d", $1
200
- }')
201
-
202
- printf " %s │ %s │ %s\n" "$date" "$bar" "$tokens_display"
203
- count=$((count + 1))
204
- done
205
- echo ""
206
- }
207
-
208
- # 导出数据
209
- export_data() {
210
- local format="$1"
211
- local stats=$(read_stats)
212
-
213
- case "$format" in
214
- csv)
215
- echo "date,tokens,cost"
216
- echo "$stats" | $JQ_CMD -r '.daily_data[] | "\(.date),\(.tokens),\(.tokens * 0.000006)"'
217
- ;;
218
- json)
219
- echo "$stats" | $JQ_CMD '.'
220
- ;;
221
- *)
222
- echo "支持的格式: csv, json"
223
- exit 1
224
- ;;
225
- esac
226
- }
227
-
228
- # 根据 mode 返回不同数据
229
- MODE=${1:-summary}
230
-
231
- case "$MODE" in
232
- today_tokens)
233
- read_stats | $JQ_CMD -r '.today_tokens'
234
- ;;
235
- today_cost)
236
- read_stats | $JQ_CMD -r '.today_cost'
237
- ;;
238
- week_tokens)
239
- read_stats | $JQ_CMD -r '.week_tokens'
240
- ;;
241
- week_cost)
242
- read_stats | $JQ_CMD -r '.week_cost'
243
- ;;
244
- month_tokens)
245
- read_stats | $JQ_CMD -r '.month_tokens'
246
- ;;
247
- month_cost)
248
- read_stats | $JQ_CMD -r '.month_cost'
249
- ;;
250
- last_month_tokens)
251
- read_stats | $JQ_CMD -r '.last_month_tokens'
252
- ;;
253
- last_month_cost)
254
- read_stats | $JQ_CMD -r '.last_month_cost'
255
- ;;
256
- trend)
257
- read_stats | $JQ_CMD -r '.daily_data'
258
- ;;
259
- chart)
260
- generate_trend "$(read_stats | $JQ_CMD -r '.daily_data')"
261
- ;;
262
- export)
263
- export_data "$2"
264
- ;;
265
- summary|json|*)
266
- read_stats
267
- ;;
268
- esac
1
+ #!/bin/bash
2
+ # Burn Your Money - Token 历史统计脚本
3
+ # 从 stats-cache.json 读取历史数据,返回今日/本周/本月统计
4
+
5
+ set -e
6
+
7
+ # 设置 jq 命令路径(支持自定义安装的 jq)
8
+ if [ -n "$JQ_PATH" ]; then
9
+ JQ_CMD="$JQ_PATH"
10
+ elif [ -f "$HOME/.claude/bin/jq.exe" ]; then
11
+ JQ_CMD="$HOME/.claude/bin/jq.exe"
12
+ elif [ -f "$HOME/.claude/bin/jq" ]; then
13
+ JQ_CMD="$HOME/.claude/bin/jq"
14
+ else
15
+ JQ_CMD="jq"
16
+ fi
17
+
18
+ # 验证 jq 是否可用
19
+ if ! command -v "$JQ_CMD" >/dev/null 2>&1; then
20
+ echo "Error: jq not found. Please install jq first:"
21
+ echo " Windows: npm install -g @winston.wan/burn-your-money"
22
+ echo " macOS: brew install jq"
23
+ echo " Linux: sudo apt-get install jq"
24
+ exit 1
25
+ fi
26
+
27
+ # 文件路径
28
+ STATS_CACHE="$HOME/.claude/stats-cache.json"
29
+ TODAY=$(date +%Y-%m-%d)
30
+ CURRENT_MONTH=$(date +%Y-%m)
31
+ LAST_MONTH=$(date -d "1 month ago" +%Y-%m 2>/dev/null || python3 -c "from datetime import datetime; print((datetime.now().replace(day=1) - __import__('datetime').timedelta(days=1)).strftime('%Y-%m'))")
32
+
33
+ # 获取本周一的日期
34
+ get_week_start() {
35
+ local day_of_week=$(date +%u) # 1=Monday, 7=Sunday
36
+ local days_to_subtract=$((day_of_week - 1))
37
+ date -d "$days_to_subtract days ago" +%Y-%m-%d 2>/dev/null || \
38
+ python3 -c "from datetime import datetime, timedelta; d = datetime.now() - timedelta(days=$(date +%u) - 1); print(d.strftime('%Y-%m-%d'))"
39
+ }
40
+
41
+ # 获取本月第一天
42
+ get_month_start() {
43
+ date +%Y-%m-01
44
+ }
45
+
46
+ WEEK_START=$(get_week_start)
47
+ MONTH_START=$(get_month_start)
48
+ LAST_MONTH_START=$(date -d "$LAST_MONTH-01" +%Y-%m-%d 2>/dev/null || echo "$LAST_MONTH-01")
49
+
50
+ # 从 stats-cache.json 读取统计数据
51
+ read_stats() {
52
+ if [ ! -f "$STATS_CACHE" ]; then
53
+ "$JQ_CMD" -n '{
54
+ today_tokens:0,today_cost:0,
55
+ week_tokens:0,week_cost:0,
56
+ month_tokens:0,month_cost:0,
57
+ last_month_tokens:0,last_month_cost:0,
58
+ total_tokens_all:0,total_cost:0,
59
+ daily_data: []
60
+ }'
61
+ return
62
+ fi
63
+
64
+ # 获取今日 token:总计 - 历史每日总和(排除今天)
65
+ # 修改:聚合所有模型的 input 和 output tokens
66
+ local total_io_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[] | (.inputTokens + .outputTokens)] | add // 0' 2>/dev/null || echo "0")
67
+
68
+ # 修改:聚合每日数据中所有模型的 token
69
+ local history_sum=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date != \"$TODAY\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
70
+ local today_data=$((total_io_tokens - history_sum))
71
+ [ "$today_data" -lt 0 ] && today_data=0
72
+
73
+ # 本周 token(排除今天,用上面的 today_data)
74
+ local week_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date >= \"$WEEK_START\" and .date != \"$TODAY\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
75
+ week_tokens=$((week_tokens + today_data))
76
+
77
+ # 本月 token
78
+ local month_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date >= \"$MONTH_START\" and .date != \"$TODAY\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
79
+ month_tokens=$((month_tokens + today_data))
80
+
81
+ # 上月 token
82
+ local last_month_tokens=$(cat "$STATS_CACHE" | $JQ_CMD -r "[.dailyModelTokens[] | select(.date >= \"$LAST_MONTH_START\" and .date < \"$MONTH_START\") | (.tokensByModel[] // 0)] | add // 0" 2>/dev/null || echo "0")
83
+
84
+ # 计算全部历史费用(使用 jq 进行精确计算,避免 awk 大数字精度问题)
85
+ # 修改:聚合所有模型的 usage
86
+ local total_input=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[].inputTokens // 0] | add // 0' 2>/dev/null || echo "0")
87
+ local total_output=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[].outputTokens // 0] | add // 0' 2>/dev/null || echo "0")
88
+ local total_cache_read=$(cat "$STATS_CACHE" | $JQ_CMD -r '[.modelUsage[].cacheReadInputTokens // 0] | add // 0' 2>/dev/null || echo "0")
89
+
90
+ # 估算总费用 (简单按 3/15/0.3 规则,虽然不同模型费率不同,但作为估算足够)
91
+ # 如果要精确需针对模型 loop,这里简化为聚合
92
+ local total_cost=$(cat "$STATS_CACHE" | $JQ_CMD -r '
93
+ [.modelUsage[]] | map(
94
+ ((.inputTokens // 0) / 1000000 * 3) +
95
+ ((.outputTokens // 0) / 1000000 * 15) +
96
+ ((.cacheReadInputTokens // 0) / 1000000 * 0.3)
97
+ ) | add | floor * 100 / 100
98
+ ' 2>/dev/null || echo "0")
99
+
100
+ # 总 token 数量(包含 cache)
101
+ local total_tokens_all=$((total_input + total_output + total_cache_read))
102
+
103
+ # 计算各周期费用(按比例分摊)
104
+ local week_cost="0.00"
105
+ local month_cost="0.00"
106
+ local last_month_cost="0.00"
107
+ local today_cost="0.00"
108
+
109
+ if [ "$total_io_tokens" != "0" ] && [ "$total_io_tokens" != "" ]; then
110
+ week_cost=$(awk "BEGIN {printf \"%.2f\", ${week_tokens} / ${total_io_tokens} * ${total_cost}}")
111
+ month_cost=$(awk "BEGIN {printf \"%.2f\", ${month_tokens} / ${total_io_tokens} * ${total_cost}}")
112
+ if [ "$last_month_tokens" -gt 0 ]; then
113
+ last_month_cost=$(awk "BEGIN {printf \"%.2f\", ${last_month_tokens} / ${total_io_tokens} * ${total_cost}}")
114
+ fi
115
+ else
116
+ week_cost=$total_cost
117
+ month_cost=$total_cost
118
+ fi
119
+
120
+ if [ "$week_tokens" != "0" ] && [ "$week_tokens" != "" ]; then
121
+ today_cost=$(awk "BEGIN {printf \"%.2f\", ${today_data} / ${week_tokens} * ${week_cost}}")
122
+ fi
123
+
124
+ # 获取每日数据(用于趋势图)
125
+ # 修改:聚合每日所有模型的 tokens
126
+ local daily_data=$(cat "$STATS_CACHE" | $JQ_CMD -c "[.dailyModelTokens[-7:][] | {date: .date, tokens: ([.tokensByModel[]] | add // 0)}]" 2>/dev/null || echo "[]")
127
+
128
+ # 输出 JSON
129
+ "$JQ_CMD" -n \
130
+ --arg today_tokens "$today_data" \
131
+ --arg today_cost "$today_cost" \
132
+ --arg week_tokens "$week_tokens" \
133
+ --arg week_cost "$week_cost" \
134
+ --arg month_tokens "$month_tokens" \
135
+ --arg month_cost "$month_cost" \
136
+ --arg last_month_tokens "$last_month_tokens" \
137
+ --arg last_month_cost "$last_month_cost" \
138
+ --arg total_tokens_all "$total_tokens_all" \
139
+ --arg total_cost "$total_cost" \
140
+ --argjson daily_data "$daily_data" \
141
+ '{
142
+ today_tokens: ($today_tokens | tonumber),
143
+ today_cost: ($today_cost | tonumber),
144
+ week_tokens: ($week_tokens | tonumber),
145
+ week_cost: ($week_cost | tonumber),
146
+ month_tokens: ($month_tokens | tonumber),
147
+ month_cost: ($month_cost | tonumber),
148
+ last_month_tokens: ($last_month_tokens | tonumber),
149
+ last_month_cost: ($last_month_cost | tonumber),
150
+ total_tokens_all: ($total_tokens_all | tonumber),
151
+ total_cost: ($total_cost | tonumber),
152
+ daily_data: $daily_data
153
+ }'
154
+ }
155
+
156
+ # 生成 ASCII 趋势图
157
+ generate_trend() {
158
+ local data="$1"
159
+ local max_tokens=0
160
+
161
+ # 找到最大值
162
+ for row in $(echo "$data" | $JQ_CMD -r '.[].tokens'); do
163
+ if [ "$row" -gt "$max_tokens" ]; then
164
+ max_tokens=$row
165
+ fi
166
+ done
167
+
168
+ # 生成图表
169
+ echo ""
170
+ echo "📊 过去 7 天 Token 趋势:"
171
+ echo ""
172
+
173
+ local count=0
174
+ for entry in $(echo "$data" | $JQ_CMD -c '.[]'); do
175
+ local date=$(echo "$entry" | $JQ_CMD -r '.date' | cut -c 6-)
176
+ local tokens=$(echo "$entry" | $JQ_CMD -r '.tokens')
177
+
178
+ # 计算条形长度
179
+ if [ "$max_tokens" -gt 0 ]; then
180
+ local bars=$(awk "BEGIN {printf \"%.0f\", $tokens / $max_tokens * 20}")
181
+ else
182
+ local bars=0
183
+ fi
184
+
185
+ # 生成条形
186
+ local bar=""
187
+ for i in $(seq 1 20); do
188
+ if [ "$i" -le "$bars" ]; then
189
+ bar+="█"
190
+ else
191
+ bar+="░"
192
+ fi
193
+ done
194
+
195
+ # 格式化 token 数量
196
+ local tokens_display=$(echo "$tokens" | awk '{
197
+ if ($1 >= 1000000) printf "%.1fM", $1/1000000
198
+ else if ($1 >= 1000) printf "%.1fK", $1/1000
199
+ else printf "%d", $1
200
+ }')
201
+
202
+ printf " %s │ %s │ %s\n" "$date" "$bar" "$tokens_display"
203
+ count=$((count + 1))
204
+ done
205
+ echo ""
206
+ }
207
+
208
+ # 导出数据
209
+ export_data() {
210
+ local format="$1"
211
+ local stats=$(read_stats)
212
+
213
+ case "$format" in
214
+ csv)
215
+ echo "date,tokens,cost"
216
+ echo "$stats" | $JQ_CMD -r '.daily_data[] | "\(.date),\(.tokens),\(.tokens * 0.000006)"'
217
+ ;;
218
+ json)
219
+ echo "$stats" | $JQ_CMD '.'
220
+ ;;
221
+ *)
222
+ echo "支持的格式: csv, json"
223
+ exit 1
224
+ ;;
225
+ esac
226
+ }
227
+
228
+ # 根据 mode 返回不同数据
229
+ MODE=${1:-summary}
230
+
231
+ case "$MODE" in
232
+ today_tokens)
233
+ read_stats | $JQ_CMD -r '.today_tokens'
234
+ ;;
235
+ today_cost)
236
+ read_stats | $JQ_CMD -r '.today_cost'
237
+ ;;
238
+ week_tokens)
239
+ read_stats | $JQ_CMD -r '.week_tokens'
240
+ ;;
241
+ week_cost)
242
+ read_stats | $JQ_CMD -r '.week_cost'
243
+ ;;
244
+ month_tokens)
245
+ read_stats | $JQ_CMD -r '.month_tokens'
246
+ ;;
247
+ month_cost)
248
+ read_stats | $JQ_CMD -r '.month_cost'
249
+ ;;
250
+ last_month_tokens)
251
+ read_stats | $JQ_CMD -r '.last_month_tokens'
252
+ ;;
253
+ last_month_cost)
254
+ read_stats | $JQ_CMD -r '.last_month_cost'
255
+ ;;
256
+ trend)
257
+ read_stats | $JQ_CMD -r '.daily_data'
258
+ ;;
259
+ chart)
260
+ generate_trend "$(read_stats | $JQ_CMD -r '.daily_data')"
261
+ ;;
262
+ export)
263
+ export_data "$2"
264
+ ;;
265
+ summary|json|*)
266
+ read_stats
267
+ ;;
268
+ esac
@@ -1,28 +0,0 @@
1
- Stack trace:
2
- Frame Function Args
3
- 0007FFFFBA30 00021005FE8E (000210285F68, 00021026AB6E, 000000000000, 0007FFFFA930) msys-2.0.dll+0x1FE8E
4
- 0007FFFFBA30 0002100467F9 (000000000000, 000000000000, 000000000000, 0007FFFFBD08) msys-2.0.dll+0x67F9
5
- 0007FFFFBA30 000210046832 (000210286019, 0007FFFFB8E8, 000000000000, 000000000000) msys-2.0.dll+0x6832
6
- 0007FFFFBA30 000210068CF6 (000000000000, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28CF6
7
- 0007FFFFBA30 000210068E24 (0007FFFFBA40, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x28E24
8
- 0007FFFFBD10 00021006A225 (0007FFFFBA40, 000000000000, 000000000000, 000000000000) msys-2.0.dll+0x2A225
9
- End of stack trace
10
- Loaded modules:
11
- 000100400000 bash.exe
12
- 7FFAC83A0000 ntdll.dll
13
- 7FFAC7620000 KERNEL32.DLL
14
- 7FFAC57F0000 KERNELBASE.dll
15
- 7FFAC7C30000 USER32.dll
16
- 000210040000 msys-2.0.dll
17
- 7FFAC54F0000 win32u.dll
18
- 7FFAC74C0000 GDI32.dll
19
- 7FFAC5EA0000 gdi32full.dll
20
- 7FFAC5CA0000 msvcp_win.dll
21
- 7FFAC5D50000 ucrtbase.dll
22
- 7FFAC7070000 advapi32.dll
23
- 7FFAC7570000 msvcrt.dll
24
- 7FFAC6140000 sechost.dll
25
- 7FFAC69C0000 RPCRT4.dll
26
- 7FFAC4AF0000 CRYPTBASE.DLL
27
- 7FFAC5BF0000 bcryptPrimitives.dll
28
- 7FFAC7E00000 IMM32.DLL