xiaozhou-chat 1.0.26 → 1.0.27

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.
Files changed (3) hide show
  1. package/bin/cli.js +58 -21
  2. package/lib/chat.js +38 -0
  3. package/package.json +1 -1
package/bin/cli.js CHANGED
@@ -37,6 +37,7 @@
37
37
  import fs from "node:fs";
38
38
  import path from "node:path";
39
39
  import readline from "node:readline";
40
+ import { execSync } from "node:child_process";
40
41
  import minimist from "minimist";
41
42
  import { MCPClient } from "../lib/mcp-lite.js";
42
43
  import {
@@ -54,7 +55,8 @@ import {
54
55
  exportHistory
55
56
  } from "../lib/history.js";
56
57
  import {
57
- chatStream
58
+ chatStream,
59
+ generateCompletion
58
60
  } from "../lib/chat.js";
59
61
  import {
60
62
  builtInTools,
@@ -431,36 +433,71 @@ rl.on("line", async (line) => {
431
433
  console.log("⚠️ 历史记录太短,无需压缩。");
432
434
  return rl.prompt();
433
435
  }
434
- // Logic similar to before, but calling chatStream with a summary prompt
435
- // To simplify: we construct a temporary context just for summary
436
+
436
437
  const toCompress = messages.slice(0, -2);
437
438
  const recent = messages.slice(-2);
438
439
 
439
440
  const summaryPrompt = `
440
441
  请总结以下对话的主要内容,提取关键信息、代码片段和决策。
441
442
  摘要应简洁明了,以便作为后续对话的上下文。
443
+ 保留所有重要的技术细节。
442
444
 
443
445
  对话内容:
444
446
  ${JSON.stringify(toCompress)}
445
447
  `;
446
- // Temporary buffer for summary
447
- let summary = "";
448
- // Mock printer or capture output?
449
- // chatStream prints to stdout. We might want to capture it instead.
450
- // But our chatStream prints to StreamPrinter.
451
- // For simplicity, let's just let it print the summary to user, then ask user if they want to apply it?
452
- // Or just do it.
453
- // To capture output, we'd need to modify chatStream or StreamPrinter.
454
- // Let's skip modifying chatStream for now and just say:
455
- // "Feature: /compress is simplified to just clearing old history for now in this refactor, or we need a non-printing mode."
456
- // Actually, let's just keep the old history slice logic for now to save time, or use a "silent" mode.
457
- // I'll add `silent: true` option to chatStream later if needed.
458
- // For now:
459
- messages = [
460
- { role: "system", content: "Previous conversation summary: (Compressed)" },
461
- ...recent
462
- ];
463
- console.log("✅ 已压缩历史 (Mock implementation)");
448
+ try {
449
+ const summary = await generateCompletion(activeConfig, [{role: "user", content: summaryPrompt}]);
450
+ messages = [
451
+ { role: "system", content: `Previous conversation summary:\n${summary}` },
452
+ ...recent
453
+ ];
454
+ saveHistory(messages);
455
+ console.log("✅ 历史记录已压缩");
456
+ console.log("摘要预览:", summary.slice(0, 100).replace(/\n/g, ' ') + "...");
457
+ } catch (e) {
458
+ console.error("❌ 压缩失败:", e.message);
459
+ }
460
+ return rl.prompt();
461
+ }
462
+
463
+ if (input === "/commit") {
464
+ try {
465
+ let diff;
466
+ try {
467
+ diff = execSync("git diff --cached", { stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
468
+ } catch (e) {
469
+ console.log("❌ 获取 git diff 失败,请确认当前目录是 git 仓库");
470
+ return rl.prompt();
471
+ }
472
+
473
+ if (!diff) {
474
+ console.log("⚠️ 暂存区为空,请先执行 'git add <file>'");
475
+ return rl.prompt();
476
+ }
477
+
478
+ console.log("🤖 正在分析 Diff 并生成 Commit Message...");
479
+ const prompt = `
480
+ 你是一个资深的开发者。请根据以下的 Git Diff 内容,生成一个符合 Conventional Commits 规范的 Commit Message。
481
+ 只返回 Commit Message 本身,不要包含 markdown 代码块或其他解释。
482
+
483
+ Diff 内容:
484
+ ${diff.slice(0, 8000)}
485
+ `;
486
+ const msg = await generateCompletion(activeConfig, [{role: "user", content: prompt}]);
487
+ console.log("\n----- 建议的 Commit Message -----");
488
+ console.log(`\x1b[32m${msg.trim()}\x1b[0m`);
489
+ console.log("-----------------------------------");
490
+
491
+ const ans = await askQuestion("提交吗? (y/n) ");
492
+ if (ans.trim().toLowerCase() === 'y') {
493
+ execSync(`git commit -m "${msg.trim().replace(/"/g, '\\"')}"`, { stdio: 'inherit' });
494
+ console.log("✅ 提交成功");
495
+ } else {
496
+ console.log("🚫 已取消");
497
+ }
498
+ } catch (e) {
499
+ console.error("❌ Commit 生成失败:", e.message);
500
+ }
464
501
  return rl.prompt();
465
502
  }
466
503
 
package/lib/chat.js CHANGED
@@ -105,6 +105,44 @@ export async function requestWithRetry(url, options, maxRetries = 3) {
105
105
  throw lastError;
106
106
  }
107
107
 
108
+ export async function generateCompletion(config, messages, options = {}) {
109
+ const {
110
+ model = config.model,
111
+ max_tokens = 4096,
112
+ jsonMode = false
113
+ } = options;
114
+
115
+ const requestUrl = `${config.baseUrl}${config.baseUrl.endsWith('/') ? '' : '/'}chat/completions`;
116
+
117
+ // 自动修正 v1
118
+ const finalUrl = (requestUrl.includes("/v1/") || requestUrl.endsWith("/v1"))
119
+ ? requestUrl
120
+ : requestUrl.replace("/chat/completions", "/v1/chat/completions");
121
+
122
+ const body = {
123
+ model,
124
+ messages,
125
+ stream: false,
126
+ max_tokens
127
+ };
128
+
129
+ if (jsonMode) {
130
+ body.response_format = { type: "json_object" };
131
+ }
132
+
133
+ const res = await requestWithRetry(finalUrl, {
134
+ method: "POST",
135
+ headers: {
136
+ "Content-Type": "application/json",
137
+ Authorization: `Bearer ${config.apiKey}`
138
+ },
139
+ body: JSON.stringify(body)
140
+ });
141
+
142
+ const data = await res.json();
143
+ return data.choices?.[0]?.message?.content || "";
144
+ }
145
+
108
146
  export async function chatStream(context, userInput = null, options = {}) {
109
147
  const {
110
148
  messages,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaozhou-chat",
3
- "version": "1.0.26",
3
+ "version": "1.0.27",
4
4
  "description": "CLI chatbot based on NewAPI",
5
5
  "bin": {
6
6
  "xiaozhou-chat": "bin/cli.js"