@ww_nero/mini-cli 1.0.69 → 1.0.70
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/chat.js +48 -4
- package/src/tools/replace.js +3 -1
- package/src/tools/write.js +15 -1
- package/src/utils/output.js +1 -2
- package/src/utils/renderer.js +28 -18
package/package.json
CHANGED
package/src/chat.js
CHANGED
|
@@ -81,6 +81,40 @@ const appendMiniInstructions = (baseContent, workspaceRoot) => {
|
|
|
81
81
|
return `${baseContent}\n\n${sections.join('\n\n')}`;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
+
const formatWriteOutput = (result) => {
|
|
85
|
+
if (!result || typeof result !== 'object' || !result.success) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const content = result.content || '';
|
|
89
|
+
const lines = content.split('\n');
|
|
90
|
+
if (lines.length <= 100) {
|
|
91
|
+
return content;
|
|
92
|
+
}
|
|
93
|
+
return lines.slice(0, 100).join('\n') + '\n...(更多内容)';
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const formatReplaceOutput = (result) => {
|
|
97
|
+
if (!result || typeof result !== 'object' || !result.success) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const searchContent = result.search || '';
|
|
101
|
+
const replaceContent = result.replace || '';
|
|
102
|
+
|
|
103
|
+
const lines = [];
|
|
104
|
+
|
|
105
|
+
const searchLines = searchContent.split('\n');
|
|
106
|
+
searchLines.forEach((line) => {
|
|
107
|
+
lines.push(chalk.red(`-${line}`));
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const replaceLines = replaceContent.split('\n');
|
|
111
|
+
replaceLines.forEach((line) => {
|
|
112
|
+
lines.push(chalk.green(`+${line}`));
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
return lines.join('\n');
|
|
116
|
+
};
|
|
117
|
+
|
|
84
118
|
const stringifyToolResult = (value) => {
|
|
85
119
|
if (typeof value === 'string') {
|
|
86
120
|
return value;
|
|
@@ -919,7 +953,19 @@ const startChatSession = async ({
|
|
|
919
953
|
const toolContent = resultInfo.content;
|
|
920
954
|
|
|
921
955
|
// Display tool output
|
|
922
|
-
if (functionName === '
|
|
956
|
+
if (functionName === 'write') {
|
|
957
|
+
// For write, display full content in white
|
|
958
|
+
const writeOutput = formatWriteOutput(toolResult);
|
|
959
|
+
if (writeOutput) {
|
|
960
|
+
console.log(writeOutput);
|
|
961
|
+
}
|
|
962
|
+
} else if (functionName === 'replace') {
|
|
963
|
+
// For replace, display diff-style output
|
|
964
|
+
const replaceOutput = formatReplaceOutput(toolResult);
|
|
965
|
+
if (replaceOutput) {
|
|
966
|
+
console.log(replaceOutput);
|
|
967
|
+
}
|
|
968
|
+
} else if (functionName === 'todos') {
|
|
923
969
|
// For todos, display full formatted output without truncation
|
|
924
970
|
if (toolContent) {
|
|
925
971
|
console.log(chalk.gray(` ${toolContent}`));
|
|
@@ -931,11 +977,9 @@ const startChatSession = async ({
|
|
|
931
977
|
console.log(chalk.gray(` ${preview}`));
|
|
932
978
|
}
|
|
933
979
|
|
|
934
|
-
// If truncated, show warning
|
|
980
|
+
// If truncated, show warning
|
|
935
981
|
if (resultInfo.truncated) {
|
|
936
982
|
console.log(chalk.yellow(` ⚠ 输出已截断 (${resultInfo.originalTokenCount} tokens > ${resultInfo.limit} limit)`));
|
|
937
|
-
} else if (resultInfo.tokenCount != null) {
|
|
938
|
-
console.log(chalk.gray(` (${resultInfo.tokenCount} tokens)`));
|
|
939
983
|
}
|
|
940
984
|
}
|
|
941
985
|
|
package/src/tools/replace.js
CHANGED
|
@@ -95,7 +95,9 @@ const replaceInFile = async ({ filePath, search, replace } = {}, context = {}) =
|
|
|
95
95
|
return {
|
|
96
96
|
success: true,
|
|
97
97
|
message: `搜索替换成功: ${filePath}`,
|
|
98
|
-
diffStats
|
|
98
|
+
diffStats,
|
|
99
|
+
search: normalizedSearch,
|
|
100
|
+
replace: normalizedReplace
|
|
99
101
|
};
|
|
100
102
|
} catch (error) {
|
|
101
103
|
return `搜索替换失败 ${filePath}: ${error.message}`;
|
package/src/tools/write.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
const { resolveWorkspacePath, writeTextFile } = require('../utils/helpers');
|
|
2
2
|
|
|
3
|
+
const countLines = (text = '') => {
|
|
4
|
+
if (!text) return 0;
|
|
5
|
+
const normalized = text.replace(/\r/g, '');
|
|
6
|
+
const newlineMatches = normalized.match(/\n/g);
|
|
7
|
+
const newlineCount = Array.isArray(newlineMatches) ? newlineMatches.length : 0;
|
|
8
|
+
const endsWithNewline = normalized.endsWith('\n');
|
|
9
|
+
return endsWithNewline ? newlineCount : newlineCount + 1;
|
|
10
|
+
};
|
|
11
|
+
|
|
3
12
|
const writeFile = async ({ filePath, content } = {}, context = {}) => {
|
|
4
13
|
if (!filePath || typeof filePath !== 'string') {
|
|
5
14
|
return 'filePath 参数不能为空';
|
|
@@ -17,7 +26,12 @@ const writeFile = async ({ filePath, content } = {}, context = {}) => {
|
|
|
17
26
|
|
|
18
27
|
try {
|
|
19
28
|
await writeTextFile(absolutePath, content);
|
|
20
|
-
return
|
|
29
|
+
return {
|
|
30
|
+
success: true,
|
|
31
|
+
message: `写入成功: ${filePath}`,
|
|
32
|
+
content,
|
|
33
|
+
lineCount: countLines(content)
|
|
34
|
+
};
|
|
21
35
|
} catch (error) {
|
|
22
36
|
return `写入失败 ${filePath}: ${error.message}`;
|
|
23
37
|
}
|
package/src/utils/output.js
CHANGED
|
@@ -62,8 +62,7 @@ const printUsageTokens = (usage) => {
|
|
|
62
62
|
if (!formatted) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
|
-
|
|
66
|
-
console.log(colorFn(`已使用tokens: ${formatted}`));
|
|
65
|
+
console.log(chalk.gray(`已使用tokens: ${formatted}`));
|
|
67
66
|
};
|
|
68
67
|
|
|
69
68
|
module.exports = {
|
package/src/utils/renderer.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
|
|
3
|
-
const ORANGE = typeof chalk.hex === 'function'
|
|
4
|
-
? chalk.hex('#FFA500')
|
|
5
|
-
: chalk.keyword('orange');
|
|
6
|
-
|
|
7
3
|
const truncateText = (text, maxLength = 200) => {
|
|
8
4
|
if (!text || typeof text !== 'string') {
|
|
9
5
|
return text;
|
|
@@ -14,28 +10,42 @@ const truncateText = (text, maxLength = 200) => {
|
|
|
14
10
|
return text.substring(0, maxLength) + '...';
|
|
15
11
|
};
|
|
16
12
|
|
|
17
|
-
const
|
|
18
|
-
if (!
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
const normalized = args.content.replace(/\r/g, '');
|
|
22
|
-
if (!normalized) {
|
|
23
|
-
return ORANGE('(0)');
|
|
24
|
-
}
|
|
13
|
+
const countLines = (text = '') => {
|
|
14
|
+
if (!text) return 0;
|
|
15
|
+
const normalized = text.replace(/\r/g, '');
|
|
25
16
|
const newlineMatches = normalized.match(/\n/g);
|
|
26
17
|
const newlineCount = Array.isArray(newlineMatches) ? newlineMatches.length : 0;
|
|
27
18
|
const endsWithNewline = normalized.endsWith('\n');
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
return endsWithNewline ? newlineCount : newlineCount + 1;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const formatWriteHeader = (args = {}) => {
|
|
23
|
+
const filePath = args.filePath || '';
|
|
24
|
+
const lineCount = countLines(args.content);
|
|
25
|
+
return ` (${filePath}, +${lineCount})`;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const formatReplaceHeader = (args = {}) => {
|
|
29
|
+
const filePath = args.filePath || '';
|
|
30
|
+
const searchLines = countLines(args.search);
|
|
31
|
+
const replaceLines = countLines(args.replace);
|
|
32
|
+
return ` (${filePath}, ${chalk.green(`+${replaceLines}`)} ${chalk.red(`-${searchLines}`)})`;
|
|
30
33
|
};
|
|
31
34
|
|
|
32
35
|
const formatHeader = (name, args, options = {}) => {
|
|
33
36
|
const statusTag = options.statusTag || '';
|
|
34
37
|
const extraMeta = Array.isArray(options.extraMeta) ? options.extraMeta : [];
|
|
35
38
|
const labelBase = `${chalk.yellow('🔧')} ${chalk.yellow(name)}`;
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
|
|
40
|
+
let specialHeader = '';
|
|
41
|
+
if (name === 'write') {
|
|
42
|
+
specialHeader = formatWriteHeader(args);
|
|
43
|
+
} else if (name === 'replace') {
|
|
44
|
+
specialHeader = formatReplaceHeader(args);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const labelWithInfo = `${labelBase}${specialHeader}`;
|
|
48
|
+
const label = statusTag ? `${labelWithInfo}${statusTag}` : labelWithInfo;
|
|
39
49
|
const metaParts = [...extraMeta];
|
|
40
50
|
|
|
41
51
|
if (name === 'bash') {
|
|
@@ -43,7 +53,7 @@ const formatHeader = (name, args, options = {}) => {
|
|
|
43
53
|
if (args.workingDirectory && args.workingDirectory !== '.') {
|
|
44
54
|
metaParts.push(`dir=${args.workingDirectory}`);
|
|
45
55
|
}
|
|
46
|
-
} else if (
|
|
56
|
+
} else if (name === 'read') {
|
|
47
57
|
if (args.filePath) metaParts.push(args.filePath);
|
|
48
58
|
} else if (name === 'todos') {
|
|
49
59
|
const count = Array.isArray(args.todos) ? args.todos.length : 0;
|