From 9973e8ec063c9a3918ad2334b6cf49b5cec32c1c Mon Sep 17 00:00:00 2001 From: kurihada Date: Wed, 10 Dec 2025 16:35:04 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A4=9A=E8=BD=AE=E5=AF=B9?= =?UTF-8?q?=E8=AF=9Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ui/terminal.ts | 113 +++++++++++++++++++++++++++------------------ 1 file changed, 68 insertions(+), 45 deletions(-) diff --git a/src/ui/terminal.ts b/src/ui/terminal.ts index 706f174..1e90aa5 100644 --- a/src/ui/terminal.ts +++ b/src/ui/terminal.ts @@ -1,18 +1,23 @@ import * as readline from 'readline'; import chalk from 'chalk'; -import ora from 'ora'; import type { Agent } from '../core/agent.js'; export class TerminalUI { private agent: Agent; private rl: readline.Interface; - private spinner = ora(); + private isClosed = false; constructor(agent: Agent) { this.agent = agent; this.rl = readline.createInterface({ input: process.stdin, output: process.stdout, + terminal: true, + }); + + // 监听关闭事件 + this.rl.on('close', () => { + this.isClosed = true; }); } @@ -20,7 +25,7 @@ export class TerminalUI { private showWelcome(): void { console.log(chalk.cyan('\n╔════════════════════════════════════════╗')); console.log(chalk.cyan('║') + chalk.bold.white(' 🤖 AI Terminal Assistant ') + chalk.cyan('║')); - console.log(chalk.cyan('║') + chalk.gray(' Powered by Claude ') + chalk.cyan('║')); + console.log(chalk.cyan('║') + chalk.gray(' Powered by DeepSeek / Claude ') + chalk.cyan('║')); console.log(chalk.cyan('╚════════════════════════════════════════╝\n')); console.log(chalk.gray('输入你的问题,或使用以下命令:')); console.log(chalk.yellow(' /help') + chalk.gray(' - 显示帮助')); @@ -52,6 +57,7 @@ export class TerminalUI { case '/exit': case '/quit': console.log(chalk.cyan('\n👋 再见!\n')); + this.close(); process.exit(0); default: @@ -61,9 +67,14 @@ export class TerminalUI { // 提问并获取用户输入 private prompt(): Promise { - return new Promise((resolve) => { + return new Promise((resolve, reject) => { + if (this.isClosed) { + reject(new Error('readline closed')); + return; + } + this.rl.question(chalk.green('You > '), (answer) => { - resolve(answer); + resolve(answer ?? ''); }); }); } @@ -72,58 +83,70 @@ export class TerminalUI { async start(): Promise { this.showWelcome(); - while (true) { - const input = await this.prompt(); + while (!this.isClosed) { + try { + const input = await this.prompt(); - // 跳过空输入 - if (!input.trim()) { - continue; - } - - // 处理命令 - if (input.startsWith('/')) { - if (this.handleCommand(input)) { + // 跳过空输入 + if (!input.trim()) { continue; } - } - // 发送给 AI - this.spinner.start(chalk.gray('思考中...')); - - try { - let isFirstChunk = true; - - await this.agent.chat(input, (text) => { - if (isFirstChunk) { - this.spinner.stop(); - process.stdout.write(chalk.blue('AI > ')); - isFirstChunk = false; + // 处理命令 + if (input.startsWith('/')) { + if (this.handleCommand(input)) { + continue; } + } - // 处理工具调用的输出 - if (text.startsWith('\n[调用工具:')) { - process.stdout.write(chalk.yellow(text)); - } else if (text.startsWith('[结果:') || text.startsWith('[错误:')) { - process.stdout.write(chalk.gray(text)); - } else { - process.stdout.write(text); - } - }); + // 发送给 AI + process.stdout.write(chalk.gray('思考中...')); - console.log('\n'); - } catch (error) { - this.spinner.stop(); - console.log( - chalk.red( - `\n❌ 错误: ${error instanceof Error ? error.message : String(error)}\n` - ) - ); + try { + let isFirstChunk = true; + + await this.agent.chat(input, (text) => { + if (isFirstChunk) { + // 清除 "思考中..." 并显示 AI 前缀 + process.stdout.write('\r' + ' '.repeat(20) + '\r'); + process.stdout.write(chalk.blue('AI > ')); + isFirstChunk = false; + } + + // 处理工具调用的输出 + if (text.startsWith('\n[调用工具:')) { + process.stdout.write(chalk.yellow(text)); + } else if (text.startsWith('[结果:') || text.startsWith('[错误:')) { + process.stdout.write(chalk.gray(text)); + } else { + process.stdout.write(text); + } + }); + + console.log('\n'); + } catch (error) { + // 清除 "思考中..." + process.stdout.write('\r' + ' '.repeat(20) + '\r'); + console.log( + chalk.red( + `❌ 错误: ${error instanceof Error ? error.message : String(error)}\n` + ) + ); + } + } catch { + // readline 关闭,退出循环 + break; } } + + console.log(chalk.cyan('\n👋 再见!\n')); } // 关闭 close(): void { - this.rl.close(); + if (!this.isClosed) { + this.isClosed = true; + this.rl.close(); + } } }