minimax-status 1.1.13 → 1.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 +25 -21
- package/cli/api.js +13 -11
- 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
|
@@ -134,10 +134,10 @@ npm run package
|
|
|
134
134
|
集成成功后,底部状态栏将显示:
|
|
135
135
|
|
|
136
136
|
```
|
|
137
|
-
my-app
|
|
137
|
+
my-app ❯ main * ❯ MiniMax-M2 ❯ 60% (2700/4500) ❯ 1h20m ❯ 剩5天
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
显示格式:`目录
|
|
140
|
+
显示格式:`目录 ❯ 分支 ❯ 模型 ❯ 百分比(剩余/总数) ❯ 倒计时 ❯ 到期天数`
|
|
141
141
|
|
|
142
142
|
**颜色说明**:
|
|
143
143
|
|
|
@@ -219,18 +219,10 @@ my-app │ main * │ ...
|
|
|
219
219
|
集成成功后,底部状态栏将显示:
|
|
220
220
|
|
|
221
221
|
```
|
|
222
|
-
minimax-status
|
|
222
|
+
minimax-status ❯ main * ❯ 10% (4047/4500) ❯ 12m ❯ 剩21天
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
显示格式:`目录
|
|
226
|
-
|
|
227
|
-
### 进度条风格
|
|
228
|
-
|
|
229
|
-
使用 `█` 和 `░` 字符显示进度条:
|
|
230
|
-
|
|
231
|
-
- `█░░░░░░░░` - 10% 使用量
|
|
232
|
-
- `█████░░░░` - 50% 使用量
|
|
233
|
-
- `██████████` - 100% 使用量
|
|
225
|
+
显示格式:`目录 ❯ 分支 ❯ 百分比(剩余/总数) ❯ 倒计时 ❯ 到期天数`
|
|
234
226
|
|
|
235
227
|
**颜色说明**:
|
|
236
228
|
|
|
@@ -277,6 +269,16 @@ minimax-status │ main * │ Usage █░░░░░░░░ 10% (4047/4500)
|
|
|
277
269
|
[● MiniMax-M2 27% • 3307/4500 • 1h26m ⚡
|
|
278
270
|
```
|
|
279
271
|
|
|
272
|
+
## 截图演示
|
|
273
|
+
|
|
274
|
+
### Claude Code 集成
|
|
275
|
+
|
|
276
|
+

|
|
277
|
+
|
|
278
|
+
### Droid 集成
|
|
279
|
+
|
|
280
|
+

|
|
281
|
+
|
|
280
282
|
## 命令说明
|
|
281
283
|
|
|
282
284
|
| 命令 | 描述 | 示例 |
|
|
@@ -297,18 +299,10 @@ minimax-status │ main * │ Usage █░░░░░░░░ 10% (4047/4500)
|
|
|
297
299
|
| 分支 | Git 分支名称 |
|
|
298
300
|
| 模型 | MiniMax 模型名称 |
|
|
299
301
|
| 上下文 | 上下文窗口使用率 |
|
|
300
|
-
| Usage |
|
|
302
|
+
| Usage | 使用量百分比(剩余/总数) |
|
|
301
303
|
| ⏱ | 额度重置倒计时 |
|
|
302
304
|
| 到期 | 订阅到期时间(颜色动态变化) |
|
|
303
305
|
|
|
304
|
-
### 进度条
|
|
305
|
-
|
|
306
|
-
使用 `█` 和 `░` 字符显示进度条:
|
|
307
|
-
|
|
308
|
-
- `█░░░░░░░░` - 10% 使用量
|
|
309
|
-
- `█████░░░░░` - 50% 使用量
|
|
310
|
-
- `██████████` - 100% 使用量
|
|
311
|
-
|
|
312
306
|
### 颜色规则
|
|
313
307
|
|
|
314
308
|
| 场景 | 颜色 | 说明 |
|
|
@@ -407,6 +401,16 @@ MIT License - 详见 [LICENSE](LICENSE) 文件
|
|
|
407
401
|
|
|
408
402
|
欢迎提交 Issue 和 Pull Request!
|
|
409
403
|
|
|
404
|
+
## 导航
|
|
405
|
+
|
|
406
|
+
| 客户端 | 路径 | 说明 |
|
|
407
|
+
|--------|------|------|
|
|
408
|
+
| **CLI** | [`cli/`](cli/) | 命令行工具,npm 全局包 |
|
|
409
|
+
| **VSCode** | [`vscode-extension/`](vscode-extension/) | VSCode 状态栏集成 |
|
|
410
|
+
| **OpenClaw** | [`openclaw/`](openclaw/) | OpenClaw 集成 |
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
410
414
|
## 相关链接
|
|
411
415
|
|
|
412
416
|
- [MiniMax 开放平台](https://platform.minimaxi.com/)
|
package/cli/api.js
CHANGED
|
@@ -80,7 +80,7 @@ class MinimaxAPI {
|
|
|
80
80
|
|
|
81
81
|
try {
|
|
82
82
|
const response = await axios.get(
|
|
83
|
-
`https://www.minimaxi.com/v1/
|
|
83
|
+
`https://www.minimaxi.com/v1/token_plan/remains`,
|
|
84
84
|
{
|
|
85
85
|
headers: {
|
|
86
86
|
Authorization: `Bearer ${this.token}`,
|
|
@@ -295,9 +295,9 @@ class MinimaxAPI {
|
|
|
295
295
|
const endTime = new Date(modelData.end_time);
|
|
296
296
|
|
|
297
297
|
// Calculate counts
|
|
298
|
-
//
|
|
299
|
-
const
|
|
300
|
-
const
|
|
298
|
+
// 新接口 usage_count 是已使用次数(正确值)
|
|
299
|
+
const usedCount = modelData.current_interval_usage_count;
|
|
300
|
+
const remainingCount = modelData.current_interval_total_count - usedCount;
|
|
301
301
|
|
|
302
302
|
// Calculate percentage - 基于已使用次数的百分比
|
|
303
303
|
const usedPercentage = Math.round(
|
|
@@ -310,7 +310,7 @@ class MinimaxAPI {
|
|
|
310
310
|
const minutes = Math.floor((remainingMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
311
311
|
|
|
312
312
|
// Calculate weekly usage data
|
|
313
|
-
const weeklyUsed = modelData.
|
|
313
|
+
const weeklyUsed = modelData.current_weekly_usage_count;
|
|
314
314
|
const weeklyTotal = modelData.current_weekly_total_count;
|
|
315
315
|
const weeklyPercentage = weeklyTotal > 0 ? Math.floor((weeklyUsed / weeklyTotal) * 100) : 0;
|
|
316
316
|
const weeklyRemainingMs = modelData.weekly_remains_time;
|
|
@@ -382,8 +382,8 @@ class MinimaxAPI {
|
|
|
382
382
|
: `${minutes} 分钟后重置`,
|
|
383
383
|
},
|
|
384
384
|
usage: {
|
|
385
|
-
used: usedCount,
|
|
386
|
-
remaining: remainingCount,
|
|
385
|
+
used: usedCount,
|
|
386
|
+
remaining: remainingCount,
|
|
387
387
|
total: modelData.current_interval_total_count,
|
|
388
388
|
percentage: usedPercentage,
|
|
389
389
|
},
|
|
@@ -415,13 +415,15 @@ class MinimaxAPI {
|
|
|
415
415
|
|
|
416
416
|
return apiData.model_remains.map(modelData => {
|
|
417
417
|
const totalCount = modelData.current_interval_total_count;
|
|
418
|
-
|
|
419
|
-
const usedCount =
|
|
418
|
+
// 新接口 usage_count 是已使用次数(正确值)
|
|
419
|
+
const usedCount = modelData.current_interval_usage_count;
|
|
420
|
+
const remainingCount = totalCount - usedCount;
|
|
420
421
|
const usedPercentage = totalCount > 0 ? Math.round((usedCount / totalCount) * 100) : 0;
|
|
421
422
|
|
|
422
423
|
// Weekly data
|
|
423
424
|
const weeklyTotal = modelData.current_weekly_total_count || 0;
|
|
424
|
-
const weeklyUsed =
|
|
425
|
+
const weeklyUsed = modelData.current_weekly_usage_count || 0;
|
|
426
|
+
const weeklyRemainingCount = weeklyTotal - weeklyUsed;
|
|
425
427
|
const weeklyPercentage = weeklyTotal > 0 ? Math.floor((weeklyUsed / weeklyTotal) * 100) : 0;
|
|
426
428
|
|
|
427
429
|
return {
|
|
@@ -433,7 +435,7 @@ class MinimaxAPI {
|
|
|
433
435
|
unlimited: weeklyTotal === 0,
|
|
434
436
|
weeklyPercentage,
|
|
435
437
|
weeklyTotal,
|
|
436
|
-
weeklyRemainingCount
|
|
438
|
+
weeklyRemainingCount,
|
|
437
439
|
};
|
|
438
440
|
});
|
|
439
441
|
}
|
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
|
}
|