minimax-status 1.1.10 → 1.1.12
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 +5 -5
- package/cli/api.js +49 -3
- package/cli/index.js +16 -20
- package/cli/renderer.js +7 -3
- package/cli/status.js +52 -10
- package/cli/statusbar.js +12 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,19 +5,19 @@
|
|
|
5
5
|
[](https://opensource.org/licenses/MIT)
|
|
6
6
|
[](https://marketplace.visualstudio.com/items?itemName=JochenYang.minimax-status-vscode)
|
|
7
7
|
|
|
8
|
-
MiniMax
|
|
8
|
+
MiniMax Token-Plan 使用状态监控工具,支持 CLI 命令和 Claude Code 状态栏集成。
|
|
9
9
|
|
|
10
10
|
## 版本
|
|
11
11
|
|
|
12
12
|
| 插件 | 版本 | 安装方式 |
|
|
13
13
|
|------|------|----------|
|
|
14
|
-
| **CLI** | 1.1.
|
|
15
|
-
| **VSCode** | 1.2.
|
|
14
|
+
| **CLI** | 1.1.11 | `npm install -g minimax-status` |
|
|
15
|
+
| **VSCode** | 1.2.7 | [VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=JochenYang.minimax-status-vscode) 或 [下载 VSIX](https://github.com/JochenYang/minimax-status/releases) |
|
|
16
16
|
| **OpenClaw** | - | 参考 `openclaw/minimax-usage/` 目录 |
|
|
17
17
|
|
|
18
18
|
## 特性
|
|
19
19
|
|
|
20
|
-
- ✅ **实时状态监控**: 显示 MiniMax
|
|
20
|
+
- ✅ **实时状态监控**: 显示 MiniMax Token-Plan 使用额度、剩余次数、重置时间
|
|
21
21
|
- ✅ **上下文窗口跟踪**: 智能解析转录文件,准确显示当前会话的上下文使用量
|
|
22
22
|
- ✅ **多种显示模式**: 详细模式、紧凑模式、持续状态栏
|
|
23
23
|
- ✅ **Claude Code 集成**: 可在 Claude Code 底部状态栏显示
|
|
@@ -413,4 +413,4 @@ MIT License - 详见 [LICENSE](LICENSE) 文件
|
|
|
413
413
|
|
|
414
414
|
---
|
|
415
415
|
|
|
416
|
-
**注意**: 本工具仅用于监控 MiniMax
|
|
416
|
+
**注意**: 本工具仅用于监控 MiniMax Token-Plan 用量使用状态,不存储或传输任何用户数据。
|
package/cli/api.js
CHANGED
|
@@ -173,10 +173,11 @@ class MinimaxAPI {
|
|
|
173
173
|
|
|
174
174
|
/**
|
|
175
175
|
* Fetch all billing records with pagination
|
|
176
|
-
* @param {number} maxPages - Maximum number of pages to fetch
|
|
176
|
+
* @param {number} maxPages - Maximum number of pages to fetch (default 100)
|
|
177
|
+
* @param {number} minStartTime - Optional: stop fetching when records are older than this time (ms)
|
|
177
178
|
* @returns {Promise<Array>} All billing records
|
|
178
179
|
*/
|
|
179
|
-
async getAllBillingRecords(maxPages =
|
|
180
|
+
async getAllBillingRecords(maxPages = 100, minStartTime = 0) {
|
|
180
181
|
const allRecords = [];
|
|
181
182
|
|
|
182
183
|
for (let page = 1; page <= maxPages; page++) {
|
|
@@ -190,6 +191,15 @@ class MinimaxAPI {
|
|
|
190
191
|
|
|
191
192
|
allRecords.push(...records);
|
|
192
193
|
|
|
194
|
+
// 如果传入了时间范围,检查是否需要继续获取
|
|
195
|
+
if (minStartTime > 0) {
|
|
196
|
+
const lastRecord = records[records.length - 1];
|
|
197
|
+
const lastRecordTime = (lastRecord.created_at || 0) * 1000;
|
|
198
|
+
if (lastRecordTime < minStartTime) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
193
203
|
if (records.length < 100) {
|
|
194
204
|
break;
|
|
195
205
|
}
|
|
@@ -302,7 +312,7 @@ class MinimaxAPI {
|
|
|
302
312
|
// Calculate weekly usage data
|
|
303
313
|
const weeklyUsed = modelData.current_weekly_total_count - modelData.current_weekly_usage_count;
|
|
304
314
|
const weeklyTotal = modelData.current_weekly_total_count;
|
|
305
|
-
const weeklyPercentage = Math.floor((weeklyUsed / weeklyTotal) * 100);
|
|
315
|
+
const weeklyPercentage = weeklyTotal > 0 ? Math.floor((weeklyUsed / weeklyTotal) * 100) : 0;
|
|
306
316
|
const weeklyRemainingMs = modelData.weekly_remains_time;
|
|
307
317
|
const weeklyDays = Math.floor(weeklyRemainingMs / (1000 * 60 * 60 * 24));
|
|
308
318
|
const weeklyHours = Math.floor((weeklyRemainingMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
|
@@ -383,6 +393,7 @@ class MinimaxAPI {
|
|
|
383
393
|
percentage: weeklyPercentage,
|
|
384
394
|
days: weeklyDays,
|
|
385
395
|
hours: weeklyHours,
|
|
396
|
+
unlimited: weeklyTotal === 0,
|
|
386
397
|
text: weeklyDays > 0
|
|
387
398
|
? `${weeklyDays} 天 ${weeklyHours} 小时后重置`
|
|
388
399
|
: `${weeklyHours} 小时后重置`,
|
|
@@ -391,6 +402,41 @@ class MinimaxAPI {
|
|
|
391
402
|
expiry: expiryInfo,
|
|
392
403
|
};
|
|
393
404
|
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Parse all models from API data
|
|
408
|
+
* @param {Object} apiData - Raw API response
|
|
409
|
+
* @returns {Array} Array of model usage data
|
|
410
|
+
*/
|
|
411
|
+
parseAllModels(apiData) {
|
|
412
|
+
if (!apiData.model_remains || apiData.model_remains.length === 0) {
|
|
413
|
+
return [];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
return apiData.model_remains.map(modelData => {
|
|
417
|
+
const totalCount = modelData.current_interval_total_count;
|
|
418
|
+
const remainingCount = modelData.current_interval_usage_count;
|
|
419
|
+
const usedCount = totalCount - remainingCount;
|
|
420
|
+
const usedPercentage = totalCount > 0 ? Math.round((usedCount / totalCount) * 100) : 0;
|
|
421
|
+
|
|
422
|
+
// Weekly data
|
|
423
|
+
const weeklyTotal = modelData.current_weekly_total_count || 0;
|
|
424
|
+
const weeklyUsed = weeklyTotal > 0 ? (modelData.current_weekly_total_count - modelData.current_weekly_usage_count) : 0;
|
|
425
|
+
const weeklyPercentage = weeklyTotal > 0 ? Math.floor((weeklyUsed / weeklyTotal) * 100) : 0;
|
|
426
|
+
|
|
427
|
+
return {
|
|
428
|
+
name: modelData.model_name,
|
|
429
|
+
used: usedCount,
|
|
430
|
+
remaining: remainingCount,
|
|
431
|
+
total: totalCount,
|
|
432
|
+
percentage: usedPercentage,
|
|
433
|
+
unlimited: weeklyTotal === 0,
|
|
434
|
+
weeklyPercentage,
|
|
435
|
+
weeklyTotal,
|
|
436
|
+
weeklyRemainingCount: modelData.current_weekly_usage_count || 0,
|
|
437
|
+
};
|
|
438
|
+
});
|
|
439
|
+
}
|
|
394
440
|
}
|
|
395
441
|
|
|
396
442
|
module.exports = MinimaxAPI;
|
package/cli/index.js
CHANGED
|
@@ -118,24 +118,12 @@ program
|
|
|
118
118
|
// 获取账单数据用于消耗统计
|
|
119
119
|
let usageStats = null;
|
|
120
120
|
try {
|
|
121
|
-
|
|
121
|
+
// 按自然月统计当月消耗
|
|
122
|
+
const now = new Date();
|
|
123
|
+
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1, 0, 0, 0, 0).getTime();
|
|
124
|
+
const billingRecords = await api.getAllBillingRecords(100, monthStart);
|
|
122
125
|
if (billingRecords.length > 0) {
|
|
123
|
-
|
|
124
|
-
let planStartTime = 0;
|
|
125
|
-
if (subscriptionData &&
|
|
126
|
-
subscriptionData.current_subscribe &&
|
|
127
|
-
subscriptionData.current_subscribe.current_subscribe_end_time) {
|
|
128
|
-
const expiryDateStr = subscriptionData.current_subscribe.current_subscribe_end_time;
|
|
129
|
-
const [month, day, year] = expiryDateStr.split('/').map(Number);
|
|
130
|
-
planStartTime = new Date(year, month - 2, day).getTime();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const now = Date.now();
|
|
134
|
-
usageStats = api.calculateUsageStats(
|
|
135
|
-
billingRecords,
|
|
136
|
-
planStartTime > 0 ? planStartTime : 0,
|
|
137
|
-
now
|
|
138
|
-
);
|
|
126
|
+
usageStats = api.calculateUsageStats(billingRecords, monthStart, now.getTime());
|
|
139
127
|
}
|
|
140
128
|
} catch (billingError) {
|
|
141
129
|
// 账单数据获取失败不影响主要功能
|
|
@@ -143,6 +131,7 @@ program
|
|
|
143
131
|
}
|
|
144
132
|
|
|
145
133
|
const statusBar = new StatusBar(usageData, usageStats, api);
|
|
134
|
+
const allModels = api.parseAllModels(apiData);
|
|
146
135
|
|
|
147
136
|
spinner.succeed("状态获取成功");
|
|
148
137
|
|
|
@@ -150,6 +139,7 @@ program
|
|
|
150
139
|
console.log(statusBar.renderCompact());
|
|
151
140
|
} else {
|
|
152
141
|
console.log("\n" + statusBar.render() + "\n");
|
|
142
|
+
console.log(StatusBar.renderAllModels(allModels) + "\n");
|
|
153
143
|
}
|
|
154
144
|
|
|
155
145
|
if (options.watch) {
|
|
@@ -176,10 +166,12 @@ program
|
|
|
176
166
|
api.getSubscriptionDetails(),
|
|
177
167
|
]);
|
|
178
168
|
const usageData = api.parseUsageData(apiData, subscriptionData);
|
|
169
|
+
const allModels = api.parseAllModels(apiData);
|
|
179
170
|
const statusBar = new StatusBar(usageData);
|
|
180
171
|
|
|
181
172
|
spinner.succeed("状态获取成功");
|
|
182
173
|
console.log("\n" + statusBar.render() + "\n");
|
|
174
|
+
console.log(StatusBar.renderAllModels(allModels) + "\n");
|
|
183
175
|
} catch (error) {
|
|
184
176
|
spinner.fail(chalk.red("获取状态失败"));
|
|
185
177
|
console.error(chalk.red(`错误: ${error.message}`));
|
|
@@ -677,11 +669,15 @@ program
|
|
|
677
669
|
// 使用量 - 进度条风格 (显示次数)
|
|
678
670
|
const usageBar = coloredBar(usage.percentage);
|
|
679
671
|
const usageColor = usage.percentage >= 85 ? chalk.red : usage.percentage >= 60 ? chalk.yellow : chalk.green;
|
|
680
|
-
let usageLine = `${
|
|
672
|
+
let usageLine = `${usageBar} ${usageColor(usage.percentage + '%')} (${usage.remaining}/${usage.total})`;
|
|
681
673
|
// 周用量紧跟在 usage 后面
|
|
682
674
|
if (weekly) {
|
|
683
|
-
|
|
684
|
-
|
|
675
|
+
if (weekly.unlimited) {
|
|
676
|
+
usageLine += ` ${chalk.gray('·')} ${chalk.blue('W')} ♾️`;
|
|
677
|
+
} else {
|
|
678
|
+
const weeklyColor = weekly.percentage >= 85 ? chalk.red : weekly.percentage >= 60 ? chalk.yellow : chalk.green;
|
|
679
|
+
usageLine += ` ${chalk.gray('·')} ${chalk.blue('W')} ${weeklyColor(weekly.percentage + '%')}`;
|
|
680
|
+
}
|
|
685
681
|
}
|
|
686
682
|
parts.push(usageLine);
|
|
687
683
|
|
package/cli/renderer.js
CHANGED
|
@@ -123,11 +123,15 @@ class Renderer {
|
|
|
123
123
|
const filled = Math.round((usagePercentage / 100) * 10);
|
|
124
124
|
const empty = 10 - filled;
|
|
125
125
|
const usageBar = usageColor('█'.repeat(filled) + '\x1b[2m' + '░'.repeat(empty) + '\x1b[0m');
|
|
126
|
-
let usageLine = `${
|
|
126
|
+
let usageLine = `${usageBar} ${usageColor(usagePercentage + '%')} (${usage.remaining}/${usage.total})`;
|
|
127
127
|
// 周用量紧跟在 usage 后面
|
|
128
128
|
if (weekly) {
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
if (weekly.unlimited) {
|
|
130
|
+
usageLine += ` ${chalk.gray('·')} ${chalk.blue('W')} ♾️`;
|
|
131
|
+
} else {
|
|
132
|
+
const weeklyColor = this.getStatusColor(weekly.percentage);
|
|
133
|
+
usageLine += ` ${chalk.gray('·')} ${chalk.blue('W')} ${weeklyColor(weekly.percentage + '%')}`;
|
|
134
|
+
}
|
|
131
135
|
}
|
|
132
136
|
parts.push(usageLine);
|
|
133
137
|
|
package/cli/status.js
CHANGED
|
@@ -49,7 +49,7 @@ class StatusBar {
|
|
|
49
49
|
|
|
50
50
|
lines.push(formatLine('昨日消耗: ', this.usageStats.lastDayUsage));
|
|
51
51
|
lines.push(formatLine('近7天消耗: ', this.usageStats.weeklyUsage));
|
|
52
|
-
lines.push(formatLine('
|
|
52
|
+
lines.push(formatLine('当月消耗: ', this.usageStats.planTotalUsage));
|
|
53
53
|
|
|
54
54
|
return lines.join('\n');
|
|
55
55
|
}
|
|
@@ -113,15 +113,21 @@ class StatusBar {
|
|
|
113
113
|
// 周用量(如果有数据)
|
|
114
114
|
if (weekly) {
|
|
115
115
|
contentLines.push('');
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
weeklyPercent
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
116
|
+
if (weekly.unlimited) {
|
|
117
|
+
// 不受限制
|
|
118
|
+
contentLines.push(`${chalk.cyan('周限额:')} ${chalk.green('不受限制')}`);
|
|
119
|
+
} else {
|
|
120
|
+
// 有限制,显示具体数据
|
|
121
|
+
const weeklyPercent = weekly.percentage;
|
|
122
|
+
const weeklyColor = weeklyPercent >= 85 ? chalk.red : weeklyPercent >= 60 ? chalk.yellow : chalk.green;
|
|
123
|
+
const weeklyProgress = this.createProgressBar(
|
|
124
|
+
Math.floor((weeklyPercent / 100) * 15),
|
|
125
|
+
15 - Math.floor((weeklyPercent / 100) * 15),
|
|
126
|
+
weeklyPercent
|
|
127
|
+
);
|
|
128
|
+
contentLines.push(`${chalk.cyan('周限额:')} ${weeklyColor(weeklyProgress)} ${weeklyColor(weekly.percentage + '%')} (${weekly.used}/${weekly.total})`);
|
|
129
|
+
contentLines.push(`${chalk.dim(' 重置:')} ${weekly.text}`);
|
|
130
|
+
}
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
// 添加到期行(如果可用)
|
|
@@ -216,6 +222,42 @@ class StatusBar {
|
|
|
216
222
|
|
|
217
223
|
return `${color('●')} ${modelName} ${usage.percentage}% ${chalk.dim(`(${usage.remaining}/${usage.total})`)} ${chalk.gray('•')} ${remaining.text} ${chalk.gray('•')} ${status}${expiryInfo}`;
|
|
218
224
|
}
|
|
225
|
+
|
|
226
|
+
// 渲染所有模型的额度
|
|
227
|
+
static renderAllModels(models) {
|
|
228
|
+
if (!models || models.length === 0) {
|
|
229
|
+
return '';
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const lines = [];
|
|
233
|
+
lines.push('');
|
|
234
|
+
lines.push(chalk.bold('📋 所有模型额度'));
|
|
235
|
+
|
|
236
|
+
// 表头
|
|
237
|
+
lines.push(chalk.gray('─'.repeat(55)));
|
|
238
|
+
lines.push(`│ ${chalk.cyan('模型').padEnd(30)} ${chalk.cyan('已用/总额').padEnd(15)} ${chalk.cyan('状态')}`);
|
|
239
|
+
lines.push(chalk.gray('─'.repeat(55)));
|
|
240
|
+
|
|
241
|
+
for (const model of models) {
|
|
242
|
+
// 颜色基于百分比
|
|
243
|
+
let color;
|
|
244
|
+
if (model.percentage >= 85) {
|
|
245
|
+
color = chalk.red;
|
|
246
|
+
} else if (model.percentage >= 60) {
|
|
247
|
+
color = chalk.yellow;
|
|
248
|
+
} else {
|
|
249
|
+
color = chalk.green;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const status = model.percentage >= 85 ? '⚠ 即将用完' : model.percentage >= 60 ? '⚡ 注意' : '✓ 正常';
|
|
253
|
+
const name = model.name.length > 28 ? model.name.substring(0, 25) + '...' : model.name;
|
|
254
|
+
|
|
255
|
+
lines.push(`│ ${name.padEnd(30)} ${color(`${model.used}/${model.total} (${model.percentage}%)`).padEnd(15)} ${color(status)}`);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
lines.push(chalk.gray('─'.repeat(55)));
|
|
259
|
+
return lines.join('\n');
|
|
260
|
+
}
|
|
219
261
|
}
|
|
220
262
|
|
|
221
263
|
module.exports = StatusBar;
|
package/cli/statusbar.js
CHANGED
|
@@ -10,7 +10,7 @@ class StatusBar {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
render() {
|
|
13
|
-
const { usage, remaining, modelName } = this.data;
|
|
13
|
+
const { usage, remaining, modelName, weekly } = this.data;
|
|
14
14
|
const percentage = usage.percentage;
|
|
15
15
|
|
|
16
16
|
// 基于已使用百分比:使用越多越危险
|
|
@@ -26,7 +26,17 @@ class StatusBar {
|
|
|
26
26
|
? `${remaining.hours}h${remaining.minutes}m`
|
|
27
27
|
: `${remaining.minutes}m`;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
let weeklyStr = '';
|
|
30
|
+
if (weekly) {
|
|
31
|
+
if (weekly.unlimited) {
|
|
32
|
+
weeklyStr = ` ${chalk.blue('W')} ♾️`;
|
|
33
|
+
} else {
|
|
34
|
+
const weeklyColor = weekly.percentage >= 85 ? chalk.red : weekly.percentage >= 60 ? chalk.yellow : chalk.green;
|
|
35
|
+
weeklyStr = ` ${chalk.blue('W')} ${weeklyColor(weekly.percentage + '%')}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return `${color('●')} ${modelName} ${color(percentage + '%')} (${usage.used}/${usage.total}) ${remainingText}${weeklyStr} ${statusIcon}`;
|
|
30
40
|
}
|
|
31
41
|
}
|
|
32
42
|
|