Code Reader
首页
帮助
设计文档
首页
帮助
设计文档
  • Claude Code UI 组件系统与状态管理深度分析

Claude Code UI 组件系统与状态管理深度分析

概述

Claude Code 使用 React + Ink 架构在终端中渲染交互式 UI。这是一个自定义的 Ink 实现(非标准 ink npm 包),位于 src/ink/,包含自定义 reconciler、screen buffer、输入处理和布局引擎。状态管理采用 自定义轻量 Store(类 Zustand),通过 useSyncExternalStore 桥接到 React。


1. UI 组件架构总览

架构分层

┌─────────────────────────────────────────────────┐
│                  Screens (3)                     │
│         REPL · ResumeConversation · Doctor       │
├─────────────────────────────────────────────────┤
│              Components (144)                    │
│  消息展示 · 权限对话框 · 输入系统 · 设计系统 ...  │
├─────────────────────────────────────────────────┤
│               Hooks (85+)                        │
│  useAppState · useTextInput · useCanUseTool ...  │
├─────────────────────────────────────────────────┤
│          State Management (6 files)              │
│  AppState · Store · Selectors · onChangeAppState  │
├─────────────────────────────────────────────────┤
│          Ink Engine (src/ink/, 48 files)         │
│  reconciler · screen · renderer · input · layout │
├─────────────────────────────────────────────────┤
│              React Reconciler                    │
│            Node.js Terminal (TTY)                │
└─────────────────────────────────────────────────┘

Provider 嵌套结构

// src/components/App.tsx
<FpsMetricsProvider>
  <StatsProvider>
    <AppStateProvider initialState={initialState} onChangeAppState={onChangeAppState}>
      <MailboxProvider>
        <VoiceProvider>
          {children}  // REPL, dialogs, etc.
        </VoiceProvider>
      </MailboxProvider>
    </AppStateProvider>
  </StatsProvider>
</FpsMetricsProvider>

2. 组件分类(144 个)

2.1 消息展示系统 (components/messages/, 34 个文件)

负责各类消息的渲染——用户输入、AI 回复、工具使用结果。

文件职责
AssistantTextMessage.tsxAI 助手文本回复
AssistantThinkingMessage.tsx思考过程展示
AssistantToolUseMessage.tsx工具调用展示
UserTextMessage.tsx用户输入消息
UserBashInputMessage.tsx用户 Bash 命令
UserImageMessage.tsx用户粘贴图片
SystemTextMessage.tsx系统消息
CompactBoundaryMessage.tsx上下文压缩边界
GroupedToolUseContent.tsx分组工具调用
UserToolResultMessage/工具结果展示(目录)

2.2 权限对话框系统 (components/permissions/, 30 个文件)

Claude Code 的核心安全机制——每个工具调用都可能需要用户审批。

文件职责
PermissionRequest.tsx权限请求基座组件
PermissionDialog.tsx权限对话框容器
BashPermissionRequest/Bash 命令权限
FileEditPermissionRequest/文件编辑权限
FileWritePermissionRequest/文件写入权限
WebFetchPermissionRequest/Web 抓取权限
ExitPlanModePermissionRequest/退出计划模式权限
SandboxPermissionRequest.tsx沙箱权限
WorkerPendingPermission.tsxWorker 待处理权限

2.3 输入系统 (components/PromptInput/, 21 个文件)

终端输入的完整实现,包含历史搜索、快捷键、补全、语音等。

文件职责
PromptInput.tsx主输入组件 (2339行),最复杂的单文件
PromptInputFooter.tsx输入框下方区域(token 显示等)
PromptInputFooterSuggestions.tsx补全建议展示
HistorySearchInput.tsx历史搜索输入
inputModes.ts输入模式管理
ShimmeredInput.tsx带闪烁效果的输入
VoiceIndicator.tsx语音输入指示器

2.4 设计系统 (components/design-system/, 16 个文件)

可复用的底层 UI 原子组件。

文件职责
ThemeProvider.tsx主题提供者
ThemedText.tsx主题化文本
ThemedBox.tsx主题化容器
Dialog.tsx对话框基座
Divider.tsx分隔线
Pane.tsx面板容器
ProgressBar.tsx进度条
Tabs.tsx标签页
FuzzyPicker.tsx模糊搜索选择器
ListItem.tsx列表项
LoadingState.tsx加载状态
StatusIcon.tsx状态图标

2.5 Agent/Teammate 系统 (components/agents/, 14 个文件)

Agent 定义编辑与管理。

文件职责
AgentsList.tsxAgent 列表
AgentDetail.tsxAgent 详情
AgentEditor.tsxAgent 编辑器
ModelSelector.tsx模型选择器
ToolSelector.tsx工具选择器
ColorPicker.tsx颜色选择器

2.6 任务系统 (components/tasks/, 12 个文件)

后台任务与 Agent 任务的展示。

文件职责
BackgroundTask.tsx后台任务展示
BackgroundTasksDialog.tsx后台任务列表对话框
InProcessTeammateDetailDialog.tsx同事实时详情
RemoteSessionDetailDialog.tsx远程会话详情
ShellProgress.tsxShell 执行进度

2.7 其他关键组件

文件职责
App.tsx顶层 Provider 包装器
Messages.tsx消息列表容器(834行)
Spinner.tsx加载动画(562行)
Onboarding.tsx首次使用引导流程
ExitFlow.tsx退出流程
FullscreenLayout.tsx全屏布局(637行),ScrollBox + bottom pin
VirtualMessageList.tsx虚拟消息列表,长会话性能优化
StatusLine.tsx状态行
Markdown.tsxMarkdown 渲染
SearchBox.tsx搜索框
QuickOpenDialog.tsx快速打开对话框
ThemePicker.tsx主题选择器
ModelPicker.tsx模型选择器

组件分类统计

消息展示 (messages/)          34 个文件
权限对话框 (permissions/)      30 个文件
输入系统 (PromptInput/)        21 个文件
设计系统 (design-system/)      16 个文件
Agent 管理 (agents/)          14 个文件
任务管理 (tasks/)             12 个文件
独立组件                       37 个文件
                             ─────────
总计                         ~144 个文件

3. 状态管理设计

3.1 Store 机制 (src/state/store.ts)

一个极简的 自定义 Store 实现(34 行),类似 Zustand 的核心:

// src/state/store.ts
type Store<T> = {
  getState: () => T
  setState: (updater: (prev: T) => T) => void
  subscribe: (listener: Listener) => () => void
}

function createStore<T>(initialState: T, onChange?: OnChange<T>): Store<T> {
  let state = initialState
  const listeners = new Set<Listener>()
  return {
    getState: () => state,
    setState: (updater) => {
      const prev = state
      const next = updater(prev)
      if (Object.is(next, prev)) return  // 浅比较跳过
      state = next
      onChange?.({ newState: next, oldState: prev })
      for (const listener of listeners) listener()
    },
    subscribe: (listener) => {
      listeners.add(listener)
      return () => listeners.delete(listener)
    },
  }
}

关键设计决策:

  • 不可变更新:setState 接受 (prev) => next 函数
  • 浅比较优化:Object.is 跳过无变化更新
  • 变更回调:onChange 用于副作用同步(如持久化到 CCR)
  • 订阅机制:标准 listener set,与 useSyncExternalStore 兼容

3.2 AppState 定义 (src/state/AppStateStore.ts)

AppState 是一个 巨型不可变对象(~90 个顶级字段),类型定义约 450 行。使用 DeepImmutable<T> 包装确保不可变性。

核心字段结构:

type AppState = DeepImmutable<{
  // === 核心配置 ===
  settings: SettingsJson           // 用户设置
  verbose: boolean                 // 详细模式
  mainLoopModel: ModelSetting      // 当前模型
  mainLoopModelForSession: ModelSetting
  statusLineText: string | undefined
  isBriefOnly: boolean             // Brief 模式

  // === UI 导航状态 ===
  expandedView: 'none' | 'tasks' | 'teammates'
  viewSelectionMode: 'none' | 'selecting-agent' | 'viewing-agent'
  footerSelection: FooterItem | null
  selectedIPAgentIndex: number
  coordinatorTaskIndex: number
  activeOverlays: ReadonlySet<string>

  // === 权限与安全 ===
  toolPermissionContext: ToolPermissionContext

  // === Agent/Team ===
  agent: string | undefined
  kairosEnabled: boolean
  teamContext?: { teamName, teammates, ... }
  standaloneAgentContext?: { name, color }
  agentNameRegistry: Map<string, AgentId>
  foregroundedTaskId?: string
  viewingAgentTaskId?: string

  // === 远程/Bridge ===
  remoteSessionUrl: string | undefined
  remoteConnectionStatus: 'connecting' | 'connected' | 'reconnecting' | 'disconnected'
  replBridgeEnabled: boolean
  replBridgeConnected: boolean
  replBridgeSessionActive: boolean

  // === MCP/插件 ===
  mcp: { clients, tools, commands, resources, pluginReconnectKey }
  plugins: { enabled, disabled, commands, errors, installationStatus }

  // === 通知/对话 ===
  notifications: { current, queue }
  elicitation: { queue }

  // === 推测执行 ===
  speculation: SpeculationState
  speculationSessionTimeSavedMs: number

  // === 提示建议 ===
  promptSuggestion: { text, promptId, shownAt, acceptedAt }
  skillImprovement: { suggestion }
}> & {
  // 非 DeepImmutable 字段(含函数类型)
  tasks: { [taskId: string]: TaskState }
  todos: { [agentId: string]: TodoList }
  inbox: { messages: [...] }
  workerSandboxPermissions: { queue, selectedIndex }
  // ... 更多
}

3.3 React 桥接 (src/state/AppState.tsx)

通过三个核心 Hook 桥接到 React:

// 读取状态切片(自动订阅,Object.is 比较)
export function useAppState<T>(selector: (state: AppState) => T): T {
  const store = useAppStore()
  return useSyncExternalStore(store.subscribe, () => selector(store.getState()))
}

// 获取 setState(不订阅任何状态,引用稳定)
export function useSetAppState() {
  return useAppStore().setState
}

// 获取整个 store(用于非 React 代码)
export function useAppStateStore() {
  return useAppStore()
}

3.4 变更副作用 (src/state/onChangeAppState.ts)

onChangeAppState 是状态变更的唯一副作用入口,在 createStore 的 onChange 回调中触发:

组件调用 setAppState
    ↓
store.setState(updater)
    ↓
Object.is 比较 → 不同则:
    ↓
onChange({ newState, oldState })  ← onChangeAppState
    ↓
    ├─ toolPermissionContext.mode 变更 → notifySessionMetadataChanged + notifyPermissionModeChanged
    ├─ mainLoopModel 变更 → updateSettingsForSource + setMainLoopModelOverride
    ├─ expandedView 变更 → saveGlobalConfig (showExpandedTodos / showSpinnerTree)
    ├─ verbose 变更 → saveGlobalConfig
    └─ settings 变更 → clearApiKeyHelperCache + applyConfigEnvironmentVariables
    ↓
通知所有 listener → useSyncExternalStore 触发重渲染

3.5 Selectors (src/state/selectors.ts)

纯数据提取函数,用于派生计算状态:

// 获取当前查看的 teammate 任务
getViewedTeammateTask(appState) → InProcessTeammateTaskState | undefined

// 确定用户输入应路由到哪个 agent
getActiveAgentForInput(appState) → 
  | { type: 'leader' }
  | { type: 'viewed', task }
  | { type: 'named_agent', task }

4. 关键 Hooks 分析(85+ 个)

4.1 分类总览

状态管理类        useAppState, useSetAppState, useSettings, useAppStateStore
输入处理类        useTextInput, useInputBuffer, useArrowKeyHistory, useVimInput,
                  usePasteHandler, useTypeahead, useCopyOnSelect, useDoublePress
工具权限类        useCanUseTool + toolPermission/ 子目录 (3 个 handler)
会话管理类        useRemoteSession, useSSHSession, useReplBridge, useAssistantHistory
IDE 集成类       useIDEIntegration, useIdeConnectionStatus, useIdeSelection, useIdeAtMentioned
任务/Agent 类     useTasksV2, useTaskListWatcher, useBackgroundTaskNavigation,
                  useSwarmInitialization, useTeammateViewAutoExit
键盘绑定类        useGlobalKeybindings, useCommandKeybindings, useExitOnCtrlCD
性能/渲染类       useAfterFirstRender, useTerminalSize, useVirtualScroll, useDeferredHookMessages
通知/事件类       useNotifications, useInboxPoller, useUpdateNotification, useNotifyAfterTimeout

4.2 useTextInput (src/hooks/useTextInput.ts, 529 行)

最复杂的 hook 之一——终端文本输入的完整实现。管理光标位置、文本缓冲区、kill ring、快捷键映射、粘贴处理等。

type UseTextInputProps = {
  value: string
  onChange: (value: string) => void
  onSubmit?: (value: string) => void
  onExit?: () => void
  focus?: boolean
  multiline?: boolean
  cursorChar: string
  columns: number
  // ... 20+ 个配置项
}

内部实现:

  • Cursor 类:管理光标位置、选择、kill ring(类似 Emacs)
  • mapInput 函数:将按键映射到操作
  • useDoublePress:双击检测(如双击 Escape)
  • 图像粘贴支持:通过 onImagePaste 回调

4.3 useCanUseTool (src/hooks/useCanUseTool.tsx, 204 行)

工具权限检查的核心 hook。协调配置权限、用户交互和分类器审批。

工具调用请求
    ↓
useCanUseTool(tool, input, context, message, toolUseID)
    ↓
hasPermissionsToUseTool() → 配置级预检
    ↓
├─ allow → resolve(allow)
├─ deny → resolve(deny)
└─ ask → 根据会话类型分派:
    ├─ interactive → handleInteractivePermission (显示 UI 等待用户)
    ├─ swarm worker → handleSwarmWorkerPermission
    └─ coordinator → handleCoordinatorPermission

4.4 useSettings (src/hooks/useSettings.ts, 17 行)

最简单的 hook 之一——useAppState 的薄封装:

function useSettings(): ReadonlySettings {
  return useAppState(s => s.settings)
}

4.5 Permission 权限系统 (src/hooks/toolPermission/)

toolPermission/
├── PermissionContext.ts     // 权限上下文工厂 + ResolveOnce 竞态控制
├── permissionLogging.ts     // 权限决策日志
└── handlers/
    ├── interactiveHandler.ts    // 交互式 UI 权限处理
    ├── swarmWorkerHandler.ts    // Swarm Worker 权限处理
    └── coordinatorHandler.ts    // Coordinator 权限处理

createPermissionContext() 创建一个冻结对象,封装了:

  • 竞态控制:createResolveOnce() 确保只 resolve 一次
  • 权限持久化:persistPermissions() 写入配置
  • 分类器检查:tryClassifier() Bash 命令安全分类器
  • Hook 执行:runHooks() 用户自定义权限 hook
  • 队列操作:pushToQueue / removeFromQueue / updateQueueItem

5. Ink 渲染引擎 (src/ink/, 48 个文件)

Claude Code 使用 自定义 Ink 实现,不是标准 npm ink 包。

5.1 核心架构

ink.tsx (1723 行)
├── Ink 类:主控制器
│   ├── LogUpdate: 终端输出管理
│   ├── Terminal: 终端抽象层
│   ├── FocusManager: 焦点管理
│   └── reconciler: React reconciler 桥接
├── reconciler.ts: 自定义 React reconciler
├── renderer.ts: 渲染器
├── render-node-to-output.ts: 节点到输出的转换
├── render-to-screen.ts: 屏幕渲染
├── screen.ts: 屏幕缓冲区
├── output.ts: 输出管理
├── selection.ts: 文本选择系统
└── focus.ts: 焦点管理

5.2 渲染管线

React 组件树
    ↓
React Reconciler (fiber)
    ↓
Ink reconciler → Yoga Layout (Flexbox)
    ↓
render-node-to-output → Output (字符网格)
    ↓
optimize → 差异计算
    ↓
writeDiffToTerminal → ANSI escape codes
    ↓
终端屏幕

5.3 关键特性

  • Alt Screen 模式:全屏应用使用 ENTER_ALT_SCREEN / EXIT_ALT_SCREEN
  • 文本选择:selection.ts 实现终端内文本选择和复制
  • 搜索高亮:searchHighlight.ts 和 searchHighlight 功能
  • 鼠标支持:hit-test.ts 处理点击事件
  • Bidi 支持:bidi.ts 处理双向文本
  • 性能优化:optimizer.ts 做差异渲染,log-update.ts 增量更新

5.4 Ink Hooks (src/ink/hooks/, 12 个)

Hook职责
use-input.ts用户输入处理(键盘事件)
use-stdin.tsstdin 流管理
use-app.ts应用级控制(退出等)
use-terminal-focus.ts终端焦点状态
use-terminal-title.ts终端标题设置
use-terminal-viewport.ts终端视口尺寸
use-animation-frame.ts动画帧回调
use-interval.ts定时器
use-selection.ts文本选择
use-search-highlight.ts搜索高亮
use-declared-cursor.ts光标声明
use-tab-status.tsTab 状态(iTerm2)

6. Screen 系统 (src/screens/, 3 个文件)

6.1 REPL.tsx (5006 行) — 主交互循环

Claude Code 的核心组件——用户与 AI 对话的主界面。

REPL
├── GlobalKeybindingHandlers   // 全局快捷键
├── CommandKeybindingHandlers  // 命令快捷键
├── CancelRequestHandler       // 取消请求处理
├── FullscreenLayout
│   ├── scrollable: Messages (消息列表)
│   ├── bottom: Spinner + PromptInput
│   ├── overlay: PermissionRequest
│   └── modal: 命令面板/对话框
└── VoiceKeybindingHandler     // 语音快捷键

REPL 管理的核心状态:

  • query — 发送 API 请求
  • messages — 消息历史
  • toolUseConfirmQueue — 权限确认队列
  • isWaitingForResponse — 等待 AI 响应
  • 各种 ref 管理暂停、计时、上下文

6.2 ResumeConversation.tsx

会话恢复界面——用户选择继续哪个历史会话。

6.3 Doctor.tsx

诊断界面——检查和修复配置问题。


7. 关键组件深度分析

7.1 Messages.tsx (834 行)

消息列表容器,处理消息归一化、分组、过滤和虚拟滚动。

// 核心数据流
原始 messages[]
    ↓
normalizeMessages()     // 归一化
    ↓
getMessagesAfterCompactBoundary()  // 压缩边界
    ↓
collapseReadSearchGroups()         // 折叠 Read/Search
    ↓
collapseHookSummaries()            // 折叠 Hook 摘要
    ↓
collapseBackgroundBashNotifications()  // 折叠后台 Bash
    ↓
applyGrouping()                    // 工具调用分组
    ↓
filterForBriefTool()              // Brief 模式过滤
    ↓
VirtualMessageList                // 虚拟滚动渲染

关键设计:

  • LogoHeader 被 React.memo 包装,避免消息更新时重绘 logo(性能关键)
  • OffscreenFreeze 冻结不可见区域
  • 使用 InVirtualListContext 和 MessageActionsSelectedContext 两个 Context

7.2 PromptInput.tsx (2339 行)

最复杂的单文件组件——终端输入框的完整实现。

核心职责:

  • 文本输入和光标管理
  • 补全建议显示
  • 输入模式切换(普通/命令/搜索)
  • 粘贴处理(文本和图片)
  • 历史导航
  • 快捷键绑定
  • Token 预算显示
  • 权限模式切换 (Shift+Tab)
  • Agent 选择(footer pill 导航)
  • 悬浮伴侣(Companion Sprite)集成

使用的关键 hooks:

useAppState(s => s.toolPermissionContext)   // 权限上下文
useAppState(s => s.mainLoopModel)           // 当前模型
useAppState(s => s.footerSelection)         // footer 选择
useAppState(s => s.viewingAgentTaskId)      // 查看的 Agent
useAppState(s => s.expandedView)            // 展开视图
useArrowKeyHistory()                        // 历史导航
useTextInput()                              // 文本输入核心
useTypeahead()                              // 前缀补全
useInputBuffer()                            // 输入缓冲
usePromptSuggestion()                       // 建议
useIdeAtMentioned()                         // IDE @提及

7.3 Spinner.tsx (562 行)

加载动画组件,显示 AI 正在处理。

关键设计:

  • SpinnerWithVerb 是入口,根据 isBriefOnly 分支到 BriefSpinner 或 SpinnerWithVerbInner
  • 使用 useAnimationFrame 驱动动画(在 SpinnerAnimationRow 中)
  • useAppState(s => s.expandedView) 决定是否展开任务列表
  • useAppState(s => s.viewingAgentTaskId) 用于 teammate 视图
  • 包含 token 预算进度条和任务树

7.4 FullscreenLayout.tsx (637 行)

全屏布局组件——将屏幕分为滚动区域和固定底部。

┌──────────────────────────────┐
│         scrollable           │ ← Messages (可滚动)
│          (messages)          │
│                              │
├──────────────────────────────┤
│  overlay (可选)              │ ← PermissionRequest 等
├──────────────────────────────┤
│  bottom (固定)               │ ← Spinner + PromptInput
└──────────────────────────────┘

modal (绝对定位,覆盖全部)
bottomFloat (右下角浮动)

使用 ScrollBox(Ink 组件)实现滚动,ScrollChromeContext 提供 sticky prompt 上下文。

7.5 Onboarding.tsx (244 行)

首次使用引导——步骤式向导。

type StepId = 'preflight' | 'theme' | 'oauth' | 'api-key' | 'security' | 'terminal-setup'

// 步骤数组动态构建
const steps: OnboardingStep[] = [
  { id: 'preflight', component: <PreflightStep /> },
  { id: 'theme', component: <ThemePicker /> },
  { id: 'oauth', component: <ConsoleOAuthFlow /> },    // 条件
  { id: 'api-key', component: <ApproveApiKey /> },     // 条件
  { id: 'security', component: <SecurityStep /> },
  { id: 'terminal-setup', component: <TerminalSetup /> },
]

8. Context Provider 系统

除了核心 AppState Store,还有 9 个独立的 React Context:

Context文件职责
AppStoreContextstate/AppState.tsx核心 AppState Store
StatsContextcontext/stats.tsx统计数据存储
FpsMetricsContextcontext/fpsMetrics.tsxFPS 指标
MailboxContextcontext/mailbox.tsx消息邮箱
VoiceContextcontext/voice.tsx语音模式
ModalContextcontext/modalContext.tsx模态对话框
TerminalWriteContextink/useTerminalNotification.ts终端原始写入
TerminalSizeContextink/components/TerminalSizeContext.tsx终端尺寸
ClockContextink/components/ClockContext.tsx时钟/时间
KeybindingContextkeybindings/KeybindingContext.tsx快捷键绑定
ScrollChromeContextcomponents/FullscreenLayout.tsx滚动 Chrome
PromptOverlayContextcontext/promptOverlayContext.tsx提示覆盖层
MCPConnectionContextservices/mcp/MCPConnectionManager.tsxMCP 连接管理
WizardContextcomponents/wizard/WizardProvider.tsx向导流程
TabsContextcomponents/design-system/Tabs.tsx标签页
ThemeContextcomponents/design-system/ThemeProvider.tsx设计主题

9. 数据流模式

9.1 状态更新流程

9.2 工具权限请求流程

9.3 消息渲染流程

9.4 对话框启动流程

showSetupDialog 自动包装 AppStateProvider + KeybindingSetup,确保每个对话框都有完整上下文。


10. 性能优化策略

10.1 React Compiler

所有组件文件开头都有 import { c as _c } from "react/compiler-runtime" ——使用 React Compiler 自动 memoization,减少手动 useMemo / useCallback。

10.2 虚拟滚动

VirtualMessageList 只渲染可见区域的消息,长会话(2800+ 条消息)不会卡顿。

10.3 增量渲染

Ink 的 optimizer.ts 做帧级差异计算,只写变化的字符到终端。

10.4 Memoized 子树

// Messages.tsx 中 LogoHeader 被 memo 包装
const LogoHeader = React.memo(function LogoHeader({ agentDefinitions }) {
  return <OffscreenFreeze>
    <Box flexDirection="column" gap={1}>
      <LogoV2 />
      <React.Suspense fallback={null}>
        <StatusNotices agentDefinitions={agentDefinitions} />
      </React.Suspense>
    </Box>
  </OffscreenFreeze>
})

10.5 条件 Dead Code Elimination

// feature() 是编译时常量,bun:bundle 在构建时消除死代码
const useVoiceIntegration = feature('VOICE_MODE')
  ? require('../hooks/useVoiceIntegration.js').useVoiceIntegration
  : () => ({ stripTrailing: () => 0, ... })

10.6 Stable References

useSetAppState() 返回稳定引用——仅调用此 hook 的组件不会因状态变更而重渲染。


总结

Claude Code 的 UI 架构有几个核心设计原则:

  1. 单一状态源:AppState 是一个巨型不可变对象,所有 UI 状态集中管理
  2. 自定义轻量 Store:34 行实现,无外部依赖,与 useSyncExternalStore 完美配合
  3. 分层 Context:核心状态用 Store,辅助状态用 React Context
  4. 自定义 Ink 引擎:完全控制渲染管线,实现终端内的富交互体验
  5. 防御性权限系统:每个工具调用都经过权限检查,三层处理路径
  6. 死代码消除:feature() 编译时常量,按构建目标裁剪功能
  7. 性能优先:虚拟滚动 + 增量渲染 + React Compiler + memo 策略