05.3 组件、输入与权限界面
关注源码
src/components/messages/*src/components/PromptInput/*src/components/permissions/*src/components/tasks/*src/ink/*src/keybindings/*src/vim/*
组件分型说明了产品语义
components/messages 不是一个通用 message renderer,而是把 transcript 中的语义块拆得非常细:
- user / assistant / system
- thinking / redacted thinking
- tool use / tool result
- hook progress
- API error
- task notification
- attachment
这说明系统把 transcript 当成有结构的事件流,而不是纯文本聊天记录。
输入栈
输入体验由多层共同组成:
PromptInput/*: 文本输入、队列命令、模式字符、候选与提交流程keybindings/*: 快捷键解析与显示vim/*: Vim motions / operators / text objectsink/*: terminal input、focus、selection、viewport
因此输入系统是独立子域,不是单一输入框组件。
权限界面为什么单独成域
components/permissions/* 体量很大,原因是权限在产品里不是一块 modal,而是一组完整交互:
- Bash permission request
- File write / sed edit diff 审批
- plan mode 进入/退出审批
- AskUserQuestion 审批
- sandbox permission request
- worker pending permission
也就是说,权限层在 UI 里拥有与消息层、任务层同等级别的复杂度。
任务与消息是两个并行视图
components/tasks/* 负责:
- 后台任务列表
- 任务详情
- remote session progress
- shell progress
- agent detail dialog
它们与 components/messages/* 并行存在,共同组成控制台体验。
ink/* 的地位
这里的 ink 已经不只是第三方库胶水,而是一套经过深改/扩展的终端 UI 基础设施,覆盖:
- term I/O
- 布局
- 渲染
- focus
- selection
- terminal event
所以在读 UI 代码时,不要把它简单理解成 React DOM 的终端版。
设计上的关键点
1. transcript、input、permissions、tasks 是并列子系统
它们都不是另一个模块的附庸,因此各自都有独立目录与组件群。
2. 权限体验被产品化了
这解释了为什么权限系统能承载复杂 diff、plan mode、ask-user 等专用 UI。
3. 终端 UI 有自己的基础设施层
ink/* 让上层组件能用更接近应用框架的方式写 TUI,而不是直接操作 ANSI。