xiaozhou-chat 1.0.28 → 1.0.30
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/bin/cli.js +56 -2
- package/lib/history.js +3 -1
- package/lib/tools.js +11 -2
- package/package.json +1 -1
package/bin/cli.js
CHANGED
|
@@ -173,7 +173,7 @@ const commands = [
|
|
|
173
173
|
"/system", "/scan", "/当前项目结构", "/load", "/save",
|
|
174
174
|
"/mcp", "/profile", "/切换模型", "/paste", "/clear",
|
|
175
175
|
"/history", "/init", "/初始化配置", "/commit", "/token",
|
|
176
|
-
"/compress"
|
|
176
|
+
"/compress", "/tools"
|
|
177
177
|
];
|
|
178
178
|
|
|
179
179
|
function completer(line) {
|
|
@@ -293,6 +293,12 @@ let inputMode = "chat";
|
|
|
293
293
|
let pasteBuffer = [];
|
|
294
294
|
|
|
295
295
|
rl.on("line", async (line) => {
|
|
296
|
+
// 防止并发输入 (解决光标跳动问题)
|
|
297
|
+
if (isProcessing && inputMode !== "paste") {
|
|
298
|
+
console.log("⚠️ AI 正在思考中,请稍候...");
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
296
302
|
// 粘贴模式处理
|
|
297
303
|
if (inputMode === "paste") {
|
|
298
304
|
if (line.trim() === "---") {
|
|
@@ -437,13 +443,16 @@ rl.on("line", async (line) => {
|
|
|
437
443
|
const toCompress = messages.slice(0, -2);
|
|
438
444
|
const recent = messages.slice(-2);
|
|
439
445
|
|
|
446
|
+
// 优化: 将 JSON 转换为更紧凑的文本格式以节省 Token
|
|
447
|
+
const conversationText = toCompress.map(m => `[${m.role.toUpperCase()}]: ${m.content}`).join("\n\n");
|
|
448
|
+
|
|
440
449
|
const summaryPrompt = `
|
|
441
450
|
请总结以下对话的主要内容,提取关键信息、代码片段和决策。
|
|
442
451
|
摘要应简洁明了,以便作为后续对话的上下文。
|
|
443
452
|
保留所有重要的技术细节。
|
|
444
453
|
|
|
445
454
|
对话内容:
|
|
446
|
-
${
|
|
455
|
+
${conversationText}
|
|
447
456
|
`;
|
|
448
457
|
try {
|
|
449
458
|
const summary = await generateCompletion(activeConfig, [{role: "user", content: summaryPrompt}]);
|
|
@@ -513,6 +522,28 @@ ${diff.slice(0, 8000)}
|
|
|
513
522
|
}
|
|
514
523
|
return rl.prompt();
|
|
515
524
|
}
|
|
525
|
+
|
|
526
|
+
if (input.startsWith("/system")) {
|
|
527
|
+
const prompt = input.slice(7).trim();
|
|
528
|
+
if (!prompt) {
|
|
529
|
+
console.log("当前系统提示词:", activeConfig.systemPrompt || "(未设置)");
|
|
530
|
+
console.log("用法: /system <prompt>");
|
|
531
|
+
return rl.prompt();
|
|
532
|
+
}
|
|
533
|
+
updateConfig("systemPrompt", prompt);
|
|
534
|
+
if (config.currentProfile) {
|
|
535
|
+
setProfileValue(config.currentProfile, "systemPrompt", prompt);
|
|
536
|
+
}
|
|
537
|
+
config = loadConfig();
|
|
538
|
+
activeConfig = getActiveConfig(config);
|
|
539
|
+
console.log("✅ 系统提示词已更新");
|
|
540
|
+
return rl.prompt();
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (input === "/init" || input === "/初始化配置") {
|
|
544
|
+
initProjectConfigFile();
|
|
545
|
+
return rl.prompt();
|
|
546
|
+
}
|
|
516
547
|
|
|
517
548
|
if (input.startsWith("/profile") || input.startsWith("/切换模型")) {
|
|
518
549
|
// ... (Similar logic to before, simplified)
|
|
@@ -540,6 +571,29 @@ ${diff.slice(0, 8000)}
|
|
|
540
571
|
return rl.prompt();
|
|
541
572
|
}
|
|
542
573
|
|
|
574
|
+
if (input === "/tools") {
|
|
575
|
+
console.log("\n🛠️ 可用工具列表:");
|
|
576
|
+
console.log("\n[Built-in]");
|
|
577
|
+
builtInTools.forEach(t => {
|
|
578
|
+
console.log(` - ${t.function.name}: ${t.function.description.slice(0, 40)}...`);
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
if (mcpClients.size > 0) {
|
|
582
|
+
console.log("\n[MCP Servers]");
|
|
583
|
+
for (const [name, client] of mcpClients) {
|
|
584
|
+
console.log(` Sources: ${name}`);
|
|
585
|
+
if (client.tools && client.tools.length > 0) {
|
|
586
|
+
client.tools.forEach(t => {
|
|
587
|
+
console.log(` - ${t.name}: ${t.description ? t.description.slice(0, 40) + "..." : "(No description)"}`);
|
|
588
|
+
});
|
|
589
|
+
} else {
|
|
590
|
+
console.log(" (No tools available)");
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return rl.prompt();
|
|
595
|
+
}
|
|
596
|
+
|
|
543
597
|
// Default: Chat
|
|
544
598
|
isProcessing = true;
|
|
545
599
|
try {
|
package/lib/history.js
CHANGED
|
@@ -61,8 +61,10 @@ export function exportHistory(messages) {
|
|
|
61
61
|
}).join("\n");
|
|
62
62
|
|
|
63
63
|
const dir = canWriteProjectDir() ? projectRoot : os.homedir();
|
|
64
|
-
const
|
|
64
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
65
|
+
const file = path.join(dir, `newapi-chat-history-${timestamp}.md`);
|
|
65
66
|
|
|
66
67
|
fs.writeFileSync(file, md, "utf-8");
|
|
68
|
+
console.log(`✅ 历史记录已导出至: ${file}`);
|
|
67
69
|
return file;
|
|
68
70
|
}
|
package/lib/tools.js
CHANGED
|
@@ -8,7 +8,7 @@ export function scanDir(dir, ignoreList = [], prefix = "", depth = 0) {
|
|
|
8
8
|
if (depth > 10) return ""; // Recursion limit
|
|
9
9
|
|
|
10
10
|
// 默认忽略列表
|
|
11
|
-
const defaultIgnore = ["node_modules", ".git", "dist", "coverage", ".DS_Store", ".env", ".next", "build"];
|
|
11
|
+
const defaultIgnore = ["node_modules", ".git", "dist", "coverage", ".DS_Store", ".env", ".next", "build", "*.log", "*.lock"];
|
|
12
12
|
const ignore = [...defaultIgnore, ...ignoreList];
|
|
13
13
|
|
|
14
14
|
let output = "";
|
|
@@ -23,7 +23,16 @@ export function scanDir(dir, ignoreList = [], prefix = "", depth = 0) {
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
for (const file of files) {
|
|
26
|
-
|
|
26
|
+
// Check ignore (support simple globs)
|
|
27
|
+
const shouldIgnore = ignore.some(pattern => {
|
|
28
|
+
if (pattern === file.name) return true;
|
|
29
|
+
if (pattern.startsWith("*") && file.name.endsWith(pattern.slice(1))) return true;
|
|
30
|
+
if (pattern.endsWith("*") && file.name.startsWith(pattern.slice(0, -1))) return true;
|
|
31
|
+
return false;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (shouldIgnore) continue;
|
|
35
|
+
|
|
27
36
|
if (file.isDirectory()) {
|
|
28
37
|
output += `${prefix}- ${file.name}/\n`;
|
|
29
38
|
output += scanDir(path.join(dir, file.name), ignoreList, `${prefix} `, depth + 1);
|