s16
REPL Screen
Terminal UI组装完整 TUI
~500 lines of code9 toolsREPL 屏幕 + 模式切换 + 欢迎信息 + 窗口自适应
REPL 是 CLI 产品的「主界面」——它把所有组件组装成体验
“A great REPL is greater than the sum of its parts”
Compose, don't inherit
[ Phase 3: 终端 UI ] · 工具数: 9 · 代码量: ~350 行
前置知识
- 需要完成: s15 [输入框]
你将学到
- Composition Root 模式组装所有组件
- 欢迎页 → 对话视图的状态切换
- 内置命令路由(/help、/clear、/tools)
- 终端窗口自适应布局
经过 s13-s15,我们有了所有组件:MessageList、PromptInput、Spinner、StatusBar。但它们还没有被组装成一个完整的产品体验。
一个专业的 CLI 需要:
- 欢迎页:启动时显示品牌信息,而不是一片空白;
- 内置命令:
/help、/clear、/tools等不需要 AI 处理的快捷操作; - 状态管理:欢迎页在第一次输入后消失,切换到对话视图;
- 窗口自适应:根据终端宽度调整布局。
设计决策
REPL = Read-Eval-Print Loop
REPL 主屏是所有组件的组合根(Composition Root):
┌─────────────────────┐
│ Welcome / Messages │ ← 互斥显示
│ │
├─────────────────────┤
│ Spinner (条件) │ ← 仅运行时显示
├─────────────────────┤
│ ❯ PromptInput │ ← 始终可见
├─────────────────────┤
│ StatusBar │ ← 始终可见
└─────────────────────┘
内置命令路由
以 / 开头的输入走命令路由,不发给 Agent:
if (text.startsWith("/")) {
if (handleCommand(text)) return; // 命中了内置命令
}
// 否则发给 Agent
欢迎页→对话的状态切换
const [showWelcome, setShowWelcome] = useState(true);
// 第一次提交后:
if (showWelcome) setShowWelcome(false);
实现要点
export function ReplScreen(): React.ReactElement {
return (
<Box flexDirection="column">
{showWelcome ? <Welcome cwd={process.cwd()} /> : <MessageList messages={messages} />}
{running && <Spinner label="thinking" />}
<PromptInput onSubmit={handleSubmit} disabled={running} />
<StatusBar messageCount={messages.length} model="claude-sonnet-4" isRunning={running} />
</Box>
);
}
useStdout 可以获取终端列数,用于未来的自适应布局。
运行验证
cd agents/s16-repl-screen
npm install
npm run dev
# 1. 看到欢迎页(品牌框 + 目录 + 模型 + 快捷键)
# 2. 输入 /help 测试内置命令
# 3. 输入问题,欢迎页消失,进入对话模式
# 4. 输入 /clear 清空消息,输入 /tools 查看工具
# 5. ESC 退出
对照 Claude Code
| 方面 | 教学版 | Claude Code |
|---|---|---|
| 主屏 | ReplScreen(~120 行) | screens/REPL.tsx(5000+ 行) |
| 欢迎 | Welcome 组件 | LogoV2 + StatusNotices |
| 命令 | switch 硬编码 | 命令解析器 + 模式栈 |
| 自适应 | useStdout 获取宽度 | useTerminalSize + 响应式布局 |
生产版 REPL.tsx 是整个应用的核心——它还管理权限请求 UI、MCP 连接、团队协作、全屏模式切换。
深入思考
- Composition Root 模式:REPL 不做业务逻辑,只负责组装和状态分发。这和 React 应用的 App.tsx 角色一样。
- 状态提升 vs Context:目前所有状态在 ReplScreen 内管理。当组件更多时,应该引入 Context 或状态管理库。
- 为什么 Claude Code 的 REPL 有 5000 行? 因为它同时处理:权限确认流、工具沙盒 UI、团队视图、语音输入、全屏编辑器、Doctor 诊断——产品复杂度远超"对话 + 工具"。
练习
- 给 Welcome 组件添加一个 ASCII Art Logo(提示:用模板字符串和
Text组件)。 - 实现
/model命令,让用户在运行时切换 AI 模型。 - 用
useStdout的stdout.columns实现自适应:当终端宽度 < 60 时,隐藏 StatusBar 的快捷键提示部分。
Phase 3 总结
恭喜!完成 s13-s16,你的 Agent 已经有了专业的终端 UI:
- ✅ Ink React 渲染(s13)
- ✅ 消息列表组件(s14)
- ✅ 输入框 + 历史记录(s15)
- ✅ REPL 主屏组装(s16)
下一个 Phase 将深入 Prompt 工程——让 Agent 更聪明。s17 System Prompt 开始。
下一课预告
Agent 已经能跑、能看、能交互了。但它的行为靠"默认人格"驱动,没有定制化。下一课 s17 System Prompt 将设计 Agent 的"灵魂"——通过 system prompt 让它知道自己是做什么的、应该怎么做。