minimax-status 1.0.0 → 1.0.1
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/cli/api.js +125 -0
- package/cli/prompts.js +112 -0
- package/cli/status.js +107 -0
- package/package.json +1 -1
- package/vscode-extension/api.js +97 -0
- package/vscode-extension/extension.js +136 -0
package/cli/api.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
class MinimaxAPI {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.token = null;
|
|
8
|
+
this.groupId = null;
|
|
9
|
+
this.configPath = path.join(process.env.HOME || process.env.USERPROFILE, '.minimax-config.json');
|
|
10
|
+
this.loadConfig();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
loadConfig() {
|
|
14
|
+
try {
|
|
15
|
+
// 只从独立的 config 文件读取
|
|
16
|
+
if (fs.existsSync(this.configPath)) {
|
|
17
|
+
const config = JSON.parse(fs.readFileSync(this.configPath, 'utf8'));
|
|
18
|
+
this.token = config.token;
|
|
19
|
+
this.groupId = config.groupId;
|
|
20
|
+
}
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('Failed to load config:', error.message);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
saveConfig() {
|
|
27
|
+
try {
|
|
28
|
+
// 保存到独立的 config 文件
|
|
29
|
+
const config = {
|
|
30
|
+
token: this.token,
|
|
31
|
+
groupId: this.groupId
|
|
32
|
+
};
|
|
33
|
+
fs.writeFileSync(this.configPath, JSON.stringify(config, null, 2));
|
|
34
|
+
} catch (error) {
|
|
35
|
+
console.error('Failed to save config:', error.message);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setCredentials(token, groupId) {
|
|
40
|
+
this.token = token;
|
|
41
|
+
this.groupId = groupId;
|
|
42
|
+
this.saveConfig();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async getUsageStatus() {
|
|
46
|
+
if (!this.token || !this.groupId) {
|
|
47
|
+
throw new Error('Missing credentials. Please run "minimax-status auth <token> <groupId>" first');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
try {
|
|
51
|
+
const response = await axios.get(
|
|
52
|
+
`https://www.minimaxi.com/v1/api/openplatform/coding_plan/remains`,
|
|
53
|
+
{
|
|
54
|
+
params: { GroupId: this.groupId },
|
|
55
|
+
headers: {
|
|
56
|
+
'Authorization': `Bearer ${this.token}`,
|
|
57
|
+
'Accept': 'application/json'
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return response.data;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
if (error.response?.status === 401) {
|
|
65
|
+
throw new Error('Invalid token or unauthorized. Please check your credentials.');
|
|
66
|
+
}
|
|
67
|
+
throw new Error(`API request failed: ${error.message}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
parseUsageData(apiData) {
|
|
72
|
+
if (!apiData.model_remains || apiData.model_remains.length === 0) {
|
|
73
|
+
throw new Error('No usage data available');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const modelData = apiData.model_remains[0];
|
|
77
|
+
const startTime = new Date(modelData.start_time);
|
|
78
|
+
const endTime = new Date(modelData.end_time);
|
|
79
|
+
const now = new Date();
|
|
80
|
+
|
|
81
|
+
// Calculate counts
|
|
82
|
+
// 注意:current_interval_usage_count 实际是剩余次数,不是已用次数
|
|
83
|
+
const remainingCount = modelData.current_interval_usage_count;
|
|
84
|
+
const usedCount = modelData.current_interval_total_count - remainingCount;
|
|
85
|
+
|
|
86
|
+
// Calculate percentage - 基于已使用次数的百分比
|
|
87
|
+
const usedPercentage = Math.round((usedCount / modelData.current_interval_total_count) * 100);
|
|
88
|
+
|
|
89
|
+
// Calculate remaining time in human-readable format
|
|
90
|
+
const remainingMs = modelData.remains_time;
|
|
91
|
+
const hours = Math.floor(remainingMs / (1000 * 60 * 60));
|
|
92
|
+
const minutes = Math.floor((remainingMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
modelName: modelData.model_name,
|
|
96
|
+
timeWindow: {
|
|
97
|
+
start: startTime.toLocaleTimeString('zh-CN', {
|
|
98
|
+
hour: '2-digit',
|
|
99
|
+
minute: '2-digit',
|
|
100
|
+
timeZone: 'Asia/Shanghai',
|
|
101
|
+
hour12: false
|
|
102
|
+
}),
|
|
103
|
+
end: endTime.toLocaleTimeString('zh-CN', {
|
|
104
|
+
hour: '2-digit',
|
|
105
|
+
minute: '2-digit',
|
|
106
|
+
timeZone: 'Asia/Shanghai',
|
|
107
|
+
hour12: false
|
|
108
|
+
}),
|
|
109
|
+
timezone: 'UTC+8'
|
|
110
|
+
},
|
|
111
|
+
remaining: {
|
|
112
|
+
hours,
|
|
113
|
+
minutes,
|
|
114
|
+
text: hours > 0 ? `${hours} 小时 ${minutes} 分钟后重置` : `${minutes} 分钟后重置`
|
|
115
|
+
},
|
|
116
|
+
usage: {
|
|
117
|
+
used: remainingCount,
|
|
118
|
+
total: modelData.current_interval_total_count,
|
|
119
|
+
percentage: usedPercentage
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
module.exports = MinimaxAPI;
|
package/cli/prompts.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const MinimaxAPI = require('./api');
|
|
4
|
+
const chalk = require('chalk').default;
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
|
|
8
|
+
class PromptStatus {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.api = new MinimaxAPI();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async loadSettings() {
|
|
14
|
+
// Try to load from settings.json in various locations
|
|
15
|
+
const possiblePaths = [
|
|
16
|
+
path.join(process.env.HOME || process.env.USERPROFILE, '.claude', 'settings.json'),
|
|
17
|
+
path.join(process.env.HOME || process.env.USERPROFILE, '.config', 'claude', 'settings.json'),
|
|
18
|
+
path.join(process.cwd(), '.claude-settings.json'),
|
|
19
|
+
path.join(process.cwd(), '.claude', 'settings.json'),
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
for (const configPath of possiblePaths) {
|
|
23
|
+
if (fs.existsSync(configPath)) {
|
|
24
|
+
try {
|
|
25
|
+
const settings = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
26
|
+
if (settings.minimaxToken && settings.minimaxGroupId) {
|
|
27
|
+
this.api.setCredentials(settings.minimaxToken, settings.minimaxGroupId);
|
|
28
|
+
return settings.minimaxStatus || {};
|
|
29
|
+
}
|
|
30
|
+
} catch (error) {
|
|
31
|
+
console.error(`Failed to read settings from ${configPath}:`, error.message);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async getPromptStatus(mode = 'compact') {
|
|
40
|
+
try {
|
|
41
|
+
await this.loadSettings();
|
|
42
|
+
const apiData = await this.api.getUsageStatus();
|
|
43
|
+
const usageData = this.api.parseUsageData(apiData);
|
|
44
|
+
|
|
45
|
+
if (mode === 'compact') {
|
|
46
|
+
return this.renderCompact(usageData);
|
|
47
|
+
} else if (mode === 'minimal') {
|
|
48
|
+
return this.renderMinimal(usageData);
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
renderMinimal(data) {
|
|
57
|
+
const { usage } = data;
|
|
58
|
+
const percentage = usage.percentage;
|
|
59
|
+
|
|
60
|
+
let color = chalk.green;
|
|
61
|
+
if (percentage >= 85) {
|
|
62
|
+
color = chalk.red;
|
|
63
|
+
} else if (percentage >= 60) {
|
|
64
|
+
color = chalk.yellow;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return color(`[MM:${percentage}%]`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
renderCompact(data) {
|
|
71
|
+
const { usage, remaining, modelName } = data;
|
|
72
|
+
const percentage = usage.percentage;
|
|
73
|
+
|
|
74
|
+
let color = chalk.green;
|
|
75
|
+
if (percentage >= 85) {
|
|
76
|
+
color = chalk.red;
|
|
77
|
+
} else if (percentage >= 60) {
|
|
78
|
+
color = chalk.yellow;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const status = percentage >= 85 ? '⚠' : percentage >= 60 ? '⚡' : '✓';
|
|
82
|
+
const remainingText = remaining.hours > 0
|
|
83
|
+
? `${remaining.hours}h${remaining.minutes}m`
|
|
84
|
+
: `${remaining.minutes}m`;
|
|
85
|
+
|
|
86
|
+
return `${color('●')} ${modelName} ${color(percentage + '%')} ${remainingText} ${status}`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// CLI usage
|
|
91
|
+
async function main() {
|
|
92
|
+
const args = process.argv.slice(2);
|
|
93
|
+
const mode = args.includes('--minimal') ? 'minimal' : 'compact';
|
|
94
|
+
|
|
95
|
+
const prompt = new PromptStatus();
|
|
96
|
+
const output = await prompt.getPromptStatus(mode);
|
|
97
|
+
|
|
98
|
+
if (output) {
|
|
99
|
+
console.log(output);
|
|
100
|
+
} else {
|
|
101
|
+
// Silent mode - no output if not configured
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (require.main === module) {
|
|
106
|
+
main().catch(error => {
|
|
107
|
+
// Silent fail for prompt integration
|
|
108
|
+
process.exit(0);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = PromptStatus;
|
package/cli/status.js
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const chalk = require('chalk').default;
|
|
2
|
+
const dayjs = require('dayjs');
|
|
3
|
+
|
|
4
|
+
class StatusBar {
|
|
5
|
+
constructor(data) {
|
|
6
|
+
this.data = data;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
render() {
|
|
10
|
+
const { modelName, timeWindow, remaining, usage } = this.data;
|
|
11
|
+
|
|
12
|
+
// Calculate progress bar width
|
|
13
|
+
const width = 30;
|
|
14
|
+
const filled = Math.floor((usage.percentage / 100) * width);
|
|
15
|
+
const empty = width - filled;
|
|
16
|
+
|
|
17
|
+
// Create progress bar with colors based on usage percentage
|
|
18
|
+
const progressBar = this.createProgressBar(filled, empty, usage.percentage);
|
|
19
|
+
|
|
20
|
+
// Format output
|
|
21
|
+
const lines = [
|
|
22
|
+
chalk.bold.blue('┌─────────────────────────────────────────────────────────────┐'),
|
|
23
|
+
`│ ${chalk.bold('MiniMax Claude Code 使用状态')} ${chalk.dim('│')}`,
|
|
24
|
+
`│ ${chalk.dim('│')}`,
|
|
25
|
+
`│ ${chalk.cyan('当前模型:')} ${modelName.padEnd(35)} ${chalk.dim('│')}`,
|
|
26
|
+
`│ ${chalk.cyan('时间窗口:')} ${timeWindow.start}-${timeWindow.end}(${timeWindow.timezone})${' '.repeat(25)} ${chalk.dim('│')}`,
|
|
27
|
+
`│ ${chalk.cyan('剩余时间:')} ${remaining.text}${' '.repeat(30 - remaining.text.length)} ${chalk.dim('│')}`,
|
|
28
|
+
`│ ${chalk.dim('│')}`,
|
|
29
|
+
`│ ${chalk.cyan('已用额度:')} ${progressBar} ${usage.percentage}% ${chalk.dim('│')}`,
|
|
30
|
+
`│ ${chalk.dim(' 剩余:')} ${usage.used}/${usage.total} 次调用`.padEnd(43) + chalk.dim('│'),
|
|
31
|
+
`│ ${chalk.dim('│')}`,
|
|
32
|
+
this.getStatusLine(usage.percentage),
|
|
33
|
+
chalk.bold.blue('└─────────────────────────────────────────────────────────────┘')
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
return lines.join('\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
createProgressBar(filled, empty, percentage) {
|
|
40
|
+
// filled 是已使用部分,empty 是剩余部分
|
|
41
|
+
const usedBar = '█'.repeat(filled);
|
|
42
|
+
const remainingBar = '░'.repeat(empty);
|
|
43
|
+
const bar = `${usedBar}${remainingBar}`;
|
|
44
|
+
|
|
45
|
+
// 进度条颜色基于已使用百分比:使用越多越危险(红色)
|
|
46
|
+
if (percentage >= 85) {
|
|
47
|
+
return chalk.red(bar);
|
|
48
|
+
} else if (percentage >= 60) {
|
|
49
|
+
return chalk.yellow(bar);
|
|
50
|
+
} else {
|
|
51
|
+
return chalk.green(bar);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getStatusLine(percentage) {
|
|
56
|
+
const status = this.getStatus(percentage);
|
|
57
|
+
const leftPadding = '│ ';
|
|
58
|
+
const rightPadding = ' '.repeat(41 - status.length) + '│';
|
|
59
|
+
|
|
60
|
+
let statusColor;
|
|
61
|
+
switch (status) {
|
|
62
|
+
case '✓ 正常':
|
|
63
|
+
statusColor = chalk.green(status);
|
|
64
|
+
break;
|
|
65
|
+
case '⚠ 接近限制':
|
|
66
|
+
statusColor = chalk.yellow(status);
|
|
67
|
+
break;
|
|
68
|
+
case '⚠ 即将到期':
|
|
69
|
+
statusColor = chalk.red(status);
|
|
70
|
+
break;
|
|
71
|
+
default:
|
|
72
|
+
statusColor = chalk.gray(status);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return `${leftPadding}${chalk.cyan('状态:')} ${statusColor}${rightPadding}`;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getStatus(percentage) {
|
|
79
|
+
// 基于已使用百分比
|
|
80
|
+
if (percentage >= 85) {
|
|
81
|
+
return '⚠ 即将用完';
|
|
82
|
+
} else if (percentage >= 60) {
|
|
83
|
+
return '⚡ 注意使用';
|
|
84
|
+
} else {
|
|
85
|
+
return '✓ 正常使用';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
renderCompact() {
|
|
90
|
+
const { usage, remaining, modelName } = this.data;
|
|
91
|
+
const status = this.getStatus(usage.percentage);
|
|
92
|
+
|
|
93
|
+
// 颜色基于已使用百分比:使用越多越危险
|
|
94
|
+
let color;
|
|
95
|
+
if (usage.percentage >= 85) {
|
|
96
|
+
color = chalk.red;
|
|
97
|
+
} else if (usage.percentage >= 60) {
|
|
98
|
+
color = chalk.yellow;
|
|
99
|
+
} else {
|
|
100
|
+
color = chalk.green;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return `${color('●')} ${modelName} ${usage.percentage}% ${chalk.dim(`(${usage.used}/${usage.total})`)} ${chalk.gray('•')} ${remaining.text} ${chalk.gray('•')} ${status}`;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
module.exports = StatusBar;
|
package/package.json
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
|
|
3
|
+
class MinimaxAPI {
|
|
4
|
+
constructor(context) {
|
|
5
|
+
this.context = context;
|
|
6
|
+
this.token = null;
|
|
7
|
+
this.groupId = null;
|
|
8
|
+
this.loadConfig();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
loadConfig() {
|
|
12
|
+
const config = vscode.workspace.getConfiguration('minimaxStatus');
|
|
13
|
+
this.token = config.get('token');
|
|
14
|
+
this.groupId = config.get('groupId');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async getUsageStatus() {
|
|
18
|
+
if (!this.token || !this.groupId) {
|
|
19
|
+
throw new Error('请在设置中配置 MiniMax 访问令牌和组 ID');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const response = await axios.get(
|
|
24
|
+
`https://www.minimaxi.com/v1/api/openplatform/coding_plan/remains`,
|
|
25
|
+
{
|
|
26
|
+
params: { GroupId: this.groupId },
|
|
27
|
+
headers: {
|
|
28
|
+
'Authorization': `Bearer ${this.token}`,
|
|
29
|
+
'Accept': 'application/json'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return response.data;
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error.response?.status === 401) {
|
|
37
|
+
throw new Error('无效的令牌或未授权。请检查您的凭据。');
|
|
38
|
+
}
|
|
39
|
+
throw new Error(`API 请求失败: ${error.message}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
parseUsageData(apiData) {
|
|
44
|
+
if (!apiData.model_remains || apiData.model_remains.length === 0) {
|
|
45
|
+
throw new Error('没有可用的使用数据');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const modelData = apiData.model_remains[0];
|
|
49
|
+
const startTime = new Date(modelData.start_time);
|
|
50
|
+
const endTime = new Date(modelData.end_time);
|
|
51
|
+
|
|
52
|
+
// Calculate used percentage
|
|
53
|
+
const totalTime = modelData.end_time - modelData.start_time;
|
|
54
|
+
const usedTime = totalTime - modelData.remains_time;
|
|
55
|
+
const usedPercentage = Math.round((usedTime / totalTime) * 100);
|
|
56
|
+
|
|
57
|
+
// Calculate remaining time
|
|
58
|
+
const remainingMs = modelData.remains_time;
|
|
59
|
+
const hours = Math.floor(remainingMs / (1000 * 60 * 60));
|
|
60
|
+
const minutes = Math.floor((remainingMs % (1000 * 60 * 60)) / (1000 * 60));
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
modelName: modelData.model_name,
|
|
64
|
+
timeWindow: {
|
|
65
|
+
start: startTime.toLocaleTimeString('zh-CN', {
|
|
66
|
+
hour: '2-digit',
|
|
67
|
+
minute: '2-digit',
|
|
68
|
+
timeZone: 'Asia/Shanghai',
|
|
69
|
+
hour12: false
|
|
70
|
+
}),
|
|
71
|
+
end: endTime.toLocaleTimeString('zh-CN', {
|
|
72
|
+
hour: '2-digit',
|
|
73
|
+
minute: '2-digit',
|
|
74
|
+
timeZone: 'Asia/Shanghai',
|
|
75
|
+
hour12: false
|
|
76
|
+
}),
|
|
77
|
+
timezone: 'UTC+8'
|
|
78
|
+
},
|
|
79
|
+
remaining: {
|
|
80
|
+
hours,
|
|
81
|
+
minutes,
|
|
82
|
+
text: hours > 0 ? `${hours} 小时 ${minutes} 分钟后重置` : `${minutes} 分钟后重置`
|
|
83
|
+
},
|
|
84
|
+
usage: {
|
|
85
|
+
used: modelData.current_interval_usage_count,
|
|
86
|
+
total: modelData.current_interval_total_count,
|
|
87
|
+
percentage: usedPercentage
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
refreshConfig() {
|
|
93
|
+
this.loadConfig();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = MinimaxAPI;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
const vscode = require('vscode');
|
|
2
|
+
const MinimaxAPI = require('./api');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @param {vscode.ExtensionContext} context
|
|
6
|
+
*/
|
|
7
|
+
function activate(context) {
|
|
8
|
+
console.log('MiniMax Status 扩展已激活');
|
|
9
|
+
|
|
10
|
+
const api = new MinimaxAPI(context);
|
|
11
|
+
const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
|
|
12
|
+
statusBarItem.command = 'minimaxStatus.refresh';
|
|
13
|
+
statusBarItem.show();
|
|
14
|
+
|
|
15
|
+
let intervalId;
|
|
16
|
+
|
|
17
|
+
const updateStatus = async () => {
|
|
18
|
+
try {
|
|
19
|
+
const apiData = await api.getUsageStatus();
|
|
20
|
+
const usageData = api.parseUsageData(apiData);
|
|
21
|
+
updateStatusBar(statusBarItem, usageData);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
console.error('获取状态失败:', error.message);
|
|
24
|
+
statusBarItem.text = '$(warning) MiniMax';
|
|
25
|
+
statusBarItem.tooltip = `错误: ${error.message}\n点击配置`;
|
|
26
|
+
statusBarItem.color = new vscode.ThemeColor('errorForeground');
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const config = vscode.workspace.getConfiguration('minimaxStatus');
|
|
31
|
+
const interval = config.get('refreshInterval', 30) * 1000;
|
|
32
|
+
|
|
33
|
+
// Initial update
|
|
34
|
+
updateStatus();
|
|
35
|
+
|
|
36
|
+
// Set up interval
|
|
37
|
+
intervalId = setInterval(updateStatus, interval);
|
|
38
|
+
|
|
39
|
+
// Subscribe to configuration changes
|
|
40
|
+
const configChangeDisposable = vscode.workspace.onDidChangeConfiguration((e) => {
|
|
41
|
+
if (e.affectsConfiguration('minimaxStatus')) {
|
|
42
|
+
api.refreshConfig();
|
|
43
|
+
const newInterval = config.get('refreshInterval', 30) * 1000;
|
|
44
|
+
clearInterval(intervalId);
|
|
45
|
+
intervalId = setInterval(updateStatus, newInterval);
|
|
46
|
+
updateStatus();
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Subscribe to refresh command
|
|
51
|
+
const refreshDisposable = vscode.commands.registerCommand('minimaxStatus.refresh', updateStatus);
|
|
52
|
+
|
|
53
|
+
// Subscribe to setup command
|
|
54
|
+
const setupDisposable = vscode.commands.registerCommand('minimaxStatus.setup', async () => {
|
|
55
|
+
const token = await vscode.window.showInputBox({
|
|
56
|
+
prompt: '请输入您的 MiniMax 访问令牌',
|
|
57
|
+
password: true,
|
|
58
|
+
ignoreFocusOut: true
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!token) return;
|
|
62
|
+
|
|
63
|
+
const groupId = await vscode.window.showInputBox({
|
|
64
|
+
prompt: '请输入您的 MiniMax 组 ID',
|
|
65
|
+
ignoreFocusOut: true
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (!groupId) return;
|
|
69
|
+
|
|
70
|
+
await config.update('token', token, vscode.ConfigurationTarget.Global);
|
|
71
|
+
await config.update('groupId', groupId, vscode.ConfigurationTarget.Global);
|
|
72
|
+
|
|
73
|
+
vscode.window.showInformationMessage('MiniMax 凭据已保存');
|
|
74
|
+
api.refreshConfig();
|
|
75
|
+
updateStatus();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Add to subscriptions
|
|
79
|
+
context.subscriptions.push(
|
|
80
|
+
statusBarItem,
|
|
81
|
+
configChangeDisposable,
|
|
82
|
+
refreshDisposable,
|
|
83
|
+
setupDisposable
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
// Show setup message if credentials are missing
|
|
87
|
+
if (!api.token || !api.groupId) {
|
|
88
|
+
setTimeout(() => {
|
|
89
|
+
vscode.window.showInformationMessage(
|
|
90
|
+
'MiniMax Status 扩展需要配置令牌和组 ID',
|
|
91
|
+
'立即配置'
|
|
92
|
+
).then((selection) => {
|
|
93
|
+
if (selection === '立即配置') {
|
|
94
|
+
vscode.commands.executeCommand('minimaxStatus.setup');
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}, 2000);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function updateStatusBar(statusBarItem, data) {
|
|
102
|
+
const { usage, modelName, remaining } = data;
|
|
103
|
+
|
|
104
|
+
// Set status bar text with color
|
|
105
|
+
const percentage = usage.percentage;
|
|
106
|
+
if (percentage < 60) {
|
|
107
|
+
statusBarItem.color = new vscode.ThemeColor('statusBar.foreground');
|
|
108
|
+
} else if (percentage < 85) {
|
|
109
|
+
statusBarItem.color = new vscode.ThemeColor('problemsWarningIcon.foreground');
|
|
110
|
+
} else {
|
|
111
|
+
statusBarItem.color = new vscode.ThemeColor('errorForeground');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
statusBarItem.text = `$(clock) ${modelName} ${percentage}%`;
|
|
115
|
+
|
|
116
|
+
// Build tooltip
|
|
117
|
+
const tooltip = [
|
|
118
|
+
`模型: ${modelName}`,
|
|
119
|
+
`使用进度: ${usage.percentage}% (${usage.used}/${usage.total})`,
|
|
120
|
+
`剩余时间: ${remaining.text}`,
|
|
121
|
+
`时间窗口: ${data.timeWindow.start}-${data.timeWindow.end}(${data.timeWindow.timezone})`,
|
|
122
|
+
'',
|
|
123
|
+
'点击刷新状态'
|
|
124
|
+
].join('\n');
|
|
125
|
+
|
|
126
|
+
statusBarItem.tooltip = tooltip;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function deactivate() {
|
|
130
|
+
console.log('MiniMax Status 扩展已停用');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
activate,
|
|
135
|
+
deactivate
|
|
136
|
+
};
|