minimax-status 1.1.4 → 1.1.5
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 +79 -24
- package/cli/index.js +300 -15
- package/cli/renderer.js +20 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -126,10 +126,10 @@ npm run package
|
|
|
126
126
|
集成成功后,底部状态栏将显示:
|
|
127
127
|
|
|
128
128
|
```
|
|
129
|
-
|
|
129
|
+
my-app │ main * │ MiniMax-M2 │ 205K │ Usage ██████░░░░ 60% (2700/4500) │ ⏱ 1h20m │ 到期 5天
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
显示格式:`目录 │ 分支 │ 模型 │ 上下文 │ Usage 进度条 百分比(剩余/总数) │ ⏱ 倒计时 │ 到期 天数`
|
|
133
133
|
|
|
134
134
|
**颜色说明**:
|
|
135
135
|
|
|
@@ -141,17 +141,14 @@ npm run package
|
|
|
141
141
|
状态栏会显示当前 Git 分支信息:
|
|
142
142
|
|
|
143
143
|
```
|
|
144
|
-
|
|
144
|
+
my-app │ main * │ ...
|
|
145
145
|
```
|
|
146
146
|
|
|
147
147
|
**符号说明**:
|
|
148
148
|
|
|
149
149
|
| 符号 | 含义 |
|
|
150
150
|
|------|------|
|
|
151
|
-
|
|
|
152
|
-
| ⬆n | 有 n 个 commit 未推送到远程 |
|
|
153
|
-
| ⬇n | 有 n 个 commit 未从远程拉取(优先显示) |
|
|
154
|
-
| • | 有未提交的更改 |
|
|
151
|
+
| * | 有未提交的更改 |
|
|
155
152
|
|
|
156
153
|
**颜色规则**:
|
|
157
154
|
|
|
@@ -183,6 +180,55 @@ npm run package
|
|
|
183
180
|
|
|
184
181
|
**注意**: MiniMax 的配置独立存储在 `~/.minimax-config.json`,与 Claude Code 的配置分离。
|
|
185
182
|
|
|
183
|
+
## Droid 集成
|
|
184
|
+
|
|
185
|
+
将 MiniMax 使用状态显示在 Droid 底部状态栏。
|
|
186
|
+
|
|
187
|
+
### 配置步骤
|
|
188
|
+
|
|
189
|
+
1. **安装和配置工具**:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm install -g minimax-status
|
|
193
|
+
minimax auth <token> <groupId>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
2. **配置 Droid**:
|
|
197
|
+
|
|
198
|
+
编辑 `~/.factory/settings.json`:
|
|
199
|
+
|
|
200
|
+
```json
|
|
201
|
+
{
|
|
202
|
+
"statusLine": {
|
|
203
|
+
"type": "command",
|
|
204
|
+
"command": "minimax droid-statusline"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
3. **重启 Droid**
|
|
210
|
+
|
|
211
|
+
集成成功后,底部状态栏将显示:
|
|
212
|
+
|
|
213
|
+
```
|
|
214
|
+
minimax-status │ main * │ Usage █░░░░░░░░ 10% (4047/4500) │ ⏱ 12m │ 到期 21天
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
显示格式:`目录 │ 分支 │ Usage 进度条 百分比(剩余/总数) │ ⏱ 倒计时 │ 到期 天数`
|
|
218
|
+
|
|
219
|
+
### 进度条风格
|
|
220
|
+
|
|
221
|
+
使用 `█` 和 `░` 字符显示进度条:
|
|
222
|
+
|
|
223
|
+
- `█░░░░░░░░` - 10% 使用量
|
|
224
|
+
- `█████░░░░` - 50% 使用量
|
|
225
|
+
- `██████████` - 100% 使用量
|
|
226
|
+
|
|
227
|
+
**颜色说明**:
|
|
228
|
+
|
|
229
|
+
- **使用量**: ≥85%红色 | 60-85%黄色 | <60%绿色
|
|
230
|
+
- **到期时间**: ≤3天红色 | ≤7天黄色 | >7天绿色
|
|
231
|
+
|
|
186
232
|
## 显示示例
|
|
187
233
|
|
|
188
234
|
### 详细模式
|
|
@@ -225,26 +271,35 @@ npm run package
|
|
|
225
271
|
|
|
226
272
|
## 命令说明
|
|
227
273
|
|
|
228
|
-
| 命令
|
|
229
|
-
|
|
|
230
|
-
| `minimax auth`
|
|
231
|
-
| `minimax status`
|
|
232
|
-
| `minimax bar`
|
|
233
|
-
| `minimax statusline`
|
|
274
|
+
| 命令 | 描述 | 示例 |
|
|
275
|
+
| --------------------- | ------------------------------------------- | -------------------------------- |
|
|
276
|
+
| `minimax auth` | 设置认证凭据 | `minimax auth <token> <groupId>` |
|
|
277
|
+
| `minimax status` | 显示当前使用状态(支持 --compact、--watch) | `minimax status` |
|
|
278
|
+
| `minimax bar` | 终端底部持续状态栏 | `minimax bar` |
|
|
279
|
+
| `minimax statusline` | Claude Code 状态栏集成 | 用于 Claude Code 配置 |
|
|
280
|
+
| `minimax droid-statusline` | Droid 状态栏集成 | 用于 Droid 配置 |
|
|
234
281
|
|
|
235
282
|
## 状态说明
|
|
236
283
|
|
|
237
|
-
###
|
|
238
|
-
|
|
239
|
-
| 元素 |
|
|
240
|
-
| ------ |
|
|
241
|
-
| 目录 |
|
|
242
|
-
|
|
|
243
|
-
|
|
|
244
|
-
|
|
|
245
|
-
|
|
|
246
|
-
|
|
|
247
|
-
| 到期 |
|
|
284
|
+
### 显示元素
|
|
285
|
+
|
|
286
|
+
| 元素 | 说明 |
|
|
287
|
+
| ------ | ---------------------------------- |
|
|
288
|
+
| 目录 | 当前工作目录 |
|
|
289
|
+
| 分支 | Git 分支名称 |
|
|
290
|
+
| 模型 | MiniMax 模型名称 |
|
|
291
|
+
| 上下文 | 上下文窗口使用率 |
|
|
292
|
+
| Usage | 使用量进度条和百分比(剩余/总数) |
|
|
293
|
+
| ⏱ | 额度重置倒计时 |
|
|
294
|
+
| 到期 | 订阅到期时间(颜色动态变化) |
|
|
295
|
+
|
|
296
|
+
### 进度条
|
|
297
|
+
|
|
298
|
+
使用 `█` 和 `░` 字符显示进度条:
|
|
299
|
+
|
|
300
|
+
- `█░░░░░░░░` - 10% 使用量
|
|
301
|
+
- `█████░░░░░` - 50% 使用量
|
|
302
|
+
- `██████████` - 100% 使用量
|
|
248
303
|
|
|
249
304
|
### 颜色规则
|
|
250
305
|
|
package/cli/index.js
CHANGED
|
@@ -246,7 +246,7 @@ program
|
|
|
246
246
|
let displayModel = modelName;
|
|
247
247
|
let currentDir = null;
|
|
248
248
|
let modelId = null;
|
|
249
|
-
let contextSize =
|
|
249
|
+
let contextSize = 204800;
|
|
250
250
|
|
|
251
251
|
if (stdinData) {
|
|
252
252
|
if (stdinData.model && stdinData.model.display_name) {
|
|
@@ -265,13 +265,8 @@ program
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
if (modelId) {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
if (modelKey.includes(key.toLowerCase())) {
|
|
271
|
-
contextSize = value;
|
|
272
|
-
break;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
268
|
+
// MiniMax 模型统一使用 208K context window
|
|
269
|
+
contextSize = 204800;
|
|
275
270
|
}
|
|
276
271
|
|
|
277
272
|
let contextUsageTokens = null;
|
|
@@ -401,13 +396,303 @@ program
|
|
|
401
396
|
}
|
|
402
397
|
});
|
|
403
398
|
|
|
404
|
-
//
|
|
405
|
-
|
|
406
|
-
"
|
|
407
|
-
"
|
|
408
|
-
"
|
|
409
|
-
|
|
410
|
-
|
|
399
|
+
// Droid-statusline command - Droid 状态栏集成(从 session 文件读取数据)
|
|
400
|
+
program
|
|
401
|
+
.command("droid-statusline")
|
|
402
|
+
.description("Droid状态栏集成(从 session 文件读取数据,单次输出)")
|
|
403
|
+
.argument("[sessionPath]", "Droid session 目录路径(可选,默认自动查找)")
|
|
404
|
+
.action(async (sessionPath) => {
|
|
405
|
+
const fs = require("fs");
|
|
406
|
+
const path = require("path");
|
|
407
|
+
|
|
408
|
+
// 查找 session 目录
|
|
409
|
+
let targetSessionPath = sessionPath;
|
|
410
|
+
const currentCwd = process.cwd().replace(/\\/g, "/");
|
|
411
|
+
|
|
412
|
+
if (!targetSessionPath) {
|
|
413
|
+
const sessionsDir = path.join(process.env.HOME || process.env.USERPROFILE, ".factory", "sessions");
|
|
414
|
+
|
|
415
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
416
|
+
console.log("❌ 未找到 Droid sessions 目录");
|
|
417
|
+
process.exit(1);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 优先查找与当前工作目录匹配的 session
|
|
421
|
+
const userDirs = fs.readdirSync(sessionsDir);
|
|
422
|
+
let matchedSession = null;
|
|
423
|
+
let latestSession = null;
|
|
424
|
+
let latestStartTime = 0;
|
|
425
|
+
|
|
426
|
+
for (const userDir of userDirs) {
|
|
427
|
+
const userPath = path.join(sessionsDir, userDir);
|
|
428
|
+
if (!fs.statSync(userPath).isDirectory()) continue;
|
|
429
|
+
|
|
430
|
+
const sessions = fs.readdirSync(userPath);
|
|
431
|
+
for (const session of sessions) {
|
|
432
|
+
if (!session.endsWith(".jsonl")) continue;
|
|
433
|
+
|
|
434
|
+
const jsonlPath = path.join(userPath, session);
|
|
435
|
+
try {
|
|
436
|
+
const content = fs.readFileSync(jsonlPath, "utf8");
|
|
437
|
+
const firstLine = content.split("\n")[0];
|
|
438
|
+
const entry = JSON.parse(firstLine);
|
|
439
|
+
|
|
440
|
+
if (entry.cwd) {
|
|
441
|
+
const sessionCwd = entry.cwd.replace(/\\/g, "/");
|
|
442
|
+
// 优先匹配当前工作目录
|
|
443
|
+
if (sessionCwd === currentCwd || currentCwd.includes(sessionCwd) || sessionCwd.includes(currentCwd)) {
|
|
444
|
+
if (!matchedSession) {
|
|
445
|
+
matchedSession = userPath;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// 记录最新 session
|
|
451
|
+
if (entry.timestamp) {
|
|
452
|
+
const startTime = new Date(entry.timestamp).getTime();
|
|
453
|
+
if (startTime > latestStartTime) {
|
|
454
|
+
latestStartTime = startTime;
|
|
455
|
+
latestSession = userPath;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
} catch (e) {
|
|
459
|
+
// continue
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// 优先使用匹配的 session,否则用最新的
|
|
465
|
+
targetSessionPath = matchedSession || latestSession;
|
|
466
|
+
|
|
467
|
+
if (!targetSessionPath) {
|
|
468
|
+
console.log("❌ 未找到 Droid session");
|
|
469
|
+
process.exit(1);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// 读取 settings.json
|
|
474
|
+
const settingsFiles = fs.readdirSync(targetSessionPath).filter(f => f.endsWith(".settings.json"));
|
|
475
|
+
let settings = {};
|
|
476
|
+
|
|
477
|
+
for (const sf of settingsFiles) {
|
|
478
|
+
try {
|
|
479
|
+
const content = fs.readFileSync(path.join(targetSessionPath, sf), "utf8");
|
|
480
|
+
const parsed = JSON.parse(content);
|
|
481
|
+
if (parsed.tokenUsage) {
|
|
482
|
+
settings = parsed;
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
485
|
+
} catch (e) {
|
|
486
|
+
// continue
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// 读取 jsonl 获取 cwd 和模型信息,以及实时 token 使用量
|
|
491
|
+
let cwd = process.cwd();
|
|
492
|
+
let jsonlTokens = null;
|
|
493
|
+
const jsonlFiles = fs.readdirSync(targetSessionPath).filter(f => f.endsWith(".jsonl"));
|
|
494
|
+
|
|
495
|
+
for (const jf of jsonlFiles) {
|
|
496
|
+
try {
|
|
497
|
+
const content = fs.readFileSync(path.join(targetSessionPath, jf), "utf8");
|
|
498
|
+
const lines = content.split('\n').filter(l => l.trim());
|
|
499
|
+
|
|
500
|
+
// 获取第一行获取 cwd
|
|
501
|
+
if (lines.length > 0) {
|
|
502
|
+
try {
|
|
503
|
+
const firstEntry = JSON.parse(lines[0]);
|
|
504
|
+
if (firstEntry.cwd) {
|
|
505
|
+
cwd = firstEntry.cwd;
|
|
506
|
+
}
|
|
507
|
+
} catch (e) {}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// 从最后的消息中解析实时 token 使用量
|
|
511
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
512
|
+
try {
|
|
513
|
+
const entry = JSON.parse(lines[i]);
|
|
514
|
+
// 查找 assistant 消息中的 usage
|
|
515
|
+
if (entry.type === 'message' && entry.message?.role === 'assistant' && entry.message?.usage) {
|
|
516
|
+
const u = entry.message.usage;
|
|
517
|
+
jsonlTokens = {
|
|
518
|
+
inputTokens: u.input_tokens || u.prompt_tokens || 0,
|
|
519
|
+
outputTokens: u.output_tokens || u.completion_tokens || 0,
|
|
520
|
+
cacheCreationTokens: u.cache_creation_input_tokens || u.cache_creation_prompt_tokens || 0,
|
|
521
|
+
cacheReadTokens: u.cache_read_input_tokens || u.cache_read_prompt_tokens || 0,
|
|
522
|
+
thinkingTokens: u.thinking_tokens || 0
|
|
523
|
+
};
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
} catch (e) {
|
|
527
|
+
continue;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
} catch (e) {
|
|
531
|
+
// continue
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const currentDir = cwd.split(/[/\\]/).pop();
|
|
536
|
+
|
|
537
|
+
// 优先使用 jsonl 中的实时 token 使用量,否则用 settings 中的累计值
|
|
538
|
+
const tokenUsage = (jsonlTokens && (jsonlTokens.inputTokens > 0 || jsonlTokens.outputTokens > 0))
|
|
539
|
+
? jsonlTokens
|
|
540
|
+
: (settings.tokenUsage || {});
|
|
541
|
+
|
|
542
|
+
const inputTokens = tokenUsage.inputTokens || 0;
|
|
543
|
+
const outputTokens = tokenUsage.outputTokens || 0;
|
|
544
|
+
const cacheCreationTokens = tokenUsage.cacheCreationTokens || 0;
|
|
545
|
+
const cacheReadTokens = tokenUsage.cacheReadTokens || 0;
|
|
546
|
+
const thinkingTokens = tokenUsage.thinkingTokens || 0;
|
|
547
|
+
|
|
548
|
+
// 实时上下文使用量(不包括累计的 cacheReadTokens)
|
|
549
|
+
const contextTokens = inputTokens + outputTokens + cacheCreationTokens + thinkingTokens;
|
|
550
|
+
// 累计 token(用于显示)
|
|
551
|
+
const totalTokens = inputTokens + outputTokens + cacheCreationTokens + cacheReadTokens + thinkingTokens;
|
|
552
|
+
|
|
553
|
+
// 获取模型信息
|
|
554
|
+
const modelName = settings.model || "MiniMax-M2.5-highspeed";
|
|
555
|
+
const modelDisplayName = modelName.replace(/^custom:/, "").replace(/-[0-9]+$/, "");
|
|
556
|
+
|
|
557
|
+
// 获取 API 使用量
|
|
558
|
+
let usageData = null;
|
|
559
|
+
try {
|
|
560
|
+
const [apiData, subscriptionData] = await Promise.all([
|
|
561
|
+
api.getUsageStatus(),
|
|
562
|
+
api.getSubscriptionDetails(),
|
|
563
|
+
]);
|
|
564
|
+
usageData = api.parseUsageData(apiData, subscriptionData);
|
|
565
|
+
} catch (e) {
|
|
566
|
+
usageData = {
|
|
567
|
+
usage: { percentage: 0, input: 0, output: 0, cached: 0, total: 0 },
|
|
568
|
+
remaining: "未知",
|
|
569
|
+
expiry: "未知",
|
|
570
|
+
modelName: modelDisplayName
|
|
571
|
+
};
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const { usage, remaining, expiry } = usageData;
|
|
575
|
+
|
|
576
|
+
// 获取 git 分支
|
|
577
|
+
let gitBranch = null;
|
|
578
|
+
try {
|
|
579
|
+
const branch = require('child_process').execSync(
|
|
580
|
+
'git symbolic-ref --short HEAD',
|
|
581
|
+
{ cwd: cwd, encoding: 'utf8', timeout: 3000 }
|
|
582
|
+
).trim();
|
|
583
|
+
if (branch) {
|
|
584
|
+
gitBranch = { name: branch };
|
|
585
|
+
|
|
586
|
+
// 检查未提交的更改
|
|
587
|
+
try {
|
|
588
|
+
const status = require('child_process').execSync(
|
|
589
|
+
'git status --porcelain',
|
|
590
|
+
{ cwd: cwd, encoding: 'utf8', timeout: 3000 }
|
|
591
|
+
).trim();
|
|
592
|
+
if (status) {
|
|
593
|
+
gitBranch.hasChanges = true;
|
|
594
|
+
}
|
|
595
|
+
} catch (e) {
|
|
596
|
+
// ignore
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
} catch (e) {
|
|
600
|
+
// 非 git 目录
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// 计算上下文使用量(从 session 实时 token)
|
|
604
|
+
// 使用实时 contextTokens 计算百分比
|
|
605
|
+
const contextUsageValue = contextTokens;
|
|
606
|
+
const contextSizeValue = 204800; // MiniMax M2 context window
|
|
607
|
+
|
|
608
|
+
// 获取 Droid 全局配置统计(不是当前工作目录)
|
|
609
|
+
const droidConfigDir = path.join(process.env.HOME || process.env.USERPROFILE, ".factory");
|
|
610
|
+
let configCounts = { claudeMdCount: 0, rulesCount: 0, mcpCount: 0, hooksCount: 0, skillsCount: 0 };
|
|
611
|
+
|
|
612
|
+
try {
|
|
613
|
+
const agentsPath = path.join(droidConfigDir, "agents");
|
|
614
|
+
const rulesPath = path.join(droidConfigDir, "rules");
|
|
615
|
+
const skillsPath = path.join(droidConfigDir, "skills");
|
|
616
|
+
const hooksPath = path.join(droidConfigDir, "hooks");
|
|
617
|
+
const mcpPath = path.join(droidConfigDir, "mcp.json");
|
|
618
|
+
|
|
619
|
+
if (fs.existsSync(agentsPath)) {
|
|
620
|
+
configCounts.claudeMdCount = fs.readdirSync(agentsPath).filter(f => f.endsWith(".md")).length;
|
|
621
|
+
}
|
|
622
|
+
if (fs.existsSync(rulesPath)) {
|
|
623
|
+
configCounts.rulesCount = fs.readdirSync(rulesPath).filter(f => f.endsWith(".md")).length;
|
|
624
|
+
}
|
|
625
|
+
if (fs.existsSync(skillsPath)) {
|
|
626
|
+
configCounts.skillsCount = fs.readdirSync(skillsPath).filter(f => f.endsWith(".md")).length;
|
|
627
|
+
}
|
|
628
|
+
if (fs.existsSync(hooksPath)) {
|
|
629
|
+
configCounts.hooksCount = fs.readdirSync(hooksPath).filter(f => f.endsWith(".ps1") || f.endsWith(".sh")).length;
|
|
630
|
+
}
|
|
631
|
+
if (fs.existsSync(mcpPath)) {
|
|
632
|
+
try {
|
|
633
|
+
const mcpData = JSON.parse(fs.readFileSync(mcpPath, "utf8"));
|
|
634
|
+
if (mcpData.mcpServers) {
|
|
635
|
+
configCounts.mcpCount = Object.keys(mcpData.mcpServers).length;
|
|
636
|
+
}
|
|
637
|
+
} catch (e) {}
|
|
638
|
+
}
|
|
639
|
+
} catch (e) {
|
|
640
|
+
// ignore errors
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// 进度条渲染函数
|
|
644
|
+
function getBarColor(p) {
|
|
645
|
+
if (p >= 85) return chalk.red;
|
|
646
|
+
if (p >= 60) return chalk.yellow;
|
|
647
|
+
return chalk.green;
|
|
648
|
+
}
|
|
649
|
+
const coloredBar = (percent, width = 10) => {
|
|
650
|
+
const filled = Math.round((percent / 100) * width);
|
|
651
|
+
const empty = width - filled;
|
|
652
|
+
const barColor = getBarColor(percent);
|
|
653
|
+
return barColor('█'.repeat(filled) + '\x1b[2m' + '░'.repeat(empty) + '\x1b[0m');
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
// 简化输出:目录 | git分支 | 使用量(进度条) | 倒计时
|
|
657
|
+
const parts = [];
|
|
658
|
+
|
|
659
|
+
// 目录
|
|
660
|
+
if (currentDir) {
|
|
661
|
+
parts.push(`${chalk.cyan(currentDir)}`);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// Git 分支
|
|
665
|
+
if (gitBranch && gitBranch.name) {
|
|
666
|
+
const isMainBranch = gitBranch.name === 'main' || gitBranch.name === 'master';
|
|
667
|
+
const branchColor = isMainBranch ? chalk.green : chalk.white;
|
|
668
|
+
let branchStr = branchColor(gitBranch.name);
|
|
669
|
+
if (gitBranch.hasChanges) {
|
|
670
|
+
branchStr += chalk.red(' *');
|
|
671
|
+
}
|
|
672
|
+
parts.push(branchStr);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// 使用量 - 进度条风格 (显示次数)
|
|
676
|
+
const usageBar = coloredBar(usage.percentage);
|
|
677
|
+
const usageColor = usage.percentage >= 85 ? chalk.red : usage.percentage >= 60 ? chalk.yellow : chalk.green;
|
|
678
|
+
parts.push(`${chalk.yellow('Usage')} ${usageBar} ${usageColor(usage.percentage + '%')} (${usage.remaining}/${usage.total})`);
|
|
679
|
+
|
|
680
|
+
// 倒计时
|
|
681
|
+
const remainingText = remaining.hours > 0
|
|
682
|
+
? `${remaining.hours}h${remaining.minutes}m`
|
|
683
|
+
: `${remaining.minutes}m`;
|
|
684
|
+
parts.push(`${chalk.yellow('⏱')} ${remainingText}`);
|
|
685
|
+
|
|
686
|
+
// 到期
|
|
687
|
+
if (expiry) {
|
|
688
|
+
const expiryColor = expiry.daysRemaining <= 3 ? chalk.red : expiry.daysRemaining <= 7 ? chalk.yellow : chalk.green;
|
|
689
|
+
parts.push(`${expiryColor('到期 ' + expiry.daysRemaining + '天')}`);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
console.log(parts.join(' │ '));
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// 模型上下文窗口大小(仅MiniMax模型)
|
|
411
696
|
|
|
412
697
|
function startWatching(api, statusBar) {
|
|
413
698
|
let intervalId;
|
package/cli/renderer.js
CHANGED
|
@@ -75,7 +75,7 @@ class Renderer {
|
|
|
75
75
|
const parts = [];
|
|
76
76
|
|
|
77
77
|
if (currentDir) {
|
|
78
|
-
parts.push(`${chalk.
|
|
78
|
+
parts.push(`${chalk.cyan(currentDir)}`);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// Git 分支显示
|
|
@@ -86,55 +86,49 @@ class Renderer {
|
|
|
86
86
|
const isMainBranch = name === 'main' || name === 'master';
|
|
87
87
|
const branchColor = isMainBranch ? chalk.green : chalk.white;
|
|
88
88
|
|
|
89
|
-
//
|
|
90
|
-
let branchStr = branchColor(
|
|
91
|
-
|
|
92
|
-
// 优先显示 behind(未拉取),不同时显示 ahead 和 behind
|
|
93
|
-
if (behind > 0) {
|
|
94
|
-
branchStr += chalk.cyan(' ⬇' + behind);
|
|
95
|
-
} else if (ahead > 0) {
|
|
96
|
-
branchStr += chalk.yellow(' ⬆' + ahead);
|
|
97
|
-
} else if (ahead === -1) {
|
|
98
|
-
// 没有 upstream 但有本地 commits
|
|
99
|
-
branchStr += chalk.yellow(' ⬆');
|
|
100
|
-
}
|
|
89
|
+
// 构建分支显示字符串
|
|
90
|
+
let branchStr = branchColor(name);
|
|
101
91
|
|
|
102
|
-
//
|
|
92
|
+
// 未提交更改用 * 标记
|
|
103
93
|
if (hasChanges) {
|
|
104
|
-
branchStr += chalk.red('
|
|
94
|
+
branchStr += chalk.red(' *');
|
|
105
95
|
}
|
|
106
96
|
|
|
107
97
|
parts.push(branchStr);
|
|
108
98
|
}
|
|
109
99
|
|
|
110
|
-
|
|
100
|
+
// 模型
|
|
101
|
+
parts.push(`${chalk.magenta(modelName)}`);
|
|
111
102
|
|
|
112
|
-
//
|
|
103
|
+
// 上下文窗口
|
|
113
104
|
if (contextUsage !== null && contextUsage !== undefined) {
|
|
114
105
|
const contextPercent = Math.round((contextUsage / contextSize) * 100);
|
|
115
106
|
const contextColor = this.getStatusColor(contextPercent);
|
|
116
|
-
|
|
117
|
-
const contextStr = `${contextColor('⚡' + contextPercent + '%')}${contextColor('·')}${contextColor(this.formatTokens(contextUsage) + ' tokens')}`;
|
|
118
|
-
parts.push(contextStr);
|
|
107
|
+
parts.push(`${contextColor(contextPercent + '%')} ${chalk.gray(this.formatTokens(contextUsage))}`);
|
|
119
108
|
} else {
|
|
120
|
-
parts.push(
|
|
109
|
+
parts.push(chalk.cyan(this.formatContextSize(contextSize)));
|
|
121
110
|
}
|
|
122
111
|
|
|
123
|
-
//
|
|
112
|
+
// 使用量 - 进度条风格
|
|
124
113
|
const usageColor = this.getStatusColor(usagePercentage);
|
|
125
|
-
|
|
114
|
+
const filled = Math.round((usagePercentage / 100) * 10);
|
|
115
|
+
const empty = 10 - filled;
|
|
116
|
+
const usageBar = usageColor('█'.repeat(filled) + '\x1b[2m' + '░'.repeat(empty) + '\x1b[0m');
|
|
117
|
+
parts.push(`${chalk.yellow('Usage')} ${usageBar} ${usageColor(usagePercentage + '%')} (${usage.remaining}/${usage.total})`);
|
|
126
118
|
|
|
119
|
+
// 倒计时 - 保留图标
|
|
127
120
|
const remainingText = remaining.hours > 0
|
|
128
121
|
? `${remaining.hours}h${remaining.minutes}m`
|
|
129
122
|
: `${remaining.minutes}m`;
|
|
130
|
-
parts.push(`${chalk.yellow('
|
|
123
|
+
parts.push(`${chalk.yellow('⏱')} ${remainingText}`);
|
|
131
124
|
|
|
125
|
+
// 到期 - 保留图标
|
|
132
126
|
if (expiry) {
|
|
133
127
|
const expiryColor = expiry.daysRemaining <= 3 ? chalk.red : expiry.daysRemaining <= 7 ? chalk.yellow : chalk.green;
|
|
134
|
-
parts.push(`${expiryColor('
|
|
128
|
+
parts.push(`${expiryColor('到期 ' + expiry.daysRemaining + '天')}`);
|
|
135
129
|
}
|
|
136
130
|
|
|
137
|
-
return parts.join('
|
|
131
|
+
return parts.join(' │ ');
|
|
138
132
|
}
|
|
139
133
|
|
|
140
134
|
renderToolsLine(tools) {
|