Skip to content

Latest commit

 

History

History
161 lines (113 loc) · 4.94 KB

File metadata and controls

161 lines (113 loc) · 4.94 KB

06. UI、状态与 REPL

这篇讲什么

这一章解释 Claude Code 在当前快照中的终端交互层:UI 是怎么组织的,全局状态放在哪里,REPL 为什么会显得非常重。

先给结论

Claude Code 的终端界面不是简单的 readline 包装,而是一套基于 React + Ink 的状态驱动应用。REPL 是主交互屏,AppState 是核心共享状态,AppStateProvider 负责把状态、设置变更和上下文能力注入整棵组件树。

源码依据

Mermaid 图:UI 状态关系图

flowchart TD
    A[App] --> B[AppStateProvider]
    A --> C[StatsProvider]
    A --> D[FpsMetricsProvider]
    B --> E[REPL]
    E --> F[PromptInput]
    E --> G[Messages]
    E --> H[Notifications / Dialogs]
    E --> I[Tasks / Teammates]
    B --> J[mcp state]
    B --> K[plugins state]
    B --> L[bridge / remote state]
    B --> M[toolPermissionContext]
Loading

顶层 UI 包装做了什么

src/components/App.tsx 很简洁,但暴露了整个 UI 的基本结构:

  • FpsMetricsProvider
  • StatsProvider
  • AppStateProvider

这意味着终端 UI 至少有三类共享能力:

  • 性能/FPS 指标
  • 统计信息
  • 统一应用状态

AppStateProvider 的职责

src/state/AppState.tsx 进一步说明了状态层的组织方式:

  • 通过 createStore(...) 创建状态存储。
  • 在挂载时检查 bypassPermissions 是否需要被强制禁用。
  • 通过 useSettingsChange(...) 响应设置变更。
  • 额外包裹 MailboxProvider 和可能存在的 VoiceProvider

可以把它看成“UI 与非 UI 系统之间的边界层”。它既服务 React 组件,也向非 React 代码暴露 getState/setState

AppState 里有什么

src/state/AppStateStore.ts 显示,AppState 很大,但结构是有规律的。它至少包含以下几组核心状态:

1. 会话与显示状态

  • mainLoopModel
  • statusLineText
  • expandedView
  • viewSelectionMode
  • footerSelection
  • isBriefOnly

2. 权限与交互状态

  • toolPermissionContext
  • thinkingEnabled
  • promptSuggestionEnabled
  • notifications
  • elicitation

3. 远程与 Bridge 状态

  • remoteSessionUrl
  • remoteConnectionStatus
  • replBridgeEnabled
  • replBridgeConnected
  • replBridgeSessionActive
  • replBridgeError

4. 扩展与外部能力状态

  • mcp.clients
  • mcp.tools
  • mcp.commands
  • mcp.resources
  • plugins.enabled
  • plugins.disabled
  • plugins.errors

5. 任务与多代理状态

  • tasks
  • agentNameRegistry
  • foregroundedTaskId
  • viewingAgentTaskId
  • todos

这也解释了为什么 REPL 主屏会很重:它几乎是这些状态的汇合点。

为什么 REPL.tsx 这么大

src/screens/REPL.tsx 的 import 面非常宽,说明 REPL 不只是“文本输入框”。

从文件顶部可直接看到它要同时处理:

  • 输入与键盘事件
  • 搜索、高亮、消息列表
  • 提示框、通知、弹窗
  • hook 结果、MCP elicitation、权限请求
  • IDE 集成、remote session、SSH session
  • 插件、skills、任务、后台会话
  • 消息流、token 预算、成本汇总
  • speculative suggestion、prompt suggestion
  • worktree、restore、resume、compact

换句话说,REPL 是 Claude Code 的主控制台。

local-jsx 命令和 UI 的关系

命令系统中大量命令是 local-jsx 类型,例如:

  • /help
  • /config
  • /doctor
  • /plugin
  • /tasks

这些命令实际上是在 REPL 内部打开一个 React 视图或对话框,而不是执行一个无界面的 shell 动作。

REPL 与 QueryEngine 的关系

这两个层次不要混淆:

  • REPL.tsx 负责交互编排、UI、输入队列、消息展示、状态协同。
  • QueryEngine.ts 负责具体的一轮对话或任务提交过程中,如何组织上下文、调用模型、处理工具和累计会话状态。

一个偏“终端应用壳”,一个偏“执行引擎”。

阅读 UI 层的建议

研究 UI 时,不建议直接硬啃 REPL.tsx 全文。更高效的路径是:

  1. 先看 src/components/App.tsx
  2. 再看 src/state/AppStateStore.ts 理解状态面。
  3. 再回到 src/screens/REPL.tsx 搜你关心的主题,例如 permissionsremoteplugintasksquery

这一章的工作结论

Claude Code 的终端 UI 是一套状态很重、模块耦合也很深的 React + Ink 应用。很多看似“命令行功能”的能力,其实都是通过 REPL 主屏和共享状态系统协调出来的。