Skip to content

Feature/tui redesign#139

Open
MarsQiu007 wants to merge 66 commits intoNarcooo:masterfrom
MarsQiu007:feature/tui-redesign
Open

Feature/tui redesign#139
MarsQiu007 wants to merge 66 commits intoNarcooo:masterfrom
MarsQiu007:feature/tui-redesign

Conversation

@MarsQiu007
Copy link
Copy Markdown

@MarsQiu007 MarsQiu007 commented Apr 1, 2026

Summary

  • 1.实现tui长对话工具,支持通过自然语言调整小说设定以及走向
  • 2.支持使用 cli 快捷命令
  • 3.针对每一本书都有自己的专属会话记忆文件
  • 4.对历史文件写入实现 原子操作 + 跨进程目录锁 + 并发会话消息合并,彻底消除多终端并发导致的历史覆盖与文件损坏问题

Type of change

  • Bug fix
  • New feature
  • Refactor (no behavior change)
  • Docs / SKILL.md
  • Test
  • Performance

Motivation (optional)

原有 inkos agent 缺乏交互能力(无 Tab 补全、无状态反馈),且对于长文本的输入十分不友好。本 PR 新增 Tui 交互工具,同时引入三层写保护机制保障历史数据安全。

Changes

File Change
index.tsx 全新 Ink/React TUI:ChatInterface 组件、slash 命令建议面板、Tab 补全、↑↓ 导航、实时执行计时器、执行元数据标签(worker/model/provider)、Esc 二次确认强制退出
session.ts 新增 ChatSession:将用户输入路由至 runAgentLoop 或本地控制命令;onToolStart/Complete/StatusChange/ExecutionMetadataChange 回调;/switch 切书;isHistoryPersistenceConflict 冲突恢复
history.ts 新增 ChatHistoryManager:原子写入(tmp → rename)、基于 mkdir 的跨进程目录锁(PID 存活检测 + 过期锁清理)、mergeHistories 并发消息合并、isValidBookId 防路径遍历(支持 CJK)
commands.ts 新增 SLASH_COMMANDS 定义、parseSlashCommand(含 --guidance/--mode 选项解析)、validateCommandArgsgetAutocompleteInput
types.ts 新增 ChatMessageChatHistoryChatHistoryMetadata(含 revisionclearedAttotalTokens)、ChatHistoryConfigCommandResultChatUICallbacksExecutionMetadataSlashCommand 等全套类型
errors.ts 新增 ERROR_MESSAGES 映射与 parseError(),将底层异常转换为中文友好提示 + 操作建议
README.md 新增 chat 模块架构文档与 Tab 补全使用说明
chat-commands.test.ts slash 命令解析测试:/write/audit/revise --mode/switch、非法命令等
chat-session.test.ts ChatSession 集成测试:非法命令记录历史、/exit 本地处理、/switch 切书、runAgentLoop 调用路径
chat-history.test.ts ChatHistoryManager 单元测试:原子写入、跨进程锁、并发合并、pruning、远端 clear 冲突、畸形 JSON、CJK book ID

Usage (optional)

# 启动 TUI 聊天界面
inkos chat my-book

# 在界面内使用 slash 命令
> /w<Tab>          # Tab 补全为 /write
> /revise 5 --mode polish
> /switch other-book
> /status
> Esc              # 退出(执行中按两次强制退出)

Test plan

  • pnpm typecheck passes
  • pnpm test passes (all existing + new tests)
  • Manual verification: 同时开两个终端 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 新增 revisionnumber)字段,旧文件读取时会将其视为 undefined / 0,向后兼容

完整基于 feature/tui-redesign 分支相对 master 的功能增量填写,已覆盖 TUI 重写、session 层、history 并发机制、commands 体系、类型系统和测试。

MarsQiu007 and others added 30 commits March 31, 2026 10:07
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>
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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

MarsQiu007 and others added 2 commits April 2, 2026 09:51
根本原因分析:
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>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants