minimax-status 1.1.0 → 1.1.2
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 -20
- package/cli/index.js +12 -4
- package/cli/prompts.js +1 -1
- package/cli/renderer.js +239 -238
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ npm install -g minimax-status
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
### 2. 更新(如果已经安装)
|
|
32
|
+
|
|
32
33
|
```bash
|
|
33
34
|
npm update -g minimax-status
|
|
34
35
|
```
|
|
@@ -114,6 +115,7 @@ npm run package
|
|
|
114
115
|
```json
|
|
115
116
|
{
|
|
116
117
|
"statusLine": {
|
|
118
|
+
"type": "command",
|
|
117
119
|
"command": "minimax statusline"
|
|
118
120
|
}
|
|
119
121
|
}
|
|
@@ -130,6 +132,7 @@ npm run package
|
|
|
130
132
|
显示格式:`📁 目录 | 🤖 模型 | 上下文窗口 | ↻ 使用率·剩余次数/总数 | ⌛ 重置时间 | 到期时间`
|
|
131
133
|
|
|
132
134
|
**颜色说明**:
|
|
135
|
+
|
|
133
136
|
- **到期时间**: ≤3天红色 | ≤7天黄色 | >7天绿色
|
|
134
137
|
|
|
135
138
|
### 上下文窗口显示说明
|
|
@@ -143,6 +146,7 @@ npm run package
|
|
|
143
146
|
- 例如: `200K` 表示当前模型的上下文窗口大小
|
|
144
147
|
|
|
145
148
|
**智能特性**:
|
|
149
|
+
|
|
146
150
|
- ✅ 自动解析 Claude Code 转录文件(transcript)
|
|
147
151
|
- ✅ 支持 Anthropic 和 OpenAI 两种 token 格式
|
|
148
152
|
- ✅ 正确计算缓存 tokens(cache creation + cache read)
|
|
@@ -187,36 +191,36 @@ npm run package
|
|
|
187
191
|
|
|
188
192
|
## 命令说明
|
|
189
193
|
|
|
190
|
-
| 命令 | 描述
|
|
191
|
-
|
|
192
|
-
| `minimax auth` | 设置认证凭据
|
|
194
|
+
| 命令 | 描述 | 示例 |
|
|
195
|
+
| -------------------- | ------------------------------------------- | -------------------------------- |
|
|
196
|
+
| `minimax auth` | 设置认证凭据 | `minimax auth <token> <groupId>` |
|
|
193
197
|
| `minimax status` | 显示当前使用状态(支持 --compact、--watch) | `minimax status` |
|
|
194
|
-
| `minimax bar` | 终端底部持续状态栏
|
|
195
|
-
| `minimax statusline` | Claude Code 状态栏集成
|
|
198
|
+
| `minimax bar` | 终端底部持续状态栏 | `minimax bar` |
|
|
199
|
+
| `minimax statusline` | Claude Code 状态栏集成 | 用于 Claude Code 配置 |
|
|
196
200
|
|
|
197
201
|
## 状态说明
|
|
198
202
|
|
|
199
203
|
### 状态图标
|
|
200
204
|
|
|
201
|
-
| 元素
|
|
202
|
-
|
|
203
|
-
| 目录
|
|
204
|
-
| 模型
|
|
205
|
-
| 上下文 | ⚡
|
|
206
|
-
| 使用量 | ↻
|
|
207
|
-
| 重置
|
|
208
|
-
| 到期
|
|
205
|
+
| 元素 | 图标 | 说明 |
|
|
206
|
+
| ------ | ---- | ---------------------------- |
|
|
207
|
+
| 目录 | 📁 | 当前工作目录 |
|
|
208
|
+
| 模型 | 🤖 | MiniMax 模型名称 |
|
|
209
|
+
| 上下文 | ⚡ | 上下文窗口使用率 |
|
|
210
|
+
| 使用量 | ↻ | 使用率·剩余次数/总数 |
|
|
211
|
+
| 重置 | ⌛ | 额度重置倒计时 |
|
|
212
|
+
| 到期 | - | 订阅到期时间(颜色动态变化) |
|
|
209
213
|
|
|
210
214
|
### 颜色规则
|
|
211
215
|
|
|
212
|
-
| 场景
|
|
213
|
-
|
|
214
|
-
| 使用率 < 60%
|
|
216
|
+
| 场景 | 颜色 | 说明 |
|
|
217
|
+
| ------------- | ---- | -------- |
|
|
218
|
+
| 使用率 < 60% | 绿色 | 正常使用 |
|
|
215
219
|
| 使用率 60-85% | 黄色 | 注意使用 |
|
|
216
|
-
| 使用率 ≥ 85%
|
|
217
|
-
| 到期 ≤ 3天
|
|
218
|
-
| 到期 ≤ 7天
|
|
219
|
-
| 到期 > 7天
|
|
220
|
+
| 使用率 ≥ 85% | 红色 | 危险状态 |
|
|
221
|
+
| 到期 ≤ 3天 | 红色 | 即将到期 |
|
|
222
|
+
| 到期 ≤ 7天 | 黄色 | 即将到期 |
|
|
223
|
+
| 到期 > 7天 | 绿色 | 订阅正常 |
|
|
220
224
|
|
|
221
225
|
## 配置文件
|
|
222
226
|
|
|
@@ -241,6 +245,7 @@ Claude Code 只需要配置状态栏命令:
|
|
|
241
245
|
// ~/.claude/settings.json
|
|
242
246
|
{
|
|
243
247
|
"statusLine": {
|
|
248
|
+
"type": "command",
|
|
244
249
|
"command": "minimax statusline"
|
|
245
250
|
}
|
|
246
251
|
}
|
package/cli/index.js
CHANGED
|
@@ -273,6 +273,15 @@ program
|
|
|
273
273
|
configCounts = await configCounter.count(workspacePath);
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
// 使用 Claude Code 提供的 context_window(最准确)
|
|
277
|
+
let contextUsageValue = contextUsageTokens;
|
|
278
|
+
let contextSizeValue = contextSize;
|
|
279
|
+
|
|
280
|
+
if (stdinData?.context_window) {
|
|
281
|
+
const cw = stdinData.context_window;
|
|
282
|
+
contextSizeValue = cw.context_window_size || contextSize;
|
|
283
|
+
}
|
|
284
|
+
|
|
276
285
|
const context = {
|
|
277
286
|
modelName: displayModel,
|
|
278
287
|
currentDir: displayDir,
|
|
@@ -280,8 +289,8 @@ program
|
|
|
280
289
|
usage,
|
|
281
290
|
remaining,
|
|
282
291
|
expiry,
|
|
283
|
-
contextUsage:
|
|
284
|
-
contextSize,
|
|
292
|
+
contextUsage: contextUsageValue,
|
|
293
|
+
contextSize: contextSizeValue,
|
|
285
294
|
configCounts,
|
|
286
295
|
tools: [],
|
|
287
296
|
agents: [],
|
|
@@ -295,8 +304,7 @@ program
|
|
|
295
304
|
context.todos = transcript.todos;
|
|
296
305
|
}
|
|
297
306
|
|
|
298
|
-
|
|
299
|
-
console.log(output);
|
|
307
|
+
console.log(renderer.render(context));
|
|
300
308
|
} catch (error) {
|
|
301
309
|
console.log(`❌ MiniMax 错误: ${error.message}`);
|
|
302
310
|
}
|
package/cli/prompts.js
CHANGED
|
@@ -101,7 +101,7 @@ class PromptStatus {
|
|
|
101
101
|
: `${remaining.minutes}m`;
|
|
102
102
|
|
|
103
103
|
// 添加到期信息(如果可用)
|
|
104
|
-
const expiryInfo = expiry ? ` ${chalk.
|
|
104
|
+
const expiryInfo = expiry ? ` ${chalk.cyan('•')} 剩余: ${expiry.daysRemaining}天` : '';
|
|
105
105
|
|
|
106
106
|
return `${color("●")} ${modelName} ${color(
|
|
107
107
|
percentage + "%"
|
package/cli/renderer.js
CHANGED
|
@@ -1,238 +1,239 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const chalk = require('chalk').default;
|
|
4
|
-
|
|
5
|
-
class Renderer {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.RESET = '\x1b[0m';
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
formatTokens(tokens) {
|
|
11
|
-
if (tokens >= 1000000) {
|
|
12
|
-
return `${(tokens / 1000000).toFixed(1)}M`;
|
|
13
|
-
}
|
|
14
|
-
if (tokens >= 1000) {
|
|
15
|
-
return `${(tokens / 1000).toFixed(1)}k`;
|
|
16
|
-
}
|
|
17
|
-
return tokens.toString();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
formatContextSize(size) {
|
|
21
|
-
if (size >= 1000000) {
|
|
22
|
-
return `${Math.round(size / 100000) / 10}M`;
|
|
23
|
-
}
|
|
24
|
-
if (size >= 1000) {
|
|
25
|
-
return `${Math.round(size / 1000)}K`;
|
|
26
|
-
}
|
|
27
|
-
return `${size}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
formatDuration(ms) {
|
|
31
|
-
if (ms < 60000) {
|
|
32
|
-
const secs = Math.round(ms / 1000);
|
|
33
|
-
return secs < 1 ? '<1s' : `${secs}s`;
|
|
34
|
-
}
|
|
35
|
-
const mins = Math.floor(ms / 60000);
|
|
36
|
-
const secs = Math.round((ms % 60000) / 1000);
|
|
37
|
-
return `${mins}m ${secs}s`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
truncatePath(path, maxLen = 20) {
|
|
41
|
-
if (!path || path.length <= maxLen) return path;
|
|
42
|
-
const parts = path.split(/[/\\]/);
|
|
43
|
-
const filename = parts.pop() || path;
|
|
44
|
-
if (filename.length >= maxLen) {
|
|
45
|
-
return filename.slice(0, maxLen - 3) + '...';
|
|
46
|
-
}
|
|
47
|
-
return '.../' + filename;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
truncateDesc(desc, maxLen = 40) {
|
|
51
|
-
if (!desc || desc.length <= maxLen) return desc;
|
|
52
|
-
return desc.slice(0, maxLen - 3) + '...';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
getStatusColor(percentage) {
|
|
56
|
-
if (percentage >= 85) return chalk.red;
|
|
57
|
-
if (percentage >= 60) return chalk.yellow;
|
|
58
|
-
return chalk.green;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
renderSessionLine(data) {
|
|
62
|
-
const {
|
|
63
|
-
modelName,
|
|
64
|
-
currentDir,
|
|
65
|
-
usagePercentage,
|
|
66
|
-
usage,
|
|
67
|
-
remaining,
|
|
68
|
-
expiry,
|
|
69
|
-
contextUsage,
|
|
70
|
-
contextSize,
|
|
71
|
-
configCounts,
|
|
72
|
-
sessionDuration,
|
|
73
|
-
} = data;
|
|
74
|
-
|
|
75
|
-
const parts = [];
|
|
76
|
-
|
|
77
|
-
if (currentDir) {
|
|
78
|
-
parts.push(`${chalk.blue('📁')} ${chalk.cyan(currentDir)}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
parts.push(`${chalk.magenta('🤖')} ${chalk.magenta(modelName)}`);
|
|
82
|
-
|
|
83
|
-
// 上下文窗口在前
|
|
84
|
-
if (contextUsage) {
|
|
85
|
-
const contextPercent = Math.round((contextUsage / contextSize) * 100);
|
|
86
|
-
const contextColor = this.getStatusColor(contextPercent);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
toolCounts.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const
|
|
175
|
-
const
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
const
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const chalk = require('chalk').default;
|
|
4
|
+
|
|
5
|
+
class Renderer {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.RESET = '\x1b[0m';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
formatTokens(tokens) {
|
|
11
|
+
if (tokens >= 1000000) {
|
|
12
|
+
return `${(tokens / 1000000).toFixed(1)}M`;
|
|
13
|
+
}
|
|
14
|
+
if (tokens >= 1000) {
|
|
15
|
+
return `${(tokens / 1000).toFixed(1)}k`;
|
|
16
|
+
}
|
|
17
|
+
return tokens.toString();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
formatContextSize(size) {
|
|
21
|
+
if (size >= 1000000) {
|
|
22
|
+
return `${Math.round(size / 100000) / 10}M`;
|
|
23
|
+
}
|
|
24
|
+
if (size >= 1000) {
|
|
25
|
+
return `${Math.round(size / 1000)}K`;
|
|
26
|
+
}
|
|
27
|
+
return `${size}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
formatDuration(ms) {
|
|
31
|
+
if (ms < 60000) {
|
|
32
|
+
const secs = Math.round(ms / 1000);
|
|
33
|
+
return secs < 1 ? '<1s' : `${secs}s`;
|
|
34
|
+
}
|
|
35
|
+
const mins = Math.floor(ms / 60000);
|
|
36
|
+
const secs = Math.round((ms % 60000) / 1000);
|
|
37
|
+
return `${mins}m ${secs}s`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
truncatePath(path, maxLen = 20) {
|
|
41
|
+
if (!path || path.length <= maxLen) return path;
|
|
42
|
+
const parts = path.split(/[/\\]/);
|
|
43
|
+
const filename = parts.pop() || path;
|
|
44
|
+
if (filename.length >= maxLen) {
|
|
45
|
+
return filename.slice(0, maxLen - 3) + '...';
|
|
46
|
+
}
|
|
47
|
+
return '.../' + filename;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
truncateDesc(desc, maxLen = 40) {
|
|
51
|
+
if (!desc || desc.length <= maxLen) return desc;
|
|
52
|
+
return desc.slice(0, maxLen - 3) + '...';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getStatusColor(percentage) {
|
|
56
|
+
if (percentage >= 85) return chalk.red;
|
|
57
|
+
if (percentage >= 60) return chalk.yellow;
|
|
58
|
+
return chalk.green;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
renderSessionLine(data) {
|
|
62
|
+
const {
|
|
63
|
+
modelName,
|
|
64
|
+
currentDir,
|
|
65
|
+
usagePercentage,
|
|
66
|
+
usage,
|
|
67
|
+
remaining,
|
|
68
|
+
expiry,
|
|
69
|
+
contextUsage,
|
|
70
|
+
contextSize,
|
|
71
|
+
configCounts,
|
|
72
|
+
sessionDuration,
|
|
73
|
+
} = data;
|
|
74
|
+
|
|
75
|
+
const parts = [];
|
|
76
|
+
|
|
77
|
+
if (currentDir) {
|
|
78
|
+
parts.push(`${chalk.blue('📁')} ${chalk.cyan(currentDir)}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
parts.push(`${chalk.magenta('🤖')} ${chalk.magenta(modelName)}`);
|
|
82
|
+
|
|
83
|
+
// 上下文窗口在前
|
|
84
|
+
if (contextUsage !== null && contextUsage !== undefined) {
|
|
85
|
+
const contextPercent = Math.round((contextUsage / contextSize) * 100);
|
|
86
|
+
const contextColor = this.getStatusColor(contextPercent);
|
|
87
|
+
// 合并百分比和实际使用量,用 · 分割,统一颜色
|
|
88
|
+
const contextStr = `${contextColor('⚡' + contextPercent + '%')}${contextColor('·')}${contextColor(this.formatTokens(contextUsage) + ' tokens')}`;
|
|
89
|
+
parts.push(contextStr);
|
|
90
|
+
} else {
|
|
91
|
+
parts.push(`${chalk.cyan(this.formatContextSize(contextSize))}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 使用量合并
|
|
95
|
+
const usageColor = this.getStatusColor(usagePercentage);
|
|
96
|
+
parts.push(`${chalk.yellow('↻')} ${usageColor(usagePercentage + '%')}${chalk.yellow('·')}${chalk.white(usage.remaining + '/' + usage.total)}`);
|
|
97
|
+
|
|
98
|
+
const remainingText = remaining.hours > 0
|
|
99
|
+
? `${remaining.hours}h${remaining.minutes}m`
|
|
100
|
+
: `${remaining.minutes}m`;
|
|
101
|
+
parts.push(`${chalk.yellow('⌛')} ${chalk.white(remainingText)}`);
|
|
102
|
+
|
|
103
|
+
if (configCounts.claudeMdCount > 0) {
|
|
104
|
+
parts.push(`${chalk.white(configCounts.claudeMdCount + ' CLAUDE.md')}`);
|
|
105
|
+
}
|
|
106
|
+
if (configCounts.rulesCount > 0) {
|
|
107
|
+
parts.push(`${chalk.cyan(configCounts.rulesCount + ' rules')}`);
|
|
108
|
+
}
|
|
109
|
+
if (configCounts.mcpCount > 0) {
|
|
110
|
+
parts.push(`${chalk.yellow(configCounts.mcpCount + ' MCPs')}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (expiry) {
|
|
114
|
+
const expiryColor = expiry.daysRemaining <= 3 ? chalk.red : expiry.daysRemaining <= 7 ? chalk.yellow : chalk.green;
|
|
115
|
+
parts.push(`${expiryColor('到期: ' + expiry.daysRemaining + '天')}`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return parts.join(' | ');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
renderToolsLine(tools) {
|
|
122
|
+
if (!tools || tools.length === 0) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const parts = [];
|
|
127
|
+
const runningTools = tools.filter(t => t.status === 'running');
|
|
128
|
+
const completedTools = tools.filter(t => t.status === 'completed' || t.status === 'error');
|
|
129
|
+
|
|
130
|
+
for (const tool of runningTools.slice(-2)) {
|
|
131
|
+
const target = tool.target ? this.truncatePath(tool.target) : '';
|
|
132
|
+
parts.push(`${chalk.yellow('◐')} ${chalk.cyan(tool.name)}${target ? chalk.cyan(': ' + target) : ''}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const toolCounts = new Map();
|
|
136
|
+
for (const tool of completedTools) {
|
|
137
|
+
const count = toolCounts.get(tool.name) || 0;
|
|
138
|
+
toolCounts.set(tool.name, count + 1);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const sortedTools = Array.from(toolCounts.entries())
|
|
142
|
+
.sort((a, b) => b[1] - a[1])
|
|
143
|
+
.slice(0, 4);
|
|
144
|
+
|
|
145
|
+
for (const [name, count] of sortedTools) {
|
|
146
|
+
parts.push(`${chalk.green('✓')} ${name} ${chalk.green('×' + count)}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (parts.length === 0) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return parts.join(' | ');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
renderAgentsLine(agents) {
|
|
157
|
+
if (!agents || agents.length === 0) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const runningAgents = agents.filter(a => a.status === 'running');
|
|
162
|
+
const recentCompleted = agents
|
|
163
|
+
.filter(a => a.status === 'completed')
|
|
164
|
+
.slice(-2);
|
|
165
|
+
|
|
166
|
+
const toShow = [...runningAgents, ...recentCompleted].slice(-3);
|
|
167
|
+
|
|
168
|
+
if (toShow.length === 0) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const lines = [];
|
|
173
|
+
for (const agent of toShow) {
|
|
174
|
+
const statusIcon = agent.status === 'running' ? chalk.yellow('◐') : chalk.green('✓');
|
|
175
|
+
const type = chalk.magenta(agent.type);
|
|
176
|
+
const model = agent.model ? chalk.cyan('[' + agent.model + ']') : '';
|
|
177
|
+
const desc = agent.description ? chalk.white(': ' + this.truncateDesc(agent.description)) : '';
|
|
178
|
+
|
|
179
|
+
const now = Date.now();
|
|
180
|
+
const start = agent.startTime?.getTime() || now;
|
|
181
|
+
const end = agent.endTime?.getTime() || now;
|
|
182
|
+
const elapsed = this.formatDuration(end - start);
|
|
183
|
+
|
|
184
|
+
lines.push(`${statusIcon} ${type}${model}${desc} ${chalk.yellow('(' + elapsed + ')')}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return lines.join('\n');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
renderTodosLine(todos) {
|
|
191
|
+
if (!todos || todos.length === 0) {
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const inProgress = todos.find(t => t.status === 'in_progress');
|
|
196
|
+
const completed = todos.filter(t => t.status === 'completed').length;
|
|
197
|
+
const total = todos.length;
|
|
198
|
+
|
|
199
|
+
if (!inProgress) {
|
|
200
|
+
if (completed === total && total > 0) {
|
|
201
|
+
return `${chalk.green('✓')} All todos complete ${chalk.green('(' + completed + '/' + total + ')')}`;
|
|
202
|
+
}
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const content = this.truncateDesc(inProgress.content, 50);
|
|
207
|
+
const progress = chalk.white('(' + completed + '/' + total + ')');
|
|
208
|
+
|
|
209
|
+
return `${chalk.yellow('▸')} ${content} ${progress}`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
render(context) {
|
|
213
|
+
const lines = [];
|
|
214
|
+
|
|
215
|
+
const sessionLine = this.renderSessionLine(context);
|
|
216
|
+
if (sessionLine) {
|
|
217
|
+
lines.push(sessionLine);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const toolsLine = this.renderToolsLine(context.tools);
|
|
221
|
+
if (toolsLine) {
|
|
222
|
+
lines.push(toolsLine);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const agentsLine = this.renderAgentsLine(context.agents);
|
|
226
|
+
if (agentsLine) {
|
|
227
|
+
lines.push(agentsLine);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const todosLine = this.renderTodosLine(context.todos);
|
|
231
|
+
if (todosLine) {
|
|
232
|
+
lines.push(todosLine);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return lines.join('\n');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
module.exports = Renderer;
|