Conversation
Complete rewrite of TUI chat interface using modern @clack/prompts library, replacing problematic blessed implementation. ## Features Implemented **Phase 1: Core Infrastructure** - Add @clack/prompts and @clack/core dependencies - Create modular file structure under packages/cli/src/chat/ - Implement ChatHistoryManager with file persistence and auto-pruning - Define comprehensive type system (ChatMessage, ChatHistory, etc.) - Create slash command parser with full validation **Phase 2: Session Management** - Implement ChatSession class integrating runAgentLoop - Add slash command to natural language conversion - Implement streaming callbacks for real-time feedback - Add error handling with user-friendly messages **Phase 3: Chat Application** - Implement ChatApp main class with intro/outro flow - Create interactive chat loop with clack components - Add special commands (/help, /status, /clear, /exit) - Display recent message history with truncation - Integrate spinner for tool execution progress **Phase 4: Testing & Documentation** - Add comprehensive unit tests for ChatHistoryManager - Add slash command parser tests - All 89 tests passing ## Technical Highlights - ESM-compatible (no blessed CommonJS issues) - Clean separation of concerns (UI, session, history, commands) - Reusable components from existing blessed implementation - Streaming support for real-time agent responses - Error recovery with user-friendly suggestions - Bilingual support (zh/en) ## Files Changed - packages/cli/package.json: Add @Clack dependencies - packages/cli/src/index.ts: Register chat command - packages/cli/src/commands/chat.ts: Command entry point - packages/cli/src/chat/: New chat module (6 files) - packages/cli/src/__tests__/: Test files (2 new) ## Testing ```bash # Run chat tests pnpm test -- chat # Try the interactive chat inkos chat <book-id> ``` Resolves: blessed TUI rendering issues, input focus problems, ESM compatibility Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add comprehensive README for the new chat interface with: - Usage instructions - Feature overview - Architecture diagram - Comparison with old blessed TUI - Testing guide Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Remove the 3-line limit on message display. Now all messages are shown in full without truncation or '... more lines' indicators. Users need to see complete agent responses, especially for long detailed explanations about their books. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Two fixes for chat interface: 1. Remove duplicate display: Only show response during streaming, not again after 'Done'. The full response is already visible via streaming chunks. 2. Improve user experience: - Show 'Receiving response...' when streaming starts - Display ✓/✗ status indicators - Only show error messages after completion This prevents the same content appearing twice (once during streaming, once after completion). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Remove accidentally committed test chat history files. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Improve command discoverability by showing available commands before each input prompt. ## Changes 1. **Command reminder before each input**: - Display quick command list: /write /audit /revise /status /clear /help /exit - Users always know available options 2. **Improved placeholder text**: - Changed from "/help for commands" to "Type naturally or use commands like /write, /audit..." - More actionable and shows examples 3. **Interactive command exploration**: - Typing "/" and pressing Enter shows detailed command suggestions - /help shows full command documentation ## User Experience Before: After: This makes the chat interface more self-documenting and reduces the need to remember or look up commands. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Revert to simpler @clack/prompts input after discovering that: 1. @inquirer/prompts autocomplete doesn't work as expected 2. True Tab-autocomplete requires low-level terminal control 3. Blessed had this feature but we removed it for stability ## Current Implementation - Simple text input with command hints - Type /help to see all commands - Commands are auto-discovered via SLASH_COMMANDS ## Future Enhancement Tab autocomplete would require: - Custom Prompt implementation with readline - Keyboard event handling - Real-time suggestion updates This is documented for future implementation if needed. For now, users can type /help or see commands in the README. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Add honest explanation of why Tab autocomplete is not currently supported and what would be needed to implement it. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Major rewrite using Ink (React-like terminal UI) replacing @clack/prompts. ## Why Ink? - Full keyboard interactivity support (Tab, arrows, etc.) - React-like component architecture - Modern, well-maintained, ESM-native - Rich component ecosystem (text-input, spinner, etc.) ## New Features **Tab Autocomplete** ✅ - Type / and press Tab to see matching commands - Use ↑↓ arrows to navigate suggestions - Tab completes selected command - Real-time filtering as you type **Rich UI Components**: - React-like component system - Spinner for processing status - Colored output with bold/dim styles - Proper keyboard event handling **Better User Experience**: - Command suggestions shown in real-time - Visual feedback for all interactions - Clean, modern terminal output - Proper message formatting ## Technical Changes **Dependencies**: - Added: ink, react, ink-text-input, ink-spinner - Removed: @clack/prompts, @clack/core, @inquirer/prompts - Added: @types/react (dev dependency) **Architecture**: - Components: ChatInterface, MessageDisplay - Hooks: useInput, useApp, useState, useEffect - JSX support enabled in tsconfig **File Structure**: - src/chat/index.tsx (React components) - Reuses: session.ts, history.ts, commands.ts, errors.ts, types.ts ## Breaking Changes - None: ChatSession, history management remain unchanged - CLI interface remains backward compatible ## Future Enhancements Now possible with Ink: - Multi-line input - Rich text rendering - Custom keybindings - Progress bars - Interactive prompts Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Document new features enabled by Ink framework: - Tab autocomplete with detailed usage - Keyboard shortcuts table - Component architecture - Comparison table vs blessed and @clack/prompts - Future enhancements now possible Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
… with Tab autocomplete
Security Fixes: - Fix path traversal vulnerability in book ID handling (history.ts, session.ts) - Validate book IDs before filesystem operations - Add input validation for slash command arguments - Persist user messages immediately to prevent data loss on agent failure Functional Improvements: - Fix /help command to display actual help content - Suppress stderr logging in TUI mode (quiet: true) - Implement quote-aware argument parsing for slash commands - Update test expectations for quote stripping behavior Addresses all critical and high-priority issues from GitHub Copilot PR review.
Optimizations: - Use Commander's built-in parseInt parser for --max-messages - Add validation for NaN and non-positive values - Remove unused @inkjs/ui dependency from package.json - Update README to clarify /exit is a special command (not in Tab autocomplete) - Add documentation for /help and /switch commands in README All tests passing (89/89).
The chat interface now displays full message content without truncation, so updating documentation to reflect current behavior.
Validation Improvements: - Add validation for --lang parameter (must be 'zh' or 'en') - Reject unsupported language values with clear error message Keyboard Handling Fixes: - Make Escape key always active (not just when suggestions shown) - Allow users to exit chat with Esc at any time - Reorganize keyboard handler for better clarity Addresses additional feedback from GitHub Copilot PR review.
Major Improvements: - Add conversation history as context to agent (last 10 messages) - Enables '继续刚才的话题' type conversations - Supports long-running chat sessions as intended - Change jsx to react-jsx to align with repo conventions - Remove unused --lang option (language switching not yet implemented) - Improve /switch error handling with try-catch - Catch exceptions from historyManager.load() - Return user-friendly error messages Addresses all remaining feedback from GitHub Copilot PR review.
Bug Fixes: - Fix /help command not displaying help text (remove early return) - Fix command suggestion navigation mismatch (implement scrolling window) - Fix user message duplication in conversation context - Fix /switch state inconsistency on error (load before updating currentBook) - Add validation for empty command input - Make save() return pruned history for proper --max-messages enforcement - Improve error message formatting in chat command All 89 tests passing.
Users now see '再见!正在退出...' message before the chat interface closes, providing better feedback instead of instant exit.
Users can now see /exit and /quit in the command suggestions when pressing Tab after typing '/', making them discoverable like other slash commands.
Help text is now added to the chat history so users can see it in the message display, instead of just returning it silently.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
问题: - Windows 分支先删除目标文件再重命名不是原子操作 - 如果进程在 rm() 和 rename() 之间崩溃会导致数据丢失 - 无法恢复原有数据 改进方案: - 实现备份-重命名策略(backup-and-rename) - 步骤 1: 将目标文件重命名为备份文件 - 步骤 2: 将临时文件重命名为目标文件 - 步骤 3: 删除备份文件 安全保障: - 如果步骤 1 失败:原文件仍然存在 - 如果步骤 2 失败:尝试回滚,恢复备份文件 - 如果步骤 3 失败:新文件已就位,备份残留可清理 优势: - 最大化数据安全性 - 失败时可恢复 - 明确的非原子性说明(Windows 限制) Unix/Linux/macOS: - 保持原生原子替换 - rename() 直接支持覆盖已存在文件 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 17 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
问题分析: - recordLocalExchange()、/clear、/help 没有错误处理 - 虽然 UI 有外层 try-catch 保护不会崩溃 - 但存在数据不一致、错误信息不友好、部分成功风险 修复内容: 1. recordLocalExchange() - 捕获 appendAssistantMessage 的错误 - 处理持久化冲突时重新加载历史 - 非持久化错误重新抛出保持原有行为 2. /clear 命令 - 使用 try-catch 包装 clear() 和 load() - 调用 handleHistoryPersistenceConflict 处理冲突 - 非持久化错误返回友好的错误消息 3. /help 命令 - 捕获 save() 错误 - 使用 handleHistoryPersistenceConflict 统一处理 - 非持久化错误重新抛出 优势: - 统一的错误处理机制 - 与 agent loop 保持一致 - 避免数据不一致 - 更好的用户体验 - 处理并发会话冲突 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 17 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1. Windows 备份文件冲突问题 - 问题:固定备份文件名可能因上次崩溃残留导致失败 - 修复:使用 UUID 生成唯一备份文件名 - 添加步骤 1:清理可能残留的备份文件 - 防止 EEXIST/EPERM 错误 2. TypeScript 类型错误 - 问题:performance.now() 需要 DOM 类型,但 tsconfig 只有 ES2022 - 修复:使用 Date.now() 替代 performance.now() - 避免 TypeScript 编译错误 - 保持相同的时间测量功能 3. 命令解析空白字符处理 - 问题:只处理空格,忽略 tab 等其他空白字符 - 修复:使用正则 /\s/ 检测所有空白字符 - 与其他部分的 \s+ 用法保持一致 - 更健壮的命令解析 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 17 changed files in this pull request and generated 1 comment.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
问题: - Tab 处理器只检查 matchingCommands.length > 0 - 即使 showCommandSuggestions 为 false 也会触发 - 可能干扰正常的文本输入行为 修复: - 添加 showCommandSuggestions 检查 - 确保只在建议显示时才触发自动补全 - 符合注释中描述的预期行为 优势: - 避免意外触发自动补全 - 保持正常的文本编辑体验 - 逻辑更清晰,与注释一致 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 17 changed files in this pull request and generated 1 comment.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
问题: - beginExecution() 使用 performance.now() 设置 startedAt - getElapsedMs() 使用 Date.now() 计算时间差 - 混用两个时钟 API 导致时间计算错误(非常大的数值) 修复: - 将 beginExecution() 改为使用 Date.now() - 与 getElapsedMs() 保持一致 - 避免混用 performance.now() 和 Date.now() 说明: - performance.now() 和 Date.now() 使用不同的时间基准 - performance.now() 从页面加载开始计时 - Date.now() 返回 Unix 时间戳 - 混用会导致时间差计算错误 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 17 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1. MessageDisplay 时间戳安全解析 - 问题:无效时间戳会抛出 RangeError 导致 TUI 崩溃 - 修复:验证日期对象,失败时回退到原始字符串或占位符 - 防止用户编辑 JSON 或旧格式数据导致的渲染失败 2. formatMessagesForDisplay 时间戳安全解析 - 问题:同上,历史消息格式化时可能崩溃 - 修复:添加日期验证,无效时使用安全的字符串表示 - 确保 JSON 加载不会因单个消息格式问题失败 3. Windows 备份清理注释修正 - 问题:注释说"清理现有备份文件",但 UUID 使路径唯一 - 修复:更正注释说明实际行为(清理旧备份,但只匹配特定模式) - 说明:真正的全局清理需要 glob 匹配所有 .bak 文件 防御性编程: - 所有日期解析都进行验证 - 失败时优雅降级而非崩溃 - 提高系统健壮性 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 17 changed files in this pull request and generated 4 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
根本原因分析: GitHub Copilot的4个问题不是孤立bug,而是同一个架构缺陷的症状: - 代码的文档(注释)描述了设计意图,但实现无法实现这些意图 - 问题1:注释说"清理旧备份",但randomUUID使实现做不到 - 问题2:注释说"best-effort",但lock释放失败会传播到核心操作 - 问题3:类型系统已保证timestamp是string,但代码用as any绕过 - 问题4:错误消息说"must be integer",但parseInt截断小数 系统性修复策略: 1. CLI参数验证(chat.ts) - 问题:Number.parseInt(3.5) → 3(截断小数) - 修复:改用Number()+Number.isInteger()验证 - 优势:错误信息与实际行为一致,用户立即得到反馈 - 测试:新增cli-options.test.ts验证解析逻辑 2. 类型安全(history.ts) - 问题:formatMessagesForDisplay用as any绕过类型 - 修复:移除as any,直接使用msg.timestamp - 优势:恢复类型安全性,避免未来类型变更隐患 - 测试:chat-history.test.ts验证timestamp处理 3. 错误处理分类(history.ts) - 问题:lock释放失败导致save/clear抛异常(即使数据已写入) - 修复:lock释放用try-catch包裹,失败不影响核心操作 - 原理:清理失败≠数据丢失,锁会被stale检测清理 - 测试:chat-history.test.ts验证best-effort语义 4. 备份清理逻辑(history.ts) - 问题:注释说"清理旧备份",但rm(backupPath)删除不存在的新UUID路径 - 修复:实现glob清理(readdir+filter删除所有*.bak文件) - 优势:注释与实现现在一致,真正解决备份累积问题 - 测试:chat-history.test.ts验证清理逻辑 TDD流程验证: - RED阶段:创建21个测试暴露设计缺陷 - GREEN阶段:实施修复,所有测试通过 - Verify GREEN:120个测试全部通过,无回归 设计教训: 代码的每个部分(注释、类型、验证、实现)必须相互一致。 当它们不一致时,问题会以多个症状的形式暴露。 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
测试分层: 1. 自动化测试(chat-tui.test.ts) - 12个测试覆盖UI关键逻辑 - 命令补全逻辑(Tab补全、命令列表) - 输入处理逻辑(斜杠命令识别、命令提取) - 消息显示逻辑(时间戳格式化、token统计) - 状态管理逻辑(命令导航、执行时间) - 边界情况处理(空输入、超长输入、特殊字符) 2. 手动测试模式(test-mode.ts) - 可直接运行的测试脚本:npx tsx src/chat/test-mode.ts - 自动创建测试环境(历史目录、预填充消息) - 提供测试场景清单(7个关键场景) - 支持交互式测试所有TUI功能 测试文档(TUI_TESTING.md): - 自动化测试运行方法和覆盖范围 - 手动测试启动步骤和场景清单 - TUI功能清单(快捷键、命令、UI特性) - 测试最佳实践和常见问题 测试验证: - 新增12个TUI自动化测试全部通过 - 完整测试套件132个测试通过 - 无回归问题 优势: - 分离自动化测试和手动测试 - 文档化测试流程和场景 - 易于维护和扩展 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 21 changed files in this pull request and generated 3 comments.
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
问题1: path操作错误(history.ts) - 错误:join(targetPath, "..")会产生file.json/..这样的无效路径 - 修复:使用dirname()和basename()正确获取父目录和文件名 - 导入:添加dirname, basename到path导入 问题2: 文档错误(TUI_TESTING.md) - 错误:文档说Node ≥18,但项目实际要求≥20 - 修复:更新为正确的Node.js版本要求 问题3: 注释与实现不一致(cli-options.test.ts) - 错误:测试注释说"DESIGN DEFECT"、"parseInt bug" - 实际:代码已修复,使用Number()+isInteger() - 修复:更新注释匹配实际实现 根本反思: - 测试通过≠实现正确 - 需要代码审查捕获实现细节错误 - 注释必须与实现保持一致 验证:所有132个测试继续通过 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Summary
cli快捷命令原子操作+跨进程目录锁+并发会话消息合并,彻底消除多终端并发导致的历史覆盖与文件损坏问题Type of change
Motivation (optional)
原有
inkos agent缺乏交互能力(无 Tab 补全、无状态反馈),且对于长文本的输入十分不友好。本 PR 新增 Tui 交互工具,同时引入三层写保护机制保障历史数据安全。Changes
ChatInterface组件、slash 命令建议面板、Tab 补全、↑↓ 导航、实时执行计时器、执行元数据标签(worker/model/provider)、Esc 二次确认强制退出ChatSession:将用户输入路由至runAgentLoop或本地控制命令;onToolStart/Complete/StatusChange/ExecutionMetadataChange回调;/switch切书;isHistoryPersistenceConflict冲突恢复ChatHistoryManager:原子写入(tmp → rename)、基于mkdir的跨进程目录锁(PID 存活检测 + 过期锁清理)、mergeHistories并发消息合并、isValidBookId防路径遍历(支持 CJK)SLASH_COMMANDS定义、parseSlashCommand(含--guidance/--mode选项解析)、validateCommandArgs、getAutocompleteInputChatMessage、ChatHistory、ChatHistoryMetadata(含revision、clearedAt、totalTokens)、ChatHistoryConfig、CommandResult、ChatUICallbacks、ExecutionMetadata、SlashCommand等全套类型ERROR_MESSAGES映射与parseError(),将底层异常转换为中文友好提示 + 操作建议/write、/audit、/revise --mode、/switch、非法命令等ChatSession集成测试:非法命令记录历史、/exit本地处理、/switch切书、runAgentLoop调用路径ChatHistoryManager单元测试:原子写入、跨进程锁、并发合并、pruning、远端 clear 冲突、畸形 JSON、CJK book IDUsage (optional)
Test plan
pnpm typecheckpassespnpm testpasses (all existing + new tests)inkos chat <book-id>,各发若干消息后退出,确认.inkos/chat_history/<bookId>.json中两端消息均保留且文件为合法 JSON;验证 Tab 补全与 ↑↓ 导航正常工作Breaking changes (optional)
inkos chat现在依赖 Ink(终端需支持 ANSI escape codes);纯管道/无 TTY 环境行为未定义ChatHistoryManager.save()返回值由Promise<void>变为Promise<ChatHistory>,调用方需使用返回值获取最新状态metadata新增revision(number)字段,旧文件读取时会将其视为undefined/0,向后兼容完整基于
feature/tui-redesign分支相对master的功能增量填写,已覆盖 TUI 重写、session 层、history 并发机制、commands 体系、类型系统和测试。