minimax-status 1.1.13 → 1.1.14
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 +10 -0
- package/cli/index.js +71 -48
- package/cli/renderer.js +74 -68
- package/cli/status.js +21 -21
- package/cli/transcript-parser.js +23 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -407,6 +407,16 @@ MIT License - 详见 [LICENSE](LICENSE) 文件
|
|
|
407
407
|
|
|
408
408
|
欢迎提交 Issue 和 Pull Request!
|
|
409
409
|
|
|
410
|
+
## 导航
|
|
411
|
+
|
|
412
|
+
| 客户端 | 路径 | 说明 |
|
|
413
|
+
|--------|------|------|
|
|
414
|
+
| **CLI** | [`cli/`](cli/) | 命令行工具,npm 全局包 |
|
|
415
|
+
| **VSCode** | [`vscode-extension/`](vscode-extension/) | VSCode 状态栏集成 |
|
|
416
|
+
| **OpenClaw** | [`openclaw/`](openclaw/) | OpenClaw 集成 |
|
|
417
|
+
|
|
418
|
+
---
|
|
419
|
+
|
|
410
420
|
## 相关链接
|
|
411
421
|
|
|
412
422
|
- [MiniMax 开放平台](https://platform.minimaxi.com/)
|
package/cli/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// Force color output even in non-TTY environments (e.g., Claude Code statusline)
|
|
4
4
|
process.env.FORCE_COLOR = "1";
|
|
@@ -350,13 +350,17 @@ program
|
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
//
|
|
354
|
-
let contextUsageValue =
|
|
353
|
+
// 优先使用 Claude Code 提供的实时 tokens_used,如果没有则回退到 transcript 解析
|
|
354
|
+
let contextUsageValue = 0;
|
|
355
355
|
let contextSizeValue = contextSize;
|
|
356
356
|
|
|
357
357
|
if (stdinData?.context_window) {
|
|
358
358
|
const cw = stdinData.context_window;
|
|
359
359
|
contextSizeValue = cw.context_window_size || contextSize;
|
|
360
|
+
// 关键点:优先取这里,这是最实时的
|
|
361
|
+
contextUsageValue = cw.tokens_used || contextUsageTokens || 0;
|
|
362
|
+
} else {
|
|
363
|
+
contextUsageValue = contextUsageTokens || 0;
|
|
360
364
|
}
|
|
361
365
|
|
|
362
366
|
const context = {
|
|
@@ -634,66 +638,85 @@ program
|
|
|
634
638
|
// ignore errors
|
|
635
639
|
}
|
|
636
640
|
|
|
637
|
-
|
|
638
|
-
function getBarColor(p) {
|
|
639
|
-
if (p >= 85) return chalk.red;
|
|
640
|
-
if (p >= 60) return chalk.yellow;
|
|
641
|
-
return chalk.green;
|
|
642
|
-
}
|
|
643
|
-
const coloredBar = (percent, width = 10) => {
|
|
644
|
-
const filled = Math.round((percent / 100) * width);
|
|
645
|
-
const empty = width - filled;
|
|
646
|
-
const barColor = getBarColor(percent);
|
|
647
|
-
return barColor('█'.repeat(filled) + '\x1b[2m' + '░'.repeat(empty) + '\x1b[0m');
|
|
648
|
-
};
|
|
641
|
+
const blocks = [];
|
|
649
642
|
|
|
650
|
-
//
|
|
651
|
-
const parts = [];
|
|
652
|
-
|
|
653
|
-
// 目录
|
|
643
|
+
// 高对比度徽章配色,纯 Powerline 渲染
|
|
654
644
|
if (currentDir) {
|
|
655
|
-
|
|
645
|
+
blocks.push({ text: ` ${currentDir} `, bg: '#1D4ED8' }); // 皇家蓝
|
|
656
646
|
}
|
|
657
647
|
|
|
658
|
-
|
|
648
|
+
const useNerdFonts = !process.env.MINIMAX_PLAIN_UI && !process.env.NO_NERD_FONTS;
|
|
649
|
+
const arrow = useNerdFonts ? '\uE0B0' : '>';
|
|
650
|
+
const branchIcon = useNerdFonts ? '\uE0A0' : '*';
|
|
651
|
+
|
|
659
652
|
if (gitBranch && gitBranch.name) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
let branchStr = branchColor(gitBranch.name);
|
|
653
|
+
let branchStr = gitBranch.name;
|
|
654
|
+
if (branchStr.length > 20) branchStr = branchStr.substring(0, 10) + '…' + branchStr.substring(branchStr.length - 7);
|
|
663
655
|
if (gitBranch.hasChanges) {
|
|
664
|
-
branchStr +=
|
|
656
|
+
branchStr += ' *';
|
|
665
657
|
}
|
|
666
|
-
|
|
658
|
+
blocks.push({ text: ` ${branchIcon} ${branchStr} `, bg: '#7E22CE' }); // 紫色回归
|
|
667
659
|
}
|
|
668
660
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
if (weekly
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
661
|
+
if (usage && usage.total > 0) {
|
|
662
|
+
let bg = '#065F46'; // 回归稳健的深翠绿 (Emerald 800)
|
|
663
|
+
if (usage.percentage >= 95) bg = '#991B1B'; // danger (Red 800)
|
|
664
|
+
else if (usage.percentage >= 75) bg = '#9A3412'; // warn (Orange 800)
|
|
665
|
+
|
|
666
|
+
let usageText = ` ${usage.percentage}% (${usage.remaining}/${usage.total}) `;
|
|
667
|
+
if (weekly) {
|
|
668
|
+
if (weekly.unlimited) {
|
|
669
|
+
usageText += `· W ∞ `;
|
|
670
|
+
} else {
|
|
671
|
+
usageText += `· W ${weekly.percentage}% `;
|
|
672
|
+
}
|
|
680
673
|
}
|
|
674
|
+
blocks.push({ text: usageText, bg: bg });
|
|
681
675
|
}
|
|
682
|
-
parts.push(usageLine);
|
|
683
676
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
677
|
+
if (remaining) {
|
|
678
|
+
const remainingText = remaining.hours > 0
|
|
679
|
+
? `${remaining.hours}h${remaining.minutes}m`
|
|
680
|
+
: `${remaining.minutes}m`;
|
|
681
|
+
blocks.push({ text: ` ${remainingText} `, bg: '#92400E' });
|
|
682
|
+
}
|
|
689
683
|
|
|
690
|
-
// 到期
|
|
691
684
|
if (expiry) {
|
|
692
|
-
|
|
693
|
-
|
|
685
|
+
let bg = '#374151'; // Gray 700
|
|
686
|
+
if (expiry.daysRemaining <= 7) bg = '#9A3412';
|
|
687
|
+
if (expiry.daysRemaining <= 3) bg = '#991B1B';
|
|
688
|
+
blocks.push({ text: ` 剩${expiry.daysRemaining}天 `, bg: bg });
|
|
694
689
|
}
|
|
695
|
-
|
|
696
|
-
|
|
690
|
+
|
|
691
|
+
let out = '';
|
|
692
|
+
const leftArrow = useNerdFonts ? '\uE0B0' : '>';
|
|
693
|
+
|
|
694
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
695
|
+
const b = blocks[i];
|
|
696
|
+
|
|
697
|
+
// 磁贴开启:顺行式起点,利用黑色箭头实现内凹镂空感
|
|
698
|
+
if (i === 0) {
|
|
699
|
+
out += '\u001b[0m' + chalk.bgHex(b.bg).black(leftArrow);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// 磁贴文字内容
|
|
703
|
+
out += '\u001b[0m' + chalk.bgHex(b.bg).bold.whiteBright(b.text);
|
|
704
|
+
|
|
705
|
+
if (i < blocks.length - 1) {
|
|
706
|
+
const nextB = blocks[i + 1];
|
|
707
|
+
if (useNerdFonts) {
|
|
708
|
+
// 衔接尖部
|
|
709
|
+
out += '\u001b[0m' + chalk.bgHex(nextB.bg).hex(b.bg)(arrow);
|
|
710
|
+
} else {
|
|
711
|
+
out += '\u001b[0m' + chalk.bgHex(b.bg).bold.whiteBright(arrow);
|
|
712
|
+
}
|
|
713
|
+
} else {
|
|
714
|
+
// 最后一块磁贴:顺行式终点
|
|
715
|
+
out += '\u001b[0m' + chalk.hex(b.bg)(arrow);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
console.log(out);
|
|
697
720
|
});
|
|
698
721
|
|
|
699
722
|
// 模型上下文窗口大小(仅MiniMax模型)
|
package/cli/renderer.js
CHANGED
|
@@ -5,6 +5,15 @@ const chalk = require('chalk').default;
|
|
|
5
5
|
class Renderer {
|
|
6
6
|
constructor() {
|
|
7
7
|
this.RESET = '\x1b[0m';
|
|
8
|
+
// 自动检测:如果环境变量设置了 MINIMAX_PLAIN_UI 或者是 NO_NERD_FONTS,则停用特殊图标
|
|
9
|
+
this.useNerdFonts = !process.env.MINIMAX_PLAIN_UI && !process.env.NO_NERD_FONTS;
|
|
10
|
+
|
|
11
|
+
// 图标配置
|
|
12
|
+
this.icons = {
|
|
13
|
+
arrow: this.useNerdFonts ? '\uE0B0' : '>',
|
|
14
|
+
leftArrow: this.useNerdFonts ? '\uE0B0' : '>', // 改为顺向箭头,实现顺行感
|
|
15
|
+
branch: this.useNerdFonts ? '\uE0A0' : '*'
|
|
16
|
+
};
|
|
8
17
|
}
|
|
9
18
|
|
|
10
19
|
formatTokens(tokens) {
|
|
@@ -60,94 +69,91 @@ class Renderer {
|
|
|
60
69
|
|
|
61
70
|
renderSessionLine(data) {
|
|
62
71
|
const {
|
|
63
|
-
modelName,
|
|
64
|
-
|
|
65
|
-
usagePercentage,
|
|
66
|
-
usage,
|
|
67
|
-
remaining,
|
|
68
|
-
expiry,
|
|
69
|
-
contextUsage,
|
|
70
|
-
contextSize,
|
|
71
|
-
configCounts,
|
|
72
|
-
sessionDuration,
|
|
73
|
-
weekly,
|
|
72
|
+
modelName, currentDir, usagePercentage, usage,
|
|
73
|
+
remaining, expiry, contextUsage, contextSize, weekly, gitBranch
|
|
74
74
|
} = data;
|
|
75
75
|
|
|
76
|
-
const
|
|
76
|
+
const blocks = [];
|
|
77
77
|
|
|
78
|
+
// Pure Powerline Data Blocks
|
|
78
79
|
if (currentDir) {
|
|
79
|
-
|
|
80
|
+
blocks.push({ text: ` ${currentDir} `, bg: '#2563EB', fg: '#FFFFFF' });
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
if (gitBranch && gitBranch.name) {
|
|
84
|
+
let name = gitBranch.name;
|
|
85
|
+
if (name.length > 20) name = name.substring(0, 10) + '…' + name.substring(name.length - 7);
|
|
86
|
+
const star = gitBranch.hasChanges ? ' *' : '';
|
|
87
|
+
blocks.push({ text: ` ${this.icons.branch} ${name}${star} `, bg: '#9333EA', fg: '#FFFFFF' });
|
|
88
|
+
}
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
90
|
+
if (modelName) {
|
|
91
|
+
blocks.push({ text: ` ${modelName} `, bg: '#4C1D95', fg: '#FFFFFF' });
|
|
92
|
+
}
|
|
89
93
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
94
|
+
if (contextSize) {
|
|
95
|
+
if (contextUsage) {
|
|
96
|
+
const pct = Math.round((contextUsage / contextSize) * 100);
|
|
97
|
+
blocks.push({ text: ` ${pct}% · ${this.formatTokens(contextUsage)} `, bg: '#0369A1', fg: '#FFFFFF' });
|
|
98
|
+
} else {
|
|
99
|
+
blocks.push({ text: ` ${this.formatContextSize(contextSize)} `, bg: '#0369A1', fg: '#FFFFFF' });
|
|
96
100
|
}
|
|
101
|
+
}
|
|
97
102
|
|
|
98
|
-
|
|
99
|
-
let
|
|
100
|
-
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
103
|
+
if (usage && usage.total > 0) {
|
|
104
|
+
let bg = '#065F46'; // safe (Emerald 800 - dark enough for white text)
|
|
105
|
+
if (usagePercentage >= 95) bg = '#991B1B'; // danger (Red 800)
|
|
106
|
+
else if (usagePercentage >= 75) bg = '#9A3412'; // warn (Orange 800)
|
|
107
|
+
|
|
108
|
+
let usageText = ` ${usagePercentage}% (${usage.remaining}/${usage.total}) `;
|
|
109
|
+
|
|
110
|
+
if (weekly) {
|
|
111
|
+
if (weekly.unlimited) {
|
|
112
|
+
usageText += `· W ∞ `;
|
|
113
|
+
} else {
|
|
114
|
+
usageText += `· W ${weekly.percentage}% `;
|
|
115
|
+
}
|
|
104
116
|
}
|
|
105
|
-
|
|
106
|
-
parts.push(branchStr);
|
|
117
|
+
blocks.push({ text: usageText, bg: bg, fg: '#FFFFFF' });
|
|
107
118
|
}
|
|
108
119
|
|
|
109
|
-
|
|
110
|
-
|
|
120
|
+
if (remaining) {
|
|
121
|
+
const remainingText = remaining.hours > 0 ? `${remaining.hours}h${remaining.minutes}m` : `${remaining.minutes}m`;
|
|
122
|
+
blocks.push({ text: ` ${remainingText} `, bg: '#92400E', fg: '#FFFFFF' });
|
|
123
|
+
}
|
|
111
124
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
} else {
|
|
118
|
-
parts.push(chalk.cyan(this.formatContextSize(contextSize)));
|
|
125
|
+
if (expiry) {
|
|
126
|
+
let bg = '#374151'; // Gray 700
|
|
127
|
+
if (expiry.daysRemaining <= 7) bg = '#9A3412';
|
|
128
|
+
if (expiry.daysRemaining <= 3) bg = '#991B1B';
|
|
129
|
+
blocks.push({ text: ` 剩${expiry.daysRemaining}天 `, bg: bg, fg: '#FFFFFF' });
|
|
119
130
|
}
|
|
120
131
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
// Powerline arrow seamless integration
|
|
133
|
+
let out = '';
|
|
134
|
+
const arrow = this.icons.arrow;
|
|
135
|
+
|
|
136
|
+
for (let i = 0; i < blocks.length; i++) {
|
|
137
|
+
const b = blocks[i];
|
|
138
|
+
// 顺行式起点:使用正向箭头 + 黑色前景色模拟内凹效果
|
|
139
|
+
if (i === 0) {
|
|
140
|
+
out += this.RESET + chalk.bgHex(b.bg).black(this.icons.leftArrow);
|
|
141
|
+
}
|
|
142
|
+
// 磁贴文字
|
|
143
|
+
out += chalk.bgHex(b.bg).whiteBright(b.text);
|
|
144
|
+
if (i < blocks.length - 1) {
|
|
145
|
+
const nextB = blocks[i + 1];
|
|
146
|
+
if (this.useNerdFonts) {
|
|
147
|
+
out += chalk.bgHex(nextB.bg).hex(b.bg)(arrow);
|
|
148
|
+
} else {
|
|
149
|
+
out += chalk.bgHex(b.bg).whiteBright(arrow);
|
|
150
|
+
}
|
|
131
151
|
} else {
|
|
132
|
-
|
|
133
|
-
usageLine += ` ${chalk.gray('·')} ${chalk.blue('W')} ${weeklyColor(weekly.percentage + '%')}`;
|
|
152
|
+
out += chalk.hex(b.bg)(arrow);
|
|
134
153
|
}
|
|
135
154
|
}
|
|
136
|
-
parts.push(usageLine);
|
|
137
|
-
|
|
138
|
-
// 倒计时 - 保留图标
|
|
139
|
-
const remainingText = remaining.hours > 0
|
|
140
|
-
? `${remaining.hours}h${remaining.minutes}m`
|
|
141
|
-
: `${remaining.minutes}m`;
|
|
142
|
-
parts.push(`${chalk.yellow('⏱')} ${remainingText}`);
|
|
143
|
-
|
|
144
|
-
// 到期 - 保留图标
|
|
145
|
-
if (expiry) {
|
|
146
|
-
const expiryColor = expiry.daysRemaining <= 3 ? chalk.red : expiry.daysRemaining <= 7 ? chalk.yellow : chalk.green;
|
|
147
|
-
parts.push(`${expiryColor('到期 ' + expiry.daysRemaining + '天')}`);
|
|
148
|
-
}
|
|
149
155
|
|
|
150
|
-
return
|
|
156
|
+
return out;
|
|
151
157
|
}
|
|
152
158
|
|
|
153
159
|
renderToolsLine(tools) {
|
package/cli/status.js
CHANGED
|
@@ -79,14 +79,14 @@ class StatusBar {
|
|
|
79
79
|
|
|
80
80
|
// 获取状态颜色
|
|
81
81
|
const getStatusColor = (percentage) => {
|
|
82
|
-
if (percentage >= 85) return chalk.
|
|
83
|
-
if (percentage >= 60) return chalk.
|
|
84
|
-
return chalk.
|
|
82
|
+
if (percentage >= 85) return chalk.hex('#EF4444');
|
|
83
|
+
if (percentage >= 60) return chalk.hex('#F59E0B');
|
|
84
|
+
return chalk.hex('#10B981');
|
|
85
85
|
};
|
|
86
86
|
|
|
87
87
|
// 显示状态
|
|
88
88
|
const getStatusText = (percentage) => {
|
|
89
|
-
if (percentage >= 85) return '
|
|
89
|
+
if (percentage >= 85) return '⛔';
|
|
90
90
|
if (percentage >= 60) return '⚡';
|
|
91
91
|
return '✓';
|
|
92
92
|
};
|
|
@@ -166,11 +166,11 @@ class StatusBar {
|
|
|
166
166
|
contentLines.push('');
|
|
167
167
|
if (weekly.unlimited) {
|
|
168
168
|
// 不受限制
|
|
169
|
-
contentLines.push(`${chalk.cyan('周限额:')} ${chalk.
|
|
169
|
+
contentLines.push(`${chalk.cyan('周限额:')} ${chalk.hex('#10B981')('不受限制')}`);
|
|
170
170
|
} else {
|
|
171
171
|
// 有限制,显示具体数据
|
|
172
172
|
const weeklyPercent = weekly.percentage;
|
|
173
|
-
const weeklyColor = weeklyPercent >= 85 ? chalk.
|
|
173
|
+
const weeklyColor = weeklyPercent >= 85 ? chalk.hex('#EF4444') : weeklyPercent >= 60 ? chalk.hex('#F59E0B') : chalk.hex('#10B981');
|
|
174
174
|
const weeklyProgress = this.createProgressBar(
|
|
175
175
|
Math.floor((weeklyPercent / 100) * 15),
|
|
176
176
|
15 - Math.floor((weeklyPercent / 100) * 15),
|
|
@@ -222,11 +222,11 @@ class StatusBar {
|
|
|
222
222
|
|
|
223
223
|
// 进度条颜色基于已使用百分比:使用越多越危险(红色)
|
|
224
224
|
if (percentage >= 85) {
|
|
225
|
-
return chalk.
|
|
225
|
+
return chalk.hex('#EF4444')(bar);
|
|
226
226
|
} else if (percentage >= 60) {
|
|
227
|
-
return chalk.
|
|
227
|
+
return chalk.hex('#F59E0B')(bar);
|
|
228
228
|
} else {
|
|
229
|
-
return chalk.
|
|
229
|
+
return chalk.hex('#10B981')(bar);
|
|
230
230
|
}
|
|
231
231
|
}
|
|
232
232
|
|
|
@@ -240,18 +240,18 @@ class StatusBar {
|
|
|
240
240
|
|
|
241
241
|
getStatusColor(status) {
|
|
242
242
|
if (status === '⚡ 注意使用') {
|
|
243
|
-
return chalk.
|
|
244
|
-
} else if (status === '
|
|
245
|
-
return chalk.
|
|
243
|
+
return chalk.hex('#F59E0B')(status);
|
|
244
|
+
} else if (status === '⛔ 即将用完') {
|
|
245
|
+
return chalk.hex('#EF4444')(status);
|
|
246
246
|
} else {
|
|
247
|
-
return chalk.
|
|
247
|
+
return chalk.hex('#10B981')(status);
|
|
248
248
|
}
|
|
249
249
|
}
|
|
250
250
|
|
|
251
251
|
getStatus(percentage) {
|
|
252
252
|
// 基于已使用百分比
|
|
253
253
|
if (percentage >= 85) {
|
|
254
|
-
return '
|
|
254
|
+
return '⛔ 即将用完';
|
|
255
255
|
} else if (percentage >= 60) {
|
|
256
256
|
return '⚡ 注意使用';
|
|
257
257
|
} else {
|
|
@@ -266,11 +266,11 @@ class StatusBar {
|
|
|
266
266
|
// 颜色基于已使用百分比:使用越多越危险
|
|
267
267
|
let color;
|
|
268
268
|
if (usage.percentage >= 85) {
|
|
269
|
-
color = chalk.
|
|
269
|
+
color = chalk.hex('#EF4444');
|
|
270
270
|
} else if (usage.percentage >= 60) {
|
|
271
|
-
color = chalk.
|
|
271
|
+
color = chalk.hex('#F59E0B');
|
|
272
272
|
} else {
|
|
273
|
-
color = chalk.
|
|
273
|
+
color = chalk.hex('#10B981');
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
// 添加到期信息(如果可用)
|
|
@@ -298,14 +298,14 @@ class StatusBar {
|
|
|
298
298
|
// 颜色基于百分比
|
|
299
299
|
let color;
|
|
300
300
|
if (model.percentage >= 85) {
|
|
301
|
-
color = chalk.
|
|
301
|
+
color = chalk.hex('#EF4444');
|
|
302
302
|
} else if (model.percentage >= 60) {
|
|
303
|
-
color = chalk.
|
|
303
|
+
color = chalk.hex('#F59E0B');
|
|
304
304
|
} else {
|
|
305
|
-
color = chalk.
|
|
305
|
+
color = chalk.hex('#10B981');
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
const status = model.percentage >= 85 ? '
|
|
308
|
+
const status = model.percentage >= 85 ? '⛔ 即将用完' : model.percentage >= 60 ? '⚡ 注意' : '✓ 正常';
|
|
309
309
|
const name = model.name.length > 28 ? model.name.substring(0, 25) + '...' : model.name;
|
|
310
310
|
|
|
311
311
|
lines.push(`│ ${name.padEnd(30)} ${color(`${model.used}/${model.total} (${model.percentage}%)`).padEnd(15)} ${color(status)}`);
|
package/cli/transcript-parser.js
CHANGED
|
@@ -147,36 +147,43 @@ class TranscriptParser {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
try {
|
|
150
|
-
const
|
|
151
|
-
const
|
|
150
|
+
const stats = fs.statSync(transcriptPath);
|
|
151
|
+
const fileSize = stats.size;
|
|
152
|
+
const bufferSize = Math.min(fileSize, 64 * 1024); // 读取最后 64KB
|
|
153
|
+
const buffer = Buffer.alloc(bufferSize);
|
|
154
|
+
|
|
155
|
+
const fd = fs.openSync(transcriptPath, 'r');
|
|
156
|
+
fs.readSync(fd, buffer, 0, bufferSize, Math.max(0, fileSize - bufferSize));
|
|
157
|
+
fs.closeSync(fd);
|
|
152
158
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
159
|
+
const content = buffer.toString('utf8');
|
|
160
|
+
const lines = content.split('\n').filter(line => line.trim());
|
|
156
161
|
|
|
157
|
-
|
|
158
|
-
const lastEntry = JSON.parse(lastLine);
|
|
162
|
+
if (lines.length === 0) return null;
|
|
159
163
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
164
|
+
// 检查最后一行是否是 summary
|
|
165
|
+
const lastLine = lines[lines.length - 1].trim();
|
|
166
|
+
try {
|
|
167
|
+
const lastEntry = JSON.parse(lastLine);
|
|
168
|
+
if (lastEntry.type === 'summary' && lastEntry.leafUuid) {
|
|
169
|
+
return this.findUsageByUuid(transcriptPath, lastEntry.leafUuid);
|
|
170
|
+
}
|
|
171
|
+
} catch (e) {}
|
|
163
172
|
|
|
173
|
+
// 从后往前找最近的 assistant usage
|
|
164
174
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
165
|
-
const line = lines[i].trim();
|
|
166
|
-
if (!line) continue;
|
|
167
|
-
|
|
168
175
|
try {
|
|
169
|
-
const entry = JSON.parse(
|
|
176
|
+
const entry = JSON.parse(lines[i]);
|
|
170
177
|
if (entry.type === 'assistant' && entry.message?.usage) {
|
|
171
178
|
return this.calculateContextTokens(entry.message.usage);
|
|
172
179
|
}
|
|
173
|
-
} catch {
|
|
180
|
+
} catch (e) {
|
|
174
181
|
continue;
|
|
175
182
|
}
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
return null;
|
|
179
|
-
} catch {
|
|
186
|
+
} catch (error) {
|
|
180
187
|
return null;
|
|
181
188
|
}
|
|
182
189
|
}
|