@winston.wan/burn-your-money 3.0.1 → 3.0.3
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/package.json +1 -1
- package/src/statusline.js +48 -3
- package/src/token-history.js +26 -44
package/package.json
CHANGED
package/src/statusline.js
CHANGED
|
@@ -172,18 +172,63 @@ function main() {
|
|
|
172
172
|
try {
|
|
173
173
|
const { execSync } = require('child_process');
|
|
174
174
|
const scriptPath = path.join(__dirname, 'token-history.js');
|
|
175
|
-
|
|
175
|
+
// 使用更兼容的方式执行脚本
|
|
176
|
+
const freshData = execSync(`node "${scriptPath}" summary`, {
|
|
177
|
+
encoding: 'utf8',
|
|
178
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
179
|
+
});
|
|
176
180
|
historyData = JSON.parse(freshData);
|
|
177
181
|
historyData._cache_time = now;
|
|
178
182
|
writeJsonFile(HISTORY_CACHE, historyData);
|
|
179
183
|
} catch (e) {
|
|
180
|
-
//
|
|
184
|
+
// 如果获取失败,尝试直接读取 stats-cache.json 作为降级方案
|
|
185
|
+
try {
|
|
186
|
+
const statsCache = path.join(os.homedir(), '.claude', 'stats-cache.json');
|
|
187
|
+
const stats = JSON.parse(fs.readFileSync(statsCache, 'utf8'));
|
|
188
|
+
|
|
189
|
+
// 从 stats-cache.json 构建基本数据
|
|
190
|
+
const totalInput = Object.values(stats.modelUsage || {}).reduce((sum, m) => sum + (m.inputTokens || 0), 0);
|
|
191
|
+
const totalOutput = Object.values(stats.modelUsage || {}).reduce((sum, m) => sum + (m.outputTokens || 0), 0);
|
|
192
|
+
const totalCache = Object.values(stats.modelUsage || {}).reduce((sum, m) => sum + (m.cacheReadInputTokens || 0), 0);
|
|
193
|
+
const totalTokens = totalInput + totalOutput + totalCache;
|
|
194
|
+
const totalCost = (totalInput / 1000000 * 3) + (totalOutput / 1000000 * 15) + (totalCache / 1000000 * 0.3);
|
|
195
|
+
|
|
196
|
+
historyData = {
|
|
197
|
+
total_tokens_all: totalTokens,
|
|
198
|
+
total_cost: totalCost.toFixed(2),
|
|
199
|
+
today_tokens: 0,
|
|
200
|
+
today_cost: '0.00',
|
|
201
|
+
week_tokens: 0,
|
|
202
|
+
week_cost: '0.00',
|
|
203
|
+
month_tokens: 0,
|
|
204
|
+
month_cost: '0.00',
|
|
205
|
+
_cache_time: now
|
|
206
|
+
};
|
|
207
|
+
writeJsonFile(HISTORY_CACHE, historyData);
|
|
208
|
+
} catch (e2) {
|
|
209
|
+
// 如果降级方案也失败,使用旧缓存或默认值
|
|
210
|
+
if (!historyData || !historyData.total_tokens_all) {
|
|
211
|
+
historyData = {
|
|
212
|
+
total_tokens_all: 0,
|
|
213
|
+
total_cost: '0.00',
|
|
214
|
+
today_tokens: 0,
|
|
215
|
+
today_cost: '0.00',
|
|
216
|
+
_cache_time: now
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
}
|
|
181
220
|
}
|
|
182
221
|
}
|
|
183
222
|
|
|
184
223
|
// 如果缓存不存在或无效,使用默认值(但保留已有数据)
|
|
185
224
|
if (!historyData || typeof historyData !== 'object') {
|
|
186
|
-
historyData = {
|
|
225
|
+
historyData = {
|
|
226
|
+
total_tokens_all: 0,
|
|
227
|
+
total_cost: '0.00',
|
|
228
|
+
today_tokens: 0,
|
|
229
|
+
today_cost: '0.00',
|
|
230
|
+
_cache_time: now
|
|
231
|
+
};
|
|
187
232
|
}
|
|
188
233
|
|
|
189
234
|
// 确保 _cache_time 存在(如果是旧缓存,添加时间戳)
|
package/src/token-history.js
CHANGED
|
@@ -78,38 +78,18 @@ function readStats() {
|
|
|
78
78
|
const totalOutputTokens = Object.values(data.modelUsage || {}).reduce((sum, model) => sum + (model.outputTokens || 0), 0);
|
|
79
79
|
const totalCacheReadTokens = Object.values(data.modelUsage || {}).reduce((sum, model) => sum + (model.cacheReadInputTokens || 0), 0);
|
|
80
80
|
|
|
81
|
-
//
|
|
82
|
-
// 注意:dailyModelTokens 不包含缓存 tokens,且可能更新不及时
|
|
83
|
-
// 如果 lastComputedDate 不是今天,今日数据可能不准确
|
|
84
|
-
const lastComputedDate = data.lastComputedDate || '';
|
|
81
|
+
// 计算今日 tokens(总计 - 历史每日总和,排除今天)
|
|
85
82
|
const dailyTokens = data.dailyModelTokens || [];
|
|
83
|
+
let historySum = 0;
|
|
84
|
+
dailyTokens.forEach(day => {
|
|
85
|
+
if (day.date !== TODAY) {
|
|
86
|
+
const models = day.tokensByModel || {};
|
|
87
|
+
historySum += Object.values(models).reduce((sum, tokens) => sum + (tokens || 0), 0);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
86
90
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
// 检查是否有今日的 dailyModelTokens 记录
|
|
90
|
-
const todayEntry = dailyTokens.find(day => day.date === TODAY);
|
|
91
|
-
let todayTokens = 0;
|
|
92
|
-
if (todayEntry) {
|
|
93
|
-
const models = todayEntry.tokensByModel || {};
|
|
94
|
-
todayTokens = Object.values(models).reduce((sum, tokens) => sum + (tokens || 0), 0);
|
|
95
|
-
// 补偿缓存 tokens(按比例估算)
|
|
96
|
-
const cacheRatio = totalCacheReadTokens / (totalTokensAll || 1);
|
|
97
|
-
todayTokens = Math.floor(todayTokens * (1 + cacheRatio));
|
|
98
|
-
} else if (lastComputedDate !== TODAY) {
|
|
99
|
-
// lastComputedDate 不是今天,无法准确计算今日 tokens
|
|
100
|
-
todayTokens = 0;
|
|
101
|
-
} else {
|
|
102
|
-
// 尝试从总量推算(可能不准确)
|
|
103
|
-
let historySum = 0;
|
|
104
|
-
dailyTokens.forEach(day => {
|
|
105
|
-
if (day.date !== TODAY) {
|
|
106
|
-
const models = day.tokensByModel || {};
|
|
107
|
-
historySum += Object.values(models).reduce((sum, tokens) => sum + (tokens || 0), 0);
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
todayTokens = totalTokensAll - historySum;
|
|
111
|
-
if (todayTokens < 0) todayTokens = 0;
|
|
112
|
-
}
|
|
91
|
+
const todayTokens = totalInputTokens + totalOutputTokens - historySum;
|
|
92
|
+
if (todayTokens < 0) todayTokens = 0;
|
|
113
93
|
|
|
114
94
|
// 本周 tokens(排除今天,用上面的 todayTokens)
|
|
115
95
|
const WEEK_START = getWeekStart();
|
|
@@ -143,17 +123,18 @@ function readStats() {
|
|
|
143
123
|
}
|
|
144
124
|
});
|
|
145
125
|
|
|
146
|
-
//
|
|
126
|
+
// 计算费用(简化:按 3/15/0.3 规则)
|
|
147
127
|
const totalCost = (totalInputTokens / 1000000 * 3) +
|
|
148
128
|
(totalOutputTokens / 1000000 * 15) +
|
|
149
129
|
(totalCacheReadTokens / 1000000 * 0.3);
|
|
150
130
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
const
|
|
131
|
+
const totalTokensAll = totalInputTokens + totalOutputTokens + totalCacheReadTokens;
|
|
132
|
+
|
|
133
|
+
// 计算各周期费用(按比例分摊)
|
|
134
|
+
const todayCost = todayTokens > 0 ? (todayTokens / (totalInputTokens + totalOutputTokens) * totalCost) : 0;
|
|
135
|
+
const weekCost = weekTokens > 0 ? (weekTokens / (totalInputTokens + totalOutputTokens) * totalCost) : 0;
|
|
136
|
+
const monthCost = monthTokens > 0 ? (monthTokens / (totalInputTokens + totalOutputTokens) * totalCost) : 0;
|
|
137
|
+
const lastMonthCost = lastMonthTokens > 0 ? (lastMonthTokens / (totalInputTokens + totalOutputTokens) * totalCost) : 0;
|
|
157
138
|
|
|
158
139
|
// 获取每日数据(用于趋势图)
|
|
159
140
|
const dailyData = dailyTokens.slice(-7).map(day => ({
|
|
@@ -276,13 +257,6 @@ function main() {
|
|
|
276
257
|
console.log('');
|
|
277
258
|
|
|
278
259
|
// 统计数据
|
|
279
|
-
console.log('💰 Token 价格说明');
|
|
280
|
-
console.log('─'.repeat(40));
|
|
281
|
-
console.log(' Input: $3.00 / 百万 tokens');
|
|
282
|
-
console.log(' Output: $15.00 / 百万 tokens');
|
|
283
|
-
console.log(' Cache: $0.30 / 百万 tokens (90% 折扣)');
|
|
284
|
-
console.log('');
|
|
285
|
-
|
|
286
260
|
console.log('📆 本周消费');
|
|
287
261
|
console.log('─'.repeat(40));
|
|
288
262
|
console.log(` Tokens: ${formatNumber(stats.week_tokens)}`);
|
|
@@ -301,6 +275,14 @@ function main() {
|
|
|
301
275
|
console.log(` 费用: $${stats.total_cost}`);
|
|
302
276
|
console.log('');
|
|
303
277
|
|
|
278
|
+
// Token 价格说明
|
|
279
|
+
console.log('💰 Token 价格说明');
|
|
280
|
+
console.log('─'.repeat(40));
|
|
281
|
+
console.log(' Input: $3.00 / 百万 tokens');
|
|
282
|
+
console.log(' Output: $15.00 / 百万 tokens');
|
|
283
|
+
console.log(' Cache: $0.30 / 百万 tokens (90% 折扣)');
|
|
284
|
+
console.log('');
|
|
285
|
+
|
|
304
286
|
// 有趣的统计
|
|
305
287
|
const totalCostNum = parseFloat(stats.total_cost);
|
|
306
288
|
const totalTokensNum = stats.total_tokens_all;
|