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 objects
  • ink/*: 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。