codemini-cli 0.2.1 → 0.2.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/package.json +1 -1
- package/src/cli.js +1 -1
- package/src/tui/chat-app.js +111 -35
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@ import { handleConfig } from './commands/config.js';
|
|
|
4
4
|
import { handleDoctor } from './commands/doctor.js';
|
|
5
5
|
import { handleSkill } from './commands/skill.js';
|
|
6
6
|
|
|
7
|
-
const VERSION = '0.2.
|
|
7
|
+
const VERSION = '0.2.2';
|
|
8
8
|
|
|
9
9
|
function printHelp() {
|
|
10
10
|
console.log(`codemini ${VERSION}
|
package/src/tui/chat-app.js
CHANGED
|
@@ -63,6 +63,7 @@ const TUI_COPY = {
|
|
|
63
63
|
waitingForInput: '等待输入',
|
|
64
64
|
ready: '就绪',
|
|
65
65
|
noMessagesYet: '还没有消息',
|
|
66
|
+
taskCompleted: '已完成任务',
|
|
66
67
|
code: '代码',
|
|
67
68
|
codeActivity: '代码活动',
|
|
68
69
|
textNotes: '说明文本',
|
|
@@ -193,6 +194,7 @@ const TUI_COPY = {
|
|
|
193
194
|
waitingForInput: 'waiting for input',
|
|
194
195
|
ready: 'ready',
|
|
195
196
|
noMessagesYet: 'No messages yet',
|
|
197
|
+
taskCompleted: 'Task completed',
|
|
196
198
|
code: 'code',
|
|
197
199
|
codeActivity: 'CODE ACTIVITY',
|
|
198
200
|
textNotes: 'NOTES',
|
|
@@ -469,6 +471,15 @@ function getActivityDisplayParts(activity) {
|
|
|
469
471
|
};
|
|
470
472
|
}
|
|
471
473
|
|
|
474
|
+
export function isIndexSystemToolName(name) {
|
|
475
|
+
const parsed = parseToolDisplayName(name);
|
|
476
|
+
return parsed.base === 'project_index' || parsed.base === 'file_index';
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export function shouldShowCompletionFooter(msg) {
|
|
480
|
+
return Boolean(msg && msg.label === 'coder' && !msg.loading && !(msg.phase || '').trim());
|
|
481
|
+
}
|
|
482
|
+
|
|
472
483
|
function describeToolActivity(name, copy, { done = false, blocked = false } = {}) {
|
|
473
484
|
const parsed = parseToolDisplayName(name);
|
|
474
485
|
if (parsed.base === 'project_index') {
|
|
@@ -905,9 +916,16 @@ export function parsePlanProgressLine(text) {
|
|
|
905
916
|
};
|
|
906
917
|
}
|
|
907
918
|
|
|
908
|
-
function
|
|
919
|
+
function getTailPreviewWindow(text, maxLines = 3) {
|
|
909
920
|
const source = String(text || '');
|
|
910
|
-
if (!source.trim()) return [];
|
|
921
|
+
if (!source.trim()) return { lines: [], startLine: 1 };
|
|
922
|
+
const sliceTail = (lines) => {
|
|
923
|
+
const tail = lines.slice(-Math.max(1, maxLines));
|
|
924
|
+
return {
|
|
925
|
+
lines: tail,
|
|
926
|
+
startLine: Math.max(1, lines.length - tail.length + 1)
|
|
927
|
+
};
|
|
928
|
+
};
|
|
911
929
|
|
|
912
930
|
const lines = source.split('\n').map((line) => line.replace(/\r$/, ''));
|
|
913
931
|
let insideFence = false;
|
|
@@ -935,21 +953,21 @@ function getTailPreviewLines(text, maxLines = 3) {
|
|
|
935
953
|
if (insideFence) {
|
|
936
954
|
const codeLines = fenceLines.filter((line) => line.trim().length > 0);
|
|
937
955
|
if (codeLines.length > 0) {
|
|
938
|
-
return codeLines
|
|
956
|
+
return sliceTail(codeLines);
|
|
939
957
|
}
|
|
940
958
|
}
|
|
941
959
|
|
|
942
960
|
const closedFenceLines = latestClosedFenceLines.filter((line) => line.trim().length > 0);
|
|
943
961
|
if (closedFenceLines.length > 0) {
|
|
944
|
-
return closedFenceLines
|
|
962
|
+
return sliceTail(closedFenceLines);
|
|
945
963
|
}
|
|
946
964
|
|
|
947
965
|
const tailLines = source
|
|
948
966
|
.split('\n')
|
|
949
967
|
.map((line) => line.replace(/\r$/, ''))
|
|
950
968
|
.filter((line) => line.trim().length > 0);
|
|
951
|
-
if (tailLines.length === 0) return [];
|
|
952
|
-
return tailLines
|
|
969
|
+
if (tailLines.length === 0) return { lines: [], startLine: 1 };
|
|
970
|
+
return sliceTail(tailLines);
|
|
953
971
|
}
|
|
954
972
|
|
|
955
973
|
function collectPreviewStrings(value, out = []) {
|
|
@@ -981,7 +999,6 @@ function collectPreviewStrings(value, out = []) {
|
|
|
981
999
|
function extractPreviewTextFromRawArguments(raw) {
|
|
982
1000
|
const source = String(raw || '');
|
|
983
1001
|
if (!source.trim()) return '';
|
|
984
|
-
|
|
985
1002
|
const contentMatch = source.match(/"(content|new_content|new_text|patch|code|body|script|source|value)"\s*:\s*"([\s\S]*)$/);
|
|
986
1003
|
if (!contentMatch) return '';
|
|
987
1004
|
|
|
@@ -989,7 +1006,7 @@ function extractPreviewTextFromRawArguments(raw) {
|
|
|
989
1006
|
.replace(/\\n/g, '\n')
|
|
990
1007
|
.replace(/\\"/g, '"')
|
|
991
1008
|
.replace(/\\\\/g, '\\')
|
|
992
|
-
.replace(/"
|
|
1009
|
+
.replace(/"\s*[,}\]]*\s*$/g, '')
|
|
993
1010
|
.trim();
|
|
994
1011
|
}
|
|
995
1012
|
|
|
@@ -1000,40 +1017,76 @@ function compactPreviewLine(line, maxChars = 56) {
|
|
|
1000
1017
|
return `${text.slice(0, Math.max(1, maxChars - 3))}...`;
|
|
1001
1018
|
}
|
|
1002
1019
|
|
|
1020
|
+
function extractPreviewLinesFromTool(tool, maxLines = 3) {
|
|
1021
|
+
const previewSource =
|
|
1022
|
+
typeof tool?.arguments === 'string'
|
|
1023
|
+
? (() => {
|
|
1024
|
+
const parsedArguments = safeJsonParse(tool.arguments);
|
|
1025
|
+
if (parsedArguments) {
|
|
1026
|
+
const parsedPreview = collectPreviewStrings(parsedArguments);
|
|
1027
|
+
if (parsedPreview.length > 0) return parsedPreview;
|
|
1028
|
+
}
|
|
1029
|
+
const rawArgumentPreview = extractPreviewTextFromRawArguments(tool.arguments);
|
|
1030
|
+
return rawArgumentPreview ? [rawArgumentPreview] : [];
|
|
1031
|
+
})()
|
|
1032
|
+
: collectPreviewStrings(tool?.arguments || tool?.content || tool?.summary || []);
|
|
1033
|
+
|
|
1034
|
+
if (previewSource.length === 0) return { lines: [], startLine: 1 };
|
|
1035
|
+
const combined = previewSource.join('\n');
|
|
1036
|
+
const previewWindow = getTailPreviewWindow(combined, maxLines);
|
|
1037
|
+
return {
|
|
1038
|
+
lines: previewWindow.lines.map((line) => compactPreviewLine(line)),
|
|
1039
|
+
startLine: previewWindow.startLine
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1003
1043
|
function getLatestToolPreviewLines(msg, maxLines = 3) {
|
|
1004
|
-
const toolCalls = [
|
|
1005
|
-
...(Array.isArray(msg?.pendingToolCalls) ? msg.pendingToolCalls : []),
|
|
1006
|
-
...(Array.isArray(msg?.toolCalls) ? msg.toolCalls : [])
|
|
1007
|
-
];
|
|
1008
1044
|
const codeTools = new Set(['edit', 'write', 'patch', 'generate_diff']);
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1045
|
+
const extractFromCalls = (calls) => {
|
|
1046
|
+
for (let index = calls.length - 1; index >= 0; index -= 1) {
|
|
1047
|
+
const tool = calls[index];
|
|
1048
|
+
const parsed = parseToolDisplayName(tool?.name);
|
|
1049
|
+
if (!codeTools.has(parsed.base)) continue;
|
|
1050
|
+
const previewWindow = extractPreviewLinesFromTool(tool, maxLines);
|
|
1051
|
+
if (previewWindow.lines.length > 0) return previewWindow;
|
|
1052
|
+
}
|
|
1053
|
+
return { lines: [], startLine: 1 };
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
const pendingCodeCalls = (Array.isArray(msg?.pendingToolCalls) ? msg.pendingToolCalls : []).filter((tool) =>
|
|
1057
|
+
codeTools.has(parseToolDisplayName(tool?.name).base)
|
|
1058
|
+
);
|
|
1059
|
+
if (pendingCodeCalls.length > 0) {
|
|
1060
|
+
const latestPendingPreview = extractPreviewLinesFromTool(pendingCodeCalls.at(-1), maxLines);
|
|
1061
|
+
if (latestPendingPreview.lines.length > 0) return latestPendingPreview;
|
|
1062
|
+
return { lines: [], startLine: 1 };
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
const toolCalls = (Array.isArray(msg?.toolCalls) ? msg.toolCalls : []).filter(
|
|
1066
|
+
(tool) => tool?.status === 'running' && codeTools.has(parseToolDisplayName(tool?.name).base)
|
|
1067
|
+
);
|
|
1068
|
+
if (toolCalls.length > 0) {
|
|
1069
|
+
return extractFromCalls(toolCalls);
|
|
1022
1070
|
}
|
|
1023
|
-
|
|
1071
|
+
|
|
1072
|
+
return { lines: [], startLine: 1 };
|
|
1024
1073
|
}
|
|
1025
1074
|
|
|
1026
1075
|
export function getGeneratingCodePlaceholderRows(msg, copy, contentWidth = 72) {
|
|
1027
1076
|
const liveStatus = String(msg?.liveStatus || '').trim();
|
|
1028
1077
|
if (!msg?.loading || (msg?.phase !== 'generating' && msg?.phase !== 'tooling')) return [];
|
|
1029
|
-
if (liveStatus !== String(copy?.runtime?.generatingCode || '').trim()) return [];
|
|
1030
1078
|
|
|
1031
|
-
const
|
|
1032
|
-
if (
|
|
1079
|
+
const previewWindow = getLatestToolPreviewLines(msg, 3);
|
|
1080
|
+
if (previewWindow.lines.length === 0) return [];
|
|
1081
|
+
const hasRunningCodeTool = (Array.isArray(msg?.toolCalls) ? msg.toolCalls : []).some(
|
|
1082
|
+
(tool) => tool?.status === 'running' && new Set(['edit', 'write', 'patch', 'generate_diff']).has(parseToolDisplayName(tool?.name).base)
|
|
1083
|
+
);
|
|
1084
|
+
const isCodeGenerationStatus = liveStatus === String(copy?.runtime?.generatingCode || '').trim();
|
|
1085
|
+
if (!isCodeGenerationStatus && !(msg?.phase === 'tooling' && hasRunningCodeTool)) return [];
|
|
1033
1086
|
|
|
1034
|
-
return
|
|
1087
|
+
return previewWindow.lines.map((line, idx) => ({
|
|
1035
1088
|
kind: 'code-placeholder',
|
|
1036
|
-
lineNo:
|
|
1089
|
+
lineNo: previewWindow.startLine + idx,
|
|
1037
1090
|
text: line,
|
|
1038
1091
|
color: 'gray'
|
|
1039
1092
|
}));
|
|
@@ -1348,7 +1401,7 @@ export function insertRowsAfterLastCodeRow(rows, extraRows) {
|
|
|
1348
1401
|
|
|
1349
1402
|
let insertIndex = -1;
|
|
1350
1403
|
for (let index = source.length - 1; index >= 0; index -= 1) {
|
|
1351
|
-
if (source[index]?.kind === 'code') {
|
|
1404
|
+
if (source[index]?.kind === 'code' || source[index]?.kind === 'code-placeholder') {
|
|
1352
1405
|
insertIndex = index + 1;
|
|
1353
1406
|
break;
|
|
1354
1407
|
}
|
|
@@ -1526,11 +1579,17 @@ function buildMessageRows(msg, showToolDetails, contentWidth = 72, copy) {
|
|
|
1526
1579
|
|
|
1527
1580
|
if (Array.isArray(msg?.segments) && msg.segments.length > 0) {
|
|
1528
1581
|
const totalTools = msg.segments.filter(
|
|
1529
|
-
(segment) =>
|
|
1582
|
+
(segment) =>
|
|
1583
|
+
segment.type === 'tool' ||
|
|
1584
|
+
segment.type === 'skill' ||
|
|
1585
|
+
(segment.type === 'system_tool' && (showToolDetails || !isIndexSystemToolName(segment.name)))
|
|
1530
1586
|
).length;
|
|
1531
1587
|
let toolIndex = 0;
|
|
1532
1588
|
for (const segment of msg.segments) {
|
|
1533
1589
|
if (segment.type === 'tool' || segment.type === 'skill' || segment.type === 'system_tool') {
|
|
1590
|
+
if (segment.type === 'system_tool' && !showToolDetails && isIndexSystemToolName(segment.name)) {
|
|
1591
|
+
continue;
|
|
1592
|
+
}
|
|
1534
1593
|
pushActivityRows(segment, toolIndex, totalTools);
|
|
1535
1594
|
toolIndex += 1;
|
|
1536
1595
|
} else {
|
|
@@ -1816,7 +1875,14 @@ function MessageBubble({ msg, loaderTick, showToolDetails, rowWindow = null, con
|
|
|
1816
1875
|
? h(Text, { color: 'blueBright' }, autoSkillBadge)
|
|
1817
1876
|
: h(Text, { color: theme.chrome }, ' ')
|
|
1818
1877
|
),
|
|
1819
|
-
...rendered
|
|
1878
|
+
...rendered,
|
|
1879
|
+
shouldShowCompletionFooter(msg)
|
|
1880
|
+
? h(
|
|
1881
|
+
Box,
|
|
1882
|
+
{ marginTop: 1, marginLeft: 1, key: `row-completion-${msg.id}` },
|
|
1883
|
+
h(Text, { color: 'gray', dimColor: true }, copy.generic.taskCompleted)
|
|
1884
|
+
)
|
|
1885
|
+
: null
|
|
1820
1886
|
)
|
|
1821
1887
|
);
|
|
1822
1888
|
}
|
|
@@ -2241,6 +2307,7 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2241
2307
|
prev.map((m) => {
|
|
2242
2308
|
if (m.id !== targetId) return m;
|
|
2243
2309
|
const toolCalls = Array.isArray(m.toolCalls) ? [...m.toolCalls] : [];
|
|
2310
|
+
const pendingToolCalls = Array.isArray(m.pendingToolCalls) ? [...m.pendingToolCalls] : [];
|
|
2244
2311
|
const activityType = toolEvent.type || 'tool';
|
|
2245
2312
|
const idx = findActivityUpdateIndex(toolCalls, toolEvent);
|
|
2246
2313
|
const startedAt = toolEvent.status === 'running' ? Date.now() : undefined;
|
|
@@ -2293,7 +2360,16 @@ export function ChatApp({ runtime, sessionId, model, language = 'zh', shellName
|
|
|
2293
2360
|
: {})
|
|
2294
2361
|
};
|
|
2295
2362
|
}
|
|
2296
|
-
|
|
2363
|
+
const shouldClearPending =
|
|
2364
|
+
activityType === 'tool' && ['running', 'done', 'blocked', 'error'].includes(toolEvent.status);
|
|
2365
|
+
const nextPendingToolCalls = shouldClearPending
|
|
2366
|
+
? pendingToolCalls.filter((entry) => {
|
|
2367
|
+
if (!entry) return false;
|
|
2368
|
+
if (toolEvent.id && entry.id) return entry.id !== toolEvent.id;
|
|
2369
|
+
return parseToolDisplayName(entry.name).base !== parseToolDisplayName(toolEvent.name).base;
|
|
2370
|
+
})
|
|
2371
|
+
: pendingToolCalls;
|
|
2372
|
+
return { ...m, toolCalls, segments, pendingToolCalls: nextPendingToolCalls };
|
|
2297
2373
|
})
|
|
2298
2374
|
);
|
|
2299
2375
|
};
|