import * as readline from 'readline'; import chalk from 'chalk'; import type { Agent } from '../core/agent.js'; export class TerminalUI { private agent: Agent; private rl: readline.Interface; 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; }); } // 显示欢迎信息 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 DeepSeek / Claude ') + chalk.cyan('║')); console.log(chalk.cyan('╚════════════════════════════════════════╝\n')); console.log(chalk.gray('输入你的问题,或使用以下命令:')); console.log(chalk.yellow(' /help') + chalk.gray(' - 显示帮助')); console.log(chalk.yellow(' /clear') + chalk.gray(' - 清空对话历史')); console.log(chalk.yellow(' /exit') + chalk.gray(' - 退出程序')); console.log(''); } // 处理特殊命令 private handleCommand(input: string): boolean { const command = input.toLowerCase().trim(); switch (command) { case '/help': console.log(chalk.cyan('\n📖 帮助信息:')); console.log(chalk.white(' 这是一个 AI 编程助手,可以帮你:')); console.log(chalk.gray(' • 读写文件')); console.log(chalk.gray(' • 执行 bash 命令')); console.log(chalk.gray(' • 搜索代码')); console.log(chalk.gray(' • 回答编程问题')); console.log(''); return true; case '/clear': // clearHistory 现在是异步的 void this.agent.clearHistory(); console.log(chalk.green('✓ 对话历史已清空\n')); return true; case '/exit': case '/quit': console.log(chalk.cyan('\n👋 再见!\n')); this.close(); process.exit(0); default: return false; } } // 提问并获取用户输入 private prompt(): Promise { return new Promise((resolve, reject) => { if (this.isClosed) { reject(new Error('readline closed')); return; } this.rl.question(chalk.green('You > '), (answer) => { resolve(answer ?? ''); }); }); } // 主循环 async start(): Promise { this.showWelcome(); while (!this.isClosed) { try { const input = await this.prompt(); // 跳过空输入 if (!input.trim()) { continue; } // 处理命令 if (input.startsWith('/')) { if (this.handleCommand(input)) { continue; } } // 发送给 AI process.stdout.write(chalk.gray('思考中...')); 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 { if (!this.isClosed) { this.isClosed = true; this.rl.close(); } } }