@ww_nero/mini-cli 1.0.89 → 1.0.91
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 +0 -0
- package/bin/mini.js +0 -0
- package/package.json +1 -1
- package/src/chat.js +25 -46
- package/src/config.js +0 -0
- package/src/index.js +0 -0
- package/src/llm.js +0 -0
- package/src/prompt/tool.js +0 -0
- package/src/request.js +0 -0
- package/src/tools/bash.js +0 -0
- package/src/tools/edit.js +2 -24
- package/src/tools/index.js +0 -0
- package/src/tools/mcp.js +0 -0
- package/src/tools/read.js +0 -0
- package/src/tools/skills.js +0 -0
- package/src/tools/write.js +0 -0
- package/src/utils/cliOptions.js +0 -0
- package/src/utils/commands.js +0 -0
- package/src/utils/git.js +0 -0
- package/src/utils/helpers.js +25 -0
- package/src/utils/history.js +0 -0
- package/src/utils/menu.js +0 -0
- package/src/utils/model.js +0 -0
- package/src/utils/output.js +10 -6
- package/src/utils/renderer.js +3 -12
- package/src/utils/settings.js +0 -0
- package/src/utils/skills.js +0 -0
- package/src/utils/think.js +1 -12
package/README.md
CHANGED
|
File without changes
|
package/bin/mini.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/src/chat.js
CHANGED
|
@@ -151,42 +151,31 @@ const enforceToolOutputLimit = (text, tokenLimit) => {
|
|
|
151
151
|
const content = typeof text === 'string' ? text : stringifyToolResult(text);
|
|
152
152
|
const safeContent = typeof content === 'string' ? content : '';
|
|
153
153
|
try {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
if (tokenCount > tokenLimit) {
|
|
157
|
-
return {
|
|
158
|
-
content: '输出内容太长,请优化工具调用方式。',
|
|
159
|
-
truncated: true,
|
|
160
|
-
originalTokenCount: tokenCount,
|
|
161
|
-
limit: tokenLimit
|
|
162
|
-
};
|
|
154
|
+
if (encode(safeContent).length > tokenLimit) {
|
|
155
|
+
return '输出内容太长,请优化工具调用方式。';
|
|
163
156
|
}
|
|
164
|
-
return
|
|
165
|
-
content: safeContent,
|
|
166
|
-
truncated: false,
|
|
167
|
-
tokenCount
|
|
168
|
-
};
|
|
157
|
+
return safeContent;
|
|
169
158
|
} catch (_) {
|
|
170
159
|
// 忽略分词异常,保持原始输出
|
|
171
|
-
return
|
|
172
|
-
content: safeContent,
|
|
173
|
-
truncated: false,
|
|
174
|
-
tokenCount: null
|
|
175
|
-
};
|
|
160
|
+
return safeContent;
|
|
176
161
|
}
|
|
177
162
|
};
|
|
178
163
|
|
|
179
|
-
const
|
|
180
|
-
if (
|
|
164
|
+
const formatToolResultForDisplay = (text, maxLength = 100) => {
|
|
165
|
+
if (typeof text !== 'string') {
|
|
181
166
|
return '';
|
|
182
167
|
}
|
|
183
|
-
const normalized = text.replace(/\
|
|
184
|
-
if (normalized
|
|
185
|
-
return
|
|
168
|
+
const normalized = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim();
|
|
169
|
+
if (!normalized) {
|
|
170
|
+
return '';
|
|
186
171
|
}
|
|
187
|
-
return normalized.
|
|
172
|
+
return normalized.length > maxLength ? 'Done' : normalized;
|
|
188
173
|
};
|
|
189
174
|
|
|
175
|
+
const indentToolResult = (text = '') => splitDisplayLines(text)
|
|
176
|
+
.map((line) => ` ${line}`)
|
|
177
|
+
.join('\n');
|
|
178
|
+
|
|
190
179
|
const supportsCursorControl = () => Boolean(process.stdout && process.stdout.isTTY);
|
|
191
180
|
|
|
192
181
|
let loadingCursorActive = false;
|
|
@@ -870,7 +859,6 @@ const startChatSession = async ({
|
|
|
870
859
|
};
|
|
871
860
|
|
|
872
861
|
while (true) {
|
|
873
|
-
process.stdout.write('\n');
|
|
874
862
|
showLoadingPrompt();
|
|
875
863
|
const streamState = {
|
|
876
864
|
thinkState: createThinkParserState(),
|
|
@@ -878,13 +866,12 @@ const startChatSession = async ({
|
|
|
878
866
|
reasoningFromThink: ''
|
|
879
867
|
};
|
|
880
868
|
let reasoningFromModel = '';
|
|
881
|
-
let
|
|
869
|
+
let outputStarted = false;
|
|
882
870
|
|
|
883
871
|
const ensureNewline = () => {
|
|
884
|
-
if (!
|
|
872
|
+
if (!outputStarted) {
|
|
885
873
|
clearLoadingPrompt();
|
|
886
|
-
|
|
887
|
-
printedNewline = true;
|
|
874
|
+
outputStarted = true;
|
|
888
875
|
}
|
|
889
876
|
};
|
|
890
877
|
|
|
@@ -962,6 +949,7 @@ const startChatSession = async ({
|
|
|
962
949
|
? parsedArgs
|
|
963
950
|
: { raw: typeof rawArgs === 'string' ? rawArgs : '' };
|
|
964
951
|
|
|
952
|
+
ensureNewline();
|
|
965
953
|
renderToolCall({ functionName, args: displayArgs }, mcpToolNames);
|
|
966
954
|
|
|
967
955
|
let toolResult;
|
|
@@ -981,8 +969,8 @@ const startChatSession = async ({
|
|
|
981
969
|
}
|
|
982
970
|
}
|
|
983
971
|
|
|
984
|
-
const
|
|
985
|
-
const toolContent =
|
|
972
|
+
const rawToolContent = stringifyToolResult(toolResult);
|
|
973
|
+
const toolContent = enforceToolOutputLimit(rawToolContent, toolOutputTokenLimit);
|
|
986
974
|
|
|
987
975
|
// Display tool output
|
|
988
976
|
if (functionName === 'write') {
|
|
@@ -997,24 +985,15 @@ const startChatSession = async ({
|
|
|
997
985
|
if (editOutput) {
|
|
998
986
|
console.log(editOutput);
|
|
999
987
|
}
|
|
1000
|
-
} else if (functionName === 'skills') {
|
|
1001
|
-
const preview = truncateForDisplay(toolContent, 200);
|
|
1002
|
-
if (preview) {
|
|
1003
|
-
console.log(chalk.gray(` ${preview}`));
|
|
1004
|
-
}
|
|
1005
988
|
} else {
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
console.log(chalk.gray(` ${preview}`));
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
// If truncated, show warning
|
|
1013
|
-
if (resultInfo.truncated) {
|
|
1014
|
-
console.log(chalk.yellow(` ⚠ 输出已截断 (${resultInfo.originalTokenCount} tokens > ${resultInfo.limit} limit)`));
|
|
989
|
+
const displayResult = formatToolResultForDisplay(rawToolContent, 100);
|
|
990
|
+
if (displayResult) {
|
|
991
|
+
console.log(chalk.gray(indentToolResult(displayResult)));
|
|
1015
992
|
}
|
|
1016
993
|
}
|
|
1017
994
|
|
|
995
|
+
process.stdout.write('\n');
|
|
996
|
+
|
|
1018
997
|
messages.push({
|
|
1019
998
|
role: 'tool',
|
|
1020
999
|
tool_call_id: toolCall.id,
|
package/src/config.js
CHANGED
|
File without changes
|
package/src/index.js
CHANGED
|
File without changes
|
package/src/llm.js
CHANGED
|
File without changes
|
package/src/prompt/tool.js
CHANGED
|
File without changes
|
package/src/request.js
CHANGED
|
File without changes
|
package/src/tools/bash.js
CHANGED
|
File without changes
|
package/src/tools/edit.js
CHANGED
|
@@ -1,35 +1,13 @@
|
|
|
1
|
-
const { diffLines } = require('diff');
|
|
2
1
|
const {
|
|
3
2
|
resolveWorkspacePath,
|
|
4
3
|
readTextFile,
|
|
5
4
|
writeTextFile,
|
|
6
5
|
normalizeLineBreaks,
|
|
7
6
|
isCodeIdentical,
|
|
8
|
-
processContent
|
|
7
|
+
processContent,
|
|
8
|
+
computeDiffStats
|
|
9
9
|
} = require('../utils/helpers');
|
|
10
10
|
|
|
11
|
-
const countLines = (text = '') => {
|
|
12
|
-
if (!text) return 0;
|
|
13
|
-
const normalized = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
14
|
-
const lines = normalized.split('\n');
|
|
15
|
-
if (lines[lines.length - 1] === '') {
|
|
16
|
-
lines.pop();
|
|
17
|
-
}
|
|
18
|
-
return lines.length;
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const computeDiffStats = (before = '', after = '') => {
|
|
22
|
-
const parts = diffLines(before, after);
|
|
23
|
-
return parts.reduce((acc, part) => {
|
|
24
|
-
if (part.added) {
|
|
25
|
-
acc.added += countLines(part.value);
|
|
26
|
-
} else if (part.removed) {
|
|
27
|
-
acc.removed += countLines(part.value);
|
|
28
|
-
}
|
|
29
|
-
return acc;
|
|
30
|
-
}, { added: 0, removed: 0 });
|
|
31
|
-
};
|
|
32
|
-
|
|
33
11
|
const editFile = async ({ filePath, search, replace } = {}, context = {}) => {
|
|
34
12
|
if (!filePath || typeof filePath !== 'string') {
|
|
35
13
|
return 'filePath 参数不能为空';
|
package/src/tools/index.js
CHANGED
|
File without changes
|
package/src/tools/mcp.js
CHANGED
|
File without changes
|
package/src/tools/read.js
CHANGED
|
File without changes
|
package/src/tools/skills.js
CHANGED
|
File without changes
|
package/src/tools/write.js
CHANGED
|
File without changes
|
package/src/utils/cliOptions.js
CHANGED
|
File without changes
|
package/src/utils/commands.js
CHANGED
|
File without changes
|
package/src/utils/git.js
CHANGED
|
File without changes
|
package/src/utils/helpers.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { diffLines } = require('diff');
|
|
1
2
|
const fsPromises = require('fs/promises');
|
|
2
3
|
const path = require('path');
|
|
3
4
|
|
|
@@ -7,6 +8,28 @@ const normalizeLineBreaks = (text = '') => {
|
|
|
7
8
|
return /^\n*$/.test(normalized) ? '' : normalized;
|
|
8
9
|
};
|
|
9
10
|
|
|
11
|
+
const countLines = (text = '') => {
|
|
12
|
+
if (!text) return 0;
|
|
13
|
+
const normalized = String(text).replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
14
|
+
const lines = normalized.split('\n');
|
|
15
|
+
if (lines[lines.length - 1] === '') {
|
|
16
|
+
lines.pop();
|
|
17
|
+
}
|
|
18
|
+
return lines.length;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const computeDiffStats = (before = '', after = '') => {
|
|
22
|
+
const parts = diffLines(String(before || ''), String(after || ''));
|
|
23
|
+
return parts.reduce((acc, part) => {
|
|
24
|
+
if (part.added) {
|
|
25
|
+
acc.added += countLines(part.value);
|
|
26
|
+
} else if (part.removed) {
|
|
27
|
+
acc.removed += countLines(part.value);
|
|
28
|
+
}
|
|
29
|
+
return acc;
|
|
30
|
+
}, { added: 0, removed: 0 });
|
|
31
|
+
};
|
|
32
|
+
|
|
10
33
|
const resolveWorkspacePath = (workspaceRoot, targetPath = '.', options = {}) => {
|
|
11
34
|
if (!workspaceRoot) {
|
|
12
35
|
throw new Error('未找到工作区目录');
|
|
@@ -83,6 +106,8 @@ const safeJsonParse = (text) => {
|
|
|
83
106
|
};
|
|
84
107
|
|
|
85
108
|
module.exports = {
|
|
109
|
+
countLines,
|
|
110
|
+
computeDiffStats,
|
|
86
111
|
normalizeLineBreaks,
|
|
87
112
|
resolveWorkspacePath,
|
|
88
113
|
readTextFile,
|
package/src/utils/history.js
CHANGED
|
File without changes
|
package/src/utils/menu.js
CHANGED
|
File without changes
|
package/src/utils/model.js
CHANGED
|
File without changes
|
package/src/utils/output.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const { Marked } = require('marked');
|
|
3
3
|
const { markedTerminal } = require('marked-terminal');
|
|
4
|
-
const { splitThinkContent
|
|
4
|
+
const { splitThinkContent } = require('./think');
|
|
5
5
|
|
|
6
6
|
const ANSI_PATTERN = /\u001B\[[0-9;]*m/g;
|
|
7
7
|
|
|
@@ -70,10 +70,14 @@ const mergeReasoningContent = (...segments) => {
|
|
|
70
70
|
return normalized.join('\n');
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
const
|
|
74
|
-
|
|
73
|
+
const printReasoningContent = (text, ensureNewline) => {
|
|
74
|
+
const normalized = typeof text === 'string'
|
|
75
|
+
? text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').trim()
|
|
76
|
+
: '';
|
|
77
|
+
|
|
78
|
+
if (!normalized) return;
|
|
75
79
|
ensureNewline();
|
|
76
|
-
console.log(chalk.gray(
|
|
80
|
+
console.log(chalk.gray(`思考:\n${normalized}`));
|
|
77
81
|
};
|
|
78
82
|
|
|
79
83
|
const printAssistantContent = (text, ensureNewline) => {
|
|
@@ -89,7 +93,7 @@ const printAssistantContent = (text, ensureNewline) => {
|
|
|
89
93
|
};
|
|
90
94
|
|
|
91
95
|
const renderAssistantOutput = (reasoning, content, ensureNewline) => {
|
|
92
|
-
|
|
96
|
+
printReasoningContent(reasoning, ensureNewline);
|
|
93
97
|
printAssistantContent(content, ensureNewline);
|
|
94
98
|
};
|
|
95
99
|
|
|
@@ -126,7 +130,7 @@ const printUsageTokens = (usage) => {
|
|
|
126
130
|
|
|
127
131
|
module.exports = {
|
|
128
132
|
mergeReasoningContent,
|
|
129
|
-
|
|
133
|
+
printReasoningContent,
|
|
130
134
|
printAssistantContent,
|
|
131
135
|
renderAssistantOutput,
|
|
132
136
|
sanitizeContentWithThink,
|
package/src/utils/renderer.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
|
+
const { countLines, computeDiffStats } = require('./helpers');
|
|
2
3
|
|
|
3
4
|
const truncateText = (text, maxLength = 200) => {
|
|
4
5
|
if (!text || typeof text !== 'string') {
|
|
@@ -10,15 +11,6 @@ const truncateText = (text, maxLength = 200) => {
|
|
|
10
11
|
return text.substring(0, maxLength) + '...';
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
const countLines = (text = '') => {
|
|
14
|
-
if (!text) return 0;
|
|
15
|
-
const normalized = text.replace(/\r/g, '');
|
|
16
|
-
const newlineMatches = normalized.match(/\n/g);
|
|
17
|
-
const newlineCount = Array.isArray(newlineMatches) ? newlineMatches.length : 0;
|
|
18
|
-
const endsWithNewline = normalized.endsWith('\n');
|
|
19
|
-
return endsWithNewline ? newlineCount : newlineCount + 1;
|
|
20
|
-
};
|
|
21
|
-
|
|
22
14
|
const formatWriteHeader = (args = {}) => {
|
|
23
15
|
const filePath = args.filePath || '';
|
|
24
16
|
const lineCount = countLines(args.content);
|
|
@@ -27,9 +19,8 @@ const formatWriteHeader = (args = {}) => {
|
|
|
27
19
|
|
|
28
20
|
const formatEditHeader = (args = {}) => {
|
|
29
21
|
const filePath = args.filePath || '';
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
return ` (${filePath}, ${chalk.green(`+${replaceLines}`)} ${chalk.red(`-${searchLines}`)})`;
|
|
22
|
+
const { added, removed } = computeDiffStats(args.search, args.replace);
|
|
23
|
+
return ` (${filePath}, ${chalk.green(`+${added}`)} ${chalk.red(`-${removed}`)})`;
|
|
33
24
|
};
|
|
34
25
|
|
|
35
26
|
const formatHeader = (name, args, options = {}) => {
|
package/src/utils/settings.js
CHANGED
|
File without changes
|
package/src/utils/skills.js
CHANGED
|
File without changes
|
package/src/utils/think.js
CHANGED
|
@@ -194,21 +194,10 @@ const splitThinkContent = (text = '') => {
|
|
|
194
194
|
return { content, reasoning };
|
|
195
195
|
};
|
|
196
196
|
|
|
197
|
-
const summarizeReasoning = (text = '', maxLength = 100) => {
|
|
198
|
-
if (!text) return '';
|
|
199
|
-
const normalized = text.replace(/\s+/g, ' ').trim();
|
|
200
|
-
if (!normalized) return '';
|
|
201
|
-
if (normalized.length > maxLength) {
|
|
202
|
-
return normalized.substring(0, maxLength) + '...';
|
|
203
|
-
}
|
|
204
|
-
return normalized;
|
|
205
|
-
};
|
|
206
|
-
|
|
207
197
|
module.exports = {
|
|
208
198
|
THINK_TAGS,
|
|
209
199
|
createThinkParserState,
|
|
210
200
|
processThinkChunk,
|
|
211
201
|
flushThinkState,
|
|
212
|
-
splitThinkContent
|
|
213
|
-
summarizeReasoning
|
|
202
|
+
splitThinkContent
|
|
214
203
|
};
|