codemini-cli 0.1.17 → 0.1.19
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 +6 -6
- package/package.json +1 -1
- package/skills/superpowers-lite/SKILL.md +10 -9
- package/src/cli.js +1 -1
- package/src/core/agent-loop.js +56 -29
- package/src/core/chat-runtime.js +79 -16
- package/src/core/command-policy.js +4 -4
- package/src/core/config-store.js +16 -29
- package/src/core/shell-profile.js +1 -1
- package/src/core/tools.js +541 -210
- package/src/tui/chat-app.js +281 -124
package/src/tui/chat-app.js
CHANGED
|
@@ -63,6 +63,8 @@ const TUI_COPY = {
|
|
|
63
63
|
ready: '就绪',
|
|
64
64
|
noMessagesYet: '还没有消息',
|
|
65
65
|
code: '代码',
|
|
66
|
+
codeActivity: '代码活动',
|
|
67
|
+
textNotes: '说明文本',
|
|
66
68
|
live: '运行中',
|
|
67
69
|
idle: '空闲',
|
|
68
70
|
plan: '计划',
|
|
@@ -81,7 +83,7 @@ const TUI_COPY = {
|
|
|
81
83
|
pendingQueue: '等待队列',
|
|
82
84
|
commandPaletteGroupedSelect: '命令面板 | 分组选择模式',
|
|
83
85
|
commandPaletteGroupedSuggestions: '命令面板 | 分组候选',
|
|
84
|
-
startupHint: '使用 /help、/commands、/exit、!<shell>。Tab 可自动补全 slash 命令。',
|
|
86
|
+
startupHint: '使用 /help、/commands、/compact、/exit、!<shell>。Tab 可自动补全 slash 命令。',
|
|
85
87
|
toolSummaryExpanded: '工具摘要:已展开',
|
|
86
88
|
toolSummaryCollapsed: '工具摘要:已收起',
|
|
87
89
|
toggleToolSummary: 'Ctrl+T 切换',
|
|
@@ -103,8 +105,12 @@ const TUI_COPY = {
|
|
|
103
105
|
blocked: '工具被拦截',
|
|
104
106
|
doneRead: '已读取文件',
|
|
105
107
|
doingRead: '正在读取文件',
|
|
108
|
+
doneEdit: '已编辑文件',
|
|
109
|
+
doingEdit: '正在编辑文件',
|
|
106
110
|
doneWrite: '已写入文件',
|
|
107
111
|
doingWrite: '正在写入文件',
|
|
112
|
+
donePatch: '已应用补丁',
|
|
113
|
+
doingPatch: '正在应用补丁',
|
|
108
114
|
doneList: '已查看目录',
|
|
109
115
|
doingList: '正在查看目录',
|
|
110
116
|
doneCommand: '已执行命令',
|
|
@@ -137,6 +143,7 @@ const TUI_COPY = {
|
|
|
137
143
|
modelThinking: '模型正在思考',
|
|
138
144
|
requestDelivered: '请求已送达,等待首个 token',
|
|
139
145
|
generatingReply: '正在生成回复',
|
|
146
|
+
generatingCode: '正在生成代码中',
|
|
140
147
|
streamingReply: '回复正在流式输出',
|
|
141
148
|
replyCompleted: '回复已完成',
|
|
142
149
|
outputFinished: '本轮输出结束',
|
|
@@ -165,6 +172,8 @@ const TUI_COPY = {
|
|
|
165
172
|
ready: 'ready',
|
|
166
173
|
noMessagesYet: 'No messages yet',
|
|
167
174
|
code: 'code',
|
|
175
|
+
codeActivity: 'CODE ACTIVITY',
|
|
176
|
+
textNotes: 'NOTES',
|
|
168
177
|
live: 'LIVE',
|
|
169
178
|
idle: 'IDLE',
|
|
170
179
|
plan: 'PLAN',
|
|
@@ -183,7 +192,7 @@ const TUI_COPY = {
|
|
|
183
192
|
pendingQueue: 'pending queue',
|
|
184
193
|
commandPaletteGroupedSelect: 'command palette | grouped select mode',
|
|
185
194
|
commandPaletteGroupedSuggestions: 'command palette | grouped suggestions',
|
|
186
|
-
startupHint: 'Use /help, /commands, /exit, !<shell>. Tab for slash autocomplete.',
|
|
195
|
+
startupHint: 'Use /help, /commands, /compact, /exit, !<shell>. Tab for slash autocomplete.',
|
|
187
196
|
toolSummaryExpanded: 'Tool summary: expanded',
|
|
188
197
|
toolSummaryCollapsed: 'Tool summary: collapsed',
|
|
189
198
|
toggleToolSummary: 'Ctrl+T to toggle',
|
|
@@ -205,8 +214,12 @@ const TUI_COPY = {
|
|
|
205
214
|
blocked: 'Tool blocked',
|
|
206
215
|
doneRead: 'Read file',
|
|
207
216
|
doingRead: 'Reading file',
|
|
217
|
+
doneEdit: 'Edited file',
|
|
218
|
+
doingEdit: 'Editing file',
|
|
208
219
|
doneWrite: 'Wrote file',
|
|
209
220
|
doingWrite: 'Writing file',
|
|
221
|
+
donePatch: 'Applied patch',
|
|
222
|
+
doingPatch: 'Applying patch',
|
|
210
223
|
doneList: 'Listed directory',
|
|
211
224
|
doingList: 'Listing directory',
|
|
212
225
|
doneCommand: 'Ran command',
|
|
@@ -239,6 +252,7 @@ const TUI_COPY = {
|
|
|
239
252
|
modelThinking: 'model is thinking',
|
|
240
253
|
requestDelivered: 'request sent, waiting for first token',
|
|
241
254
|
generatingReply: 'generating reply',
|
|
255
|
+
generatingCode: 'generating code',
|
|
242
256
|
streamingReply: 'reply is streaming',
|
|
243
257
|
replyCompleted: 'reply completed',
|
|
244
258
|
outputFinished: 'turn output finished',
|
|
@@ -313,9 +327,14 @@ function getActivityDisplayParts(activity) {
|
|
|
313
327
|
}
|
|
314
328
|
const parsed = parseToolDisplayName(activity?.name);
|
|
315
329
|
const labels = {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
330
|
+
read: 'Read',
|
|
331
|
+
edit: 'Edit',
|
|
332
|
+
write: 'Write',
|
|
333
|
+
patch: 'Patch',
|
|
334
|
+
run: 'Run',
|
|
335
|
+
grep: 'Grep',
|
|
336
|
+
glob: 'Glob',
|
|
337
|
+
list: 'List',
|
|
319
338
|
start_service: 'Service',
|
|
320
339
|
list_services: 'Service',
|
|
321
340
|
get_service_status: 'Service',
|
|
@@ -334,33 +353,47 @@ function getActivityDisplayParts(activity) {
|
|
|
334
353
|
function describeToolActivity(name, copy, { done = false, blocked = false } = {}) {
|
|
335
354
|
const { raw, base, target } = parseToolDisplayName(name);
|
|
336
355
|
const safeTarget = trimText(target, 72);
|
|
337
|
-
if (base === '
|
|
356
|
+
if (base === 'read') {
|
|
338
357
|
return blocked
|
|
339
|
-
? `${copy.toolActivity.blocked}:
|
|
358
|
+
? `${copy.toolActivity.blocked}: ${base}(${safeTarget || '.'})`
|
|
340
359
|
: done
|
|
341
360
|
? `${copy.toolActivity.doneRead}: ${safeTarget || '.'}`
|
|
342
361
|
: `${copy.toolActivity.doingRead}: ${safeTarget || '.'}`;
|
|
343
362
|
}
|
|
344
|
-
if (base === '
|
|
363
|
+
if (base === 'edit') {
|
|
345
364
|
return blocked
|
|
346
|
-
? `${copy.toolActivity.blocked}:
|
|
365
|
+
? `${copy.toolActivity.blocked}: ${base}(${safeTarget || '.'})`
|
|
366
|
+
: done
|
|
367
|
+
? `${copy.toolActivity.doneEdit}: ${safeTarget || '.'}`
|
|
368
|
+
: `${copy.toolActivity.doingEdit}: ${safeTarget || '.'}`;
|
|
369
|
+
}
|
|
370
|
+
if (base === 'write') {
|
|
371
|
+
return blocked
|
|
372
|
+
? `${copy.toolActivity.blocked}: ${base}(${safeTarget || '.'})`
|
|
347
373
|
: done
|
|
348
374
|
? `${copy.toolActivity.doneWrite}: ${safeTarget || '.'}`
|
|
349
375
|
: `${copy.toolActivity.doingWrite}: ${safeTarget || '.'}`;
|
|
350
376
|
}
|
|
351
|
-
if (base === '
|
|
377
|
+
if (base === 'patch') {
|
|
378
|
+
return blocked
|
|
379
|
+
? `${copy.toolActivity.blocked}: ${base}(${safeTarget || '.'})`
|
|
380
|
+
: done
|
|
381
|
+
? `${copy.toolActivity.donePatch}: ${safeTarget || '.'}`
|
|
382
|
+
: `${copy.toolActivity.doingPatch}: ${safeTarget || '.'}`;
|
|
383
|
+
}
|
|
384
|
+
if (base === 'list' || base === 'glob' || base === 'grep') {
|
|
352
385
|
return blocked
|
|
353
|
-
? `${copy.toolActivity.blocked}:
|
|
386
|
+
? `${copy.toolActivity.blocked}: ${base}(${safeTarget || '.'})`
|
|
354
387
|
: done
|
|
355
388
|
? `${copy.toolActivity.doneList}: ${safeTarget || '.'}`
|
|
356
389
|
: `${copy.toolActivity.doingList}: ${safeTarget || '.'}`;
|
|
357
390
|
}
|
|
358
|
-
if (base === '
|
|
391
|
+
if (base === 'run') {
|
|
359
392
|
return blocked
|
|
360
|
-
? `${copy.toolActivity.blocked}: ${safeTarget ||
|
|
393
|
+
? `${copy.toolActivity.blocked}: ${safeTarget || base}`
|
|
361
394
|
: done
|
|
362
|
-
? `${copy.toolActivity.doneCommand}: ${safeTarget ||
|
|
363
|
-
: `${copy.toolActivity.doingCommand}: ${safeTarget ||
|
|
395
|
+
? `${copy.toolActivity.doneCommand}: ${safeTarget || base}`
|
|
396
|
+
: `${copy.toolActivity.doingCommand}: ${safeTarget || base}`;
|
|
364
397
|
}
|
|
365
398
|
if (base === 'start_service' || base === 'list_services' || base === 'get_service_status' || base === 'get_service_logs' || base === 'stop_service') {
|
|
366
399
|
return blocked
|
|
@@ -451,6 +484,52 @@ function RuntimeStrip({ busy, runtimeStatus, loaderTick, copy }) {
|
|
|
451
484
|
);
|
|
452
485
|
}
|
|
453
486
|
|
|
487
|
+
function ContextProgressMeter({ runtimeState, runtimeStatus, compact = false }) {
|
|
488
|
+
const maxContextTokens = Number(runtimeState?.maxContextTokens || 0);
|
|
489
|
+
const currentContextTokens = Number(runtimeState?.currentContextTokens || 0);
|
|
490
|
+
const pctRaw =
|
|
491
|
+
Number.isFinite(runtimeState?.contextUsagePct) && runtimeState.contextUsagePct >= 0
|
|
492
|
+
? runtimeState.contextUsagePct
|
|
493
|
+
: maxContextTokens > 0
|
|
494
|
+
? (currentContextTokens / maxContextTokens) * 100
|
|
495
|
+
: 0;
|
|
496
|
+
const pct = Math.min(100, Math.max(0, pctRaw));
|
|
497
|
+
const filled = Math.min(12, Math.max(0, Math.round((pct / 100) * 12)));
|
|
498
|
+
const activeColor = pct < 40 ? 'greenBright' : pct < 75 ? 'yellowBright' : 'redBright';
|
|
499
|
+
const statusColor = runtimeStatus?.color || activeColor;
|
|
500
|
+
const chunks = Array.from({ length: 12 }, (_, idx) => {
|
|
501
|
+
const zoneColor = idx < 5 ? 'greenBright' : idx < 9 ? 'yellowBright' : 'redBright';
|
|
502
|
+
const color = idx < filled ? zoneColor : 'gray';
|
|
503
|
+
return h(Text, { key: `context-meter-${idx}`, color }, '|');
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
if (compact) {
|
|
507
|
+
return h(
|
|
508
|
+
Box,
|
|
509
|
+
{ justifyContent: 'flex-end', alignItems: 'center' },
|
|
510
|
+
h(Text, { color: 'gray' }, '上下文 '),
|
|
511
|
+
h(Text, { color: statusColor }, `${Math.round(pct)}% `),
|
|
512
|
+
h(
|
|
513
|
+
Box,
|
|
514
|
+
{ flexDirection: 'row' },
|
|
515
|
+
...chunks
|
|
516
|
+
)
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return h(
|
|
521
|
+
Box,
|
|
522
|
+
{ justifyContent: 'flex-end', alignItems: 'center' },
|
|
523
|
+
h(Text, { color: 'gray' }, '上下文 '),
|
|
524
|
+
h(Text, { color: statusColor }, `${Math.round(pct)}% `),
|
|
525
|
+
h(
|
|
526
|
+
Box,
|
|
527
|
+
null,
|
|
528
|
+
...chunks
|
|
529
|
+
)
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
454
533
|
function PlanStrip({ planState, copy }) {
|
|
455
534
|
if (!planState || !planState.total) return null;
|
|
456
535
|
const progress = `${planState.current}/${planState.total}`;
|
|
@@ -632,6 +711,21 @@ export function injectPlanStateMessage(messages, planState, activeUserMessageId,
|
|
|
632
711
|
return [...withNoPlanStrip, synthetic];
|
|
633
712
|
}
|
|
634
713
|
|
|
714
|
+
export function injectRuntimeStateMessage(messages, runtimeState, runtimeStatus, busy, activeUserMessageId, activeAssistantId) {
|
|
715
|
+
const source = Array.isArray(messages) ? messages : [];
|
|
716
|
+
if (!runtimeState) return source;
|
|
717
|
+
const withoutRuntimeStrip = source.filter((message) => !message?.runtimeStrip);
|
|
718
|
+
const userIdx = withoutRuntimeStrip.findIndex((message) => message.id === activeUserMessageId);
|
|
719
|
+
if (userIdx !== -1) {
|
|
720
|
+
return withoutRuntimeStrip;
|
|
721
|
+
}
|
|
722
|
+
const assistantIdx = withoutRuntimeStrip.findIndex((message) => message.id === activeAssistantId);
|
|
723
|
+
if (assistantIdx !== -1) {
|
|
724
|
+
return withoutRuntimeStrip;
|
|
725
|
+
}
|
|
726
|
+
return withoutRuntimeStrip;
|
|
727
|
+
}
|
|
728
|
+
|
|
635
729
|
function PlanSummaryBubble({ msg, copy }) {
|
|
636
730
|
const theme = roleStyle(msg.label);
|
|
637
731
|
const summary = msg.planSummary || parseAutoPlanSummaryMessage(msg.text);
|
|
@@ -817,6 +911,38 @@ function isBlankTextRow(row) {
|
|
|
817
911
|
return row?.kind === 'text' && String(row?.text || '').trim() === '';
|
|
818
912
|
}
|
|
819
913
|
|
|
914
|
+
function isCodeActivityName(name) {
|
|
915
|
+
const parsed = parseToolDisplayName(name);
|
|
916
|
+
return new Set([
|
|
917
|
+
'edit',
|
|
918
|
+
'write_file',
|
|
919
|
+
'patch',
|
|
920
|
+
'replace_text',
|
|
921
|
+
'replace_block',
|
|
922
|
+
'insert_before',
|
|
923
|
+
'insert_after',
|
|
924
|
+
'validate_edit',
|
|
925
|
+
'generate_diff'
|
|
926
|
+
]).has(parsed.base);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
export function isCodeLikeRow(row) {
|
|
930
|
+
if (!row) return false;
|
|
931
|
+
if (row.kind === 'code' || row.kind === 'activity' || row.kind === 'activity-summary') return true;
|
|
932
|
+
if (row.kind === 'status') return true;
|
|
933
|
+
return false;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
export function splitMessageRows(rows) {
|
|
937
|
+
const textRows = [];
|
|
938
|
+
const codeRows = [];
|
|
939
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
940
|
+
if (isCodeLikeRow(row)) codeRows.push(row);
|
|
941
|
+
else textRows.push(row);
|
|
942
|
+
}
|
|
943
|
+
return { textRows, codeRows };
|
|
944
|
+
}
|
|
945
|
+
|
|
820
946
|
export function normalizeActivitySpacingRows(inputRows) {
|
|
821
947
|
const rows = Array.isArray(inputRows) ? inputRows : [];
|
|
822
948
|
const normalized = [];
|
|
@@ -863,7 +989,7 @@ export function normalizeActivitySpacingRows(inputRows) {
|
|
|
863
989
|
|
|
864
990
|
function isReadActivityName(name) {
|
|
865
991
|
const parsed = parseToolDisplayName(name);
|
|
866
|
-
return parsed.base === '
|
|
992
|
+
return parsed.base === 'read' || parsed.base === 'Read';
|
|
867
993
|
}
|
|
868
994
|
|
|
869
995
|
function isIgnorableSegmentAfterRead(item, activityType, activityName) {
|
|
@@ -1014,6 +1140,105 @@ function buildMessageRows(msg, showToolDetails, contentWidth = 72) {
|
|
|
1014
1140
|
return normalizeActivitySpacingRows(rows);
|
|
1015
1141
|
}
|
|
1016
1142
|
|
|
1143
|
+
function renderMessageRow(msg, row, idx, loaderTick) {
|
|
1144
|
+
if (row.kind === 'activity') {
|
|
1145
|
+
const activity = { type: row.activityType, name: row.name, status: row.status };
|
|
1146
|
+
const display = getActivityDisplayParts(activity);
|
|
1147
|
+
const dotColor =
|
|
1148
|
+
activity.type === 'skill'
|
|
1149
|
+
? row.status === 'error'
|
|
1150
|
+
? 'redBright'
|
|
1151
|
+
: 'blueBright'
|
|
1152
|
+
: row.status === 'error' || row.status === 'blocked'
|
|
1153
|
+
? 'redBright'
|
|
1154
|
+
: 'greenBright';
|
|
1155
|
+
const textColor =
|
|
1156
|
+
activity.type === 'skill'
|
|
1157
|
+
? row.status === 'error'
|
|
1158
|
+
? 'redBright'
|
|
1159
|
+
: 'cyanBright'
|
|
1160
|
+
: row.status === 'error' || row.status === 'blocked'
|
|
1161
|
+
? 'redBright'
|
|
1162
|
+
: 'greenBright';
|
|
1163
|
+
return h(
|
|
1164
|
+
Box,
|
|
1165
|
+
{ key: `row-tool-${msg.id}-${idx}` },
|
|
1166
|
+
h(Text, { color: 'gray' }, ' '),
|
|
1167
|
+
h(Text, { color: dotColor }, '●'),
|
|
1168
|
+
h(Text, { color: 'gray' }, ' '),
|
|
1169
|
+
h(Text, { color: textColor }, display.primary),
|
|
1170
|
+
h(Text, { color: 'gray' }, display.secondary),
|
|
1171
|
+
row.durationText ? h(Text, { color: row.statusColor }, ` ${row.durationText}`) : null
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
if (row.kind === 'activity-summary') {
|
|
1175
|
+
return h(
|
|
1176
|
+
Box,
|
|
1177
|
+
{ key: `row-tool-summary-${msg.id}-${idx}`, marginLeft: 1 },
|
|
1178
|
+
h(Text, { color: 'gray' }, `└ ${row.text}`)
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
if (row.kind === 'plan-progress') {
|
|
1182
|
+
return h(
|
|
1183
|
+
Box,
|
|
1184
|
+
{ key: `row-plan-progress-${msg.id}-${idx}`, marginTop: 1, marginBottom: 1 },
|
|
1185
|
+
h(Text, { color: 'cyanBright' }, '[plan] '),
|
|
1186
|
+
h(Text, { color: 'yellowBright' }, `Step ${row.current}/${row.total}`),
|
|
1187
|
+
h(Text, { color: 'gray' }, ' -> '),
|
|
1188
|
+
h(Text, { color: 'magentaBright' }, String(row.role || 'agent').toUpperCase()),
|
|
1189
|
+
h(Text, { color: 'gray' }, ': '),
|
|
1190
|
+
h(Text, { color: 'white' }, row.title)
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
if (row.kind === 'status') {
|
|
1194
|
+
const dots = '.'.repeat((loaderTick % 3) + 1);
|
|
1195
|
+
const phase = msg.phase;
|
|
1196
|
+
const color =
|
|
1197
|
+
phase === 'sending'
|
|
1198
|
+
? 'yellowBright'
|
|
1199
|
+
: phase === 'queued'
|
|
1200
|
+
? 'cyanBright'
|
|
1201
|
+
: phase === 'tooling'
|
|
1202
|
+
? 'magentaBright'
|
|
1203
|
+
: phase === 'generating'
|
|
1204
|
+
? 'greenBright'
|
|
1205
|
+
: 'cyanBright';
|
|
1206
|
+
return h(
|
|
1207
|
+
Box,
|
|
1208
|
+
{ key: `row-status-${msg.id}-${idx}`, marginTop: 1 },
|
|
1209
|
+
h(Text, { color: 'gray' }, ' '),
|
|
1210
|
+
h(Text, { color }, `${row.text}${dots}`)
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
if (row.kind === 'quote') {
|
|
1214
|
+
return h(
|
|
1215
|
+
Box,
|
|
1216
|
+
{ key: `row-quote-${msg.id}-${idx}`, marginTop: 1, marginLeft: 1, paddingLeft: 1 },
|
|
1217
|
+
h(Text, { color: 'yellow' }, '▍ '),
|
|
1218
|
+
h(Text, { color: row.color }, ...renderInlineCode(row.text, row.color))
|
|
1219
|
+
);
|
|
1220
|
+
}
|
|
1221
|
+
if (row.kind === 'tree') {
|
|
1222
|
+
return h(
|
|
1223
|
+
Box,
|
|
1224
|
+
{ key: `row-tree-${msg.id}-${idx}`, marginLeft: 1 },
|
|
1225
|
+
h(Text, { color: row.color }, row.text)
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
if (row.kind === 'code') {
|
|
1229
|
+
return h(
|
|
1230
|
+
Box,
|
|
1231
|
+
{ key: `row-code-${msg.id}-${idx}`, marginLeft: 1 },
|
|
1232
|
+
h(Text, { color: 'gray' }, row.text)
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
return renderTextLine(msg, row.text, idx, row.color);
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
function renderMessageRowsInOrder(msg, rows, loaderTick, copy) {
|
|
1239
|
+
return rows.map((row, idx) => renderMessageRow(msg, row, idx, loaderTick));
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1017
1242
|
|
|
1018
1243
|
function groupCommandSuggestions(items) {
|
|
1019
1244
|
const categoryMap = {
|
|
@@ -1128,100 +1353,7 @@ function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, con
|
|
|
1128
1353
|
const start = rowWindow ? Math.max(0, rowWindow.start || 0) : 0;
|
|
1129
1354
|
const end = rowWindow ? Math.max(start, rowWindow.end || allRows.length) : allRows.length;
|
|
1130
1355
|
const visibleRows = allRows.slice(start, end);
|
|
1131
|
-
const rendered =
|
|
1132
|
-
if (row.kind === 'activity') {
|
|
1133
|
-
const activity = { type: row.activityType, name: row.name, status: row.status };
|
|
1134
|
-
const display = getActivityDisplayParts(activity);
|
|
1135
|
-
const dotColor =
|
|
1136
|
-
activity.type === 'skill'
|
|
1137
|
-
? row.status === 'error'
|
|
1138
|
-
? 'redBright'
|
|
1139
|
-
: 'blueBright'
|
|
1140
|
-
: row.status === 'error' || row.status === 'blocked'
|
|
1141
|
-
? 'redBright'
|
|
1142
|
-
: 'greenBright';
|
|
1143
|
-
const textColor =
|
|
1144
|
-
activity.type === 'skill'
|
|
1145
|
-
? row.status === 'error'
|
|
1146
|
-
? 'redBright'
|
|
1147
|
-
: 'cyanBright'
|
|
1148
|
-
: row.status === 'error' || row.status === 'blocked'
|
|
1149
|
-
? 'redBright'
|
|
1150
|
-
: 'greenBright';
|
|
1151
|
-
return h(
|
|
1152
|
-
Box,
|
|
1153
|
-
{ key: `row-tool-${msg.id}-${idx}` },
|
|
1154
|
-
h(Text, { color: 'gray' }, ' '),
|
|
1155
|
-
h(Text, { color: dotColor }, '●'),
|
|
1156
|
-
h(Text, { color: 'gray' }, ' '),
|
|
1157
|
-
h(Text, { color: textColor }, display.primary),
|
|
1158
|
-
h(Text, { color: 'gray' }, display.secondary),
|
|
1159
|
-
row.durationText ? h(Text, { color: row.statusColor }, ` ${row.durationText}`) : null
|
|
1160
|
-
);
|
|
1161
|
-
}
|
|
1162
|
-
if (row.kind === 'activity-summary') {
|
|
1163
|
-
return h(
|
|
1164
|
-
Box,
|
|
1165
|
-
{ key: `row-tool-summary-${msg.id}-${idx}`, marginLeft: 2 },
|
|
1166
|
-
h(Text, { color: 'gray' }, `└ ${row.text}`)
|
|
1167
|
-
);
|
|
1168
|
-
}
|
|
1169
|
-
if (row.kind === 'plan-progress') {
|
|
1170
|
-
return h(
|
|
1171
|
-
Box,
|
|
1172
|
-
{ key: `row-plan-progress-${msg.id}-${idx}`, marginTop: 1, marginBottom: 1 },
|
|
1173
|
-
h(Text, { color: 'cyanBright' }, '[plan] '),
|
|
1174
|
-
h(Text, { color: 'yellowBright' }, `Step ${row.current}/${row.total}`),
|
|
1175
|
-
h(Text, { color: 'gray' }, ' -> '),
|
|
1176
|
-
h(Text, { color: 'magentaBright' }, String(row.role || 'agent').toUpperCase()),
|
|
1177
|
-
h(Text, { color: 'gray' }, ': '),
|
|
1178
|
-
h(Text, { color: 'white' }, row.title)
|
|
1179
|
-
);
|
|
1180
|
-
}
|
|
1181
|
-
if (row.kind === 'status') {
|
|
1182
|
-
const dots = '.'.repeat((loaderTick % 3) + 1);
|
|
1183
|
-
const phase = msg.phase;
|
|
1184
|
-
const color =
|
|
1185
|
-
phase === 'sending'
|
|
1186
|
-
? 'yellowBright'
|
|
1187
|
-
: phase === 'queued'
|
|
1188
|
-
? 'cyanBright'
|
|
1189
|
-
: phase === 'tooling'
|
|
1190
|
-
? 'magentaBright'
|
|
1191
|
-
: phase === 'generating'
|
|
1192
|
-
? 'greenBright'
|
|
1193
|
-
: 'cyanBright';
|
|
1194
|
-
return h(
|
|
1195
|
-
Box,
|
|
1196
|
-
{ key: `row-status-${msg.id}-${idx}`, marginTop: 1 },
|
|
1197
|
-
h(Text, { color: 'gray' }, ' '),
|
|
1198
|
-
h(Text, { color }, `${row.text}${dots}`)
|
|
1199
|
-
);
|
|
1200
|
-
}
|
|
1201
|
-
if (row.kind === 'quote') {
|
|
1202
|
-
return h(
|
|
1203
|
-
Box,
|
|
1204
|
-
{ key: `row-quote-${msg.id}-${idx}`, marginTop: 1, marginLeft: 1, paddingLeft: 1 },
|
|
1205
|
-
h(Text, { color: 'yellow' }, '▍ '),
|
|
1206
|
-
h(Text, { color: row.color }, ...renderInlineCode(row.text, row.color))
|
|
1207
|
-
);
|
|
1208
|
-
}
|
|
1209
|
-
if (row.kind === 'tree') {
|
|
1210
|
-
return h(
|
|
1211
|
-
Box,
|
|
1212
|
-
{ key: `row-tree-${msg.id}-${idx}`, marginLeft: 1 },
|
|
1213
|
-
h(Text, { color: row.color }, row.text)
|
|
1214
|
-
);
|
|
1215
|
-
}
|
|
1216
|
-
if (row.kind === 'code') {
|
|
1217
|
-
return h(
|
|
1218
|
-
Box,
|
|
1219
|
-
{ key: `row-code-${msg.id}-${idx}`, marginLeft: 1 },
|
|
1220
|
-
h(Text, { color: 'gray' }, row.text)
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
return renderTextLine(msg, row.text, idx, row.color);
|
|
1224
|
-
});
|
|
1356
|
+
const rendered = renderMessageRowsInOrder(msg, visibleRows, loaderTick, copy);
|
|
1225
1357
|
|
|
1226
1358
|
return h(
|
|
1227
1359
|
Box,
|
|
@@ -1336,7 +1468,7 @@ function PendingPanel({ pendingQueue, copy }) {
|
|
|
1336
1468
|
return h(
|
|
1337
1469
|
Box,
|
|
1338
1470
|
{
|
|
1339
|
-
marginTop:
|
|
1471
|
+
marginTop: 0,
|
|
1340
1472
|
flexDirection: 'column',
|
|
1341
1473
|
borderStyle: 'round',
|
|
1342
1474
|
borderColor: 'cyan',
|
|
@@ -1416,11 +1548,10 @@ function InputBar({
|
|
|
1416
1548
|
),
|
|
1417
1549
|
h(
|
|
1418
1550
|
Box,
|
|
1419
|
-
|
|
1420
|
-
h(Text, { color: '
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
h(Text, { color: showToolDetails ? 'greenBright' : 'gray' }, ` ${copy.generic.tools} ${showToolDetails ? copy.generic.open : copy.generic.collapsed}`)
|
|
1551
|
+
{ flexDirection: 'column', alignItems: 'flex-end' },
|
|
1552
|
+
h(Text, { color: showToolDetails ? 'greenBright' : 'gray' }, ` ${copy.generic.tools} ${showToolDetails ? copy.generic.open : copy.generic.collapsed}`),
|
|
1553
|
+
pendingQueueLength > 0 ? h(Text, { color: 'cyanBright' }, ` ${copy.generic.queued} ${pendingQueueLength}`) : null,
|
|
1554
|
+
inputStage !== 'idle' || busy ? h(Text, { color: status.color }, ` ${status.tag}`) : null
|
|
1424
1555
|
)
|
|
1425
1556
|
),
|
|
1426
1557
|
h(
|
|
@@ -1503,6 +1634,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1503
1634
|
const [runtimeStatus, setRuntimeStatus] = useState(
|
|
1504
1635
|
makeIdleStatus(copy, runtime.getRuntimeState?.(), 'ready')
|
|
1505
1636
|
);
|
|
1637
|
+
const [runtimeState, setRuntimeState] = useState(runtime.getRuntimeState?.() || null);
|
|
1506
1638
|
const [inputStage, setInputStage] = useState('idle');
|
|
1507
1639
|
const [planState, setPlanState] = useState({
|
|
1508
1640
|
current: 0,
|
|
@@ -1519,12 +1651,17 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1519
1651
|
const activeUserMessageIdRef = useRef(null);
|
|
1520
1652
|
const cursorIndexRef = useRef(0);
|
|
1521
1653
|
const inFlightRef = useRef(false);
|
|
1654
|
+
const messagesRef = useRef([]);
|
|
1522
1655
|
const pendingQueueRef = useRef([]);
|
|
1523
1656
|
const deltaBufferRef = useRef('');
|
|
1524
1657
|
const deltaFlushTimerRef = useRef(null);
|
|
1525
1658
|
const escSeqRef = useRef('');
|
|
1526
1659
|
const planTextBufferRef = useRef('');
|
|
1527
1660
|
const { exit } = useApp();
|
|
1661
|
+
|
|
1662
|
+
useEffect(() => {
|
|
1663
|
+
messagesRef.current = messages;
|
|
1664
|
+
}, [messages]);
|
|
1528
1665
|
const startupHint = copy.generic.startupHint;
|
|
1529
1666
|
const isBackspaceKey = (value, key) =>
|
|
1530
1667
|
Boolean(key?.backspace) || value === '\u0008' || value === '\u007f' || (key?.ctrl && value === 'h');
|
|
@@ -1565,6 +1702,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1565
1702
|
if (!snapshot) return;
|
|
1566
1703
|
setDisplaySessionId(snapshot.sessionId || sessionId);
|
|
1567
1704
|
setDisplayModel(snapshot.model || model);
|
|
1705
|
+
setRuntimeState(snapshot);
|
|
1568
1706
|
setRuntimeStatus(makeIdleStatus(copy, snapshot, variant));
|
|
1569
1707
|
};
|
|
1570
1708
|
|
|
@@ -1815,7 +1953,18 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1815
1953
|
updatePlanProgressFromText(event.text);
|
|
1816
1954
|
setRuntimeStatus(makeStatus(copy.runtime.generatingReply, copy.runtime.streamingReply, 'greenBright'));
|
|
1817
1955
|
setInputStage('streaming');
|
|
1818
|
-
setActiveAssistantMeta(
|
|
1956
|
+
setActiveAssistantMeta((() => {
|
|
1957
|
+
const targetId = activeAssistantIdRef.current;
|
|
1958
|
+
let liveStatus = copy.runtime.generatingReply;
|
|
1959
|
+
if (targetId) {
|
|
1960
|
+
const current = messagesRef.current?.find?.((m) => m.id === targetId);
|
|
1961
|
+
const segments = Array.isArray(current?.segments) ? current.segments : [];
|
|
1962
|
+
if (segments.some((segment) => (segment.type === 'tool' || segment.type === 'skill') && isCodeActivityName(segment.name))) {
|
|
1963
|
+
liveStatus = copy.runtime.generatingCode;
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1966
|
+
return { loading: true, phase: 'generating', liveStatus };
|
|
1967
|
+
})());
|
|
1819
1968
|
queueAssistantDelta(event.text);
|
|
1820
1969
|
}
|
|
1821
1970
|
if (event?.type === 'assistant:response') {
|
|
@@ -1835,7 +1984,11 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
1835
1984
|
const detail = describeToolActivity(event.name, copy);
|
|
1836
1985
|
setRuntimeStatus(makeStatus(copy.runtime.toolRunning, detail, 'magentaBright'));
|
|
1837
1986
|
setInputStage('tooling');
|
|
1838
|
-
setActiveAssistantMeta({
|
|
1987
|
+
setActiveAssistantMeta({
|
|
1988
|
+
loading: true,
|
|
1989
|
+
phase: 'tooling',
|
|
1990
|
+
liveStatus: isCodeActivityName(event.name) ? copy.runtime.generatingCode : detail
|
|
1991
|
+
});
|
|
1839
1992
|
updateActivityStatusOnActiveAssistant({
|
|
1840
1993
|
type: 'tool',
|
|
1841
1994
|
id: event.id,
|
|
@@ -2386,7 +2539,6 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2386
2539
|
Box,
|
|
2387
2540
|
{ flexDirection: 'column' },
|
|
2388
2541
|
h(Header, { sessionId: displaySessionId, model: displayModel, shellName }),
|
|
2389
|
-
h(RuntimeStrip, { busy, runtimeStatus, loaderTick, copy }),
|
|
2390
2542
|
h(MessageList, {
|
|
2391
2543
|
messages: visibleMessages,
|
|
2392
2544
|
loaderTick,
|
|
@@ -2396,12 +2548,17 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2396
2548
|
}),
|
|
2397
2549
|
h(
|
|
2398
2550
|
Box,
|
|
2399
|
-
{ marginTop:
|
|
2551
|
+
{ marginTop: 0, marginBottom: 0, justifyContent: 'space-between', width: '100%' },
|
|
2400
2552
|
h(
|
|
2401
|
-
|
|
2402
|
-
{
|
|
2403
|
-
|
|
2404
|
-
|
|
2553
|
+
Box,
|
|
2554
|
+
{ flexGrow: 1 },
|
|
2555
|
+
h(
|
|
2556
|
+
Text,
|
|
2557
|
+
{ color: 'gray' },
|
|
2558
|
+
`${showToolDetails ? copy.generic.toolSummaryExpanded : copy.generic.toolSummaryCollapsed} (${copy.generic.toggleToolSummary}) · ${copy.generic.scrollHint}`
|
|
2559
|
+
)
|
|
2560
|
+
),
|
|
2561
|
+
h(ContextProgressMeter, { runtimeState, runtimeStatus, compact: true })
|
|
2405
2562
|
),
|
|
2406
2563
|
h(SuggestionPanel, { commandSuggestions, suggestionNav, menuIndex, copy }),
|
|
2407
2564
|
h(PendingPanel, { pendingQueue, copy }),
|