docs/plan/2026-08-20-mao-agent-cli-ux-design.md
Rama main · réplica de lectura del repositorio original.
# mao-agent CLI 用户体验专项优化设计
> 版本: v0.1 | 更新时间: 2026-08-20
> 状态: **本文档为历史设计记录,当前实现以根 `CHANGELOG.md` 与 `skills/mao-cli/reference/mao-agent.md` 为准。** U0/U1/U2 已落地;U3 的「不引入 ink」结论后续被推翻——交互层已改为 ink + React(自研按键解码器 + 行编辑器 + 布局预算,见 `agent-cli/src/tui/`),下文 §8.1 / §9 / §11 相关判断已过时
> 定位: 在协议闭环已跑通的前提下,专项提升**交互式 REPL**的可读性、可控性与「像在对话」的体感
> 关联文档: [2026-08-20-mao-agent-cli-technical-design.md](./2026-08-20-mao-agent-cli-technical-design.md)、[2026-06-25-ask-user-questions-design.md](./2026-06-25-ask-user-questions-design.md)、[2026-06-08-center-panel-approval-design.md](./2026-06-08-center-panel-approval-design.md)
> 实现目录: `agent-cli/`(`repl/`、`render/`、`commands/`)
---
## 0. 一句话总结
`mao-agent` 已具备 CLOUD/LOCAL 协议能力,但交互层仍是「行式日志 + 简陋 readline」:执行中不可输入、提问/审批打断主循环、工具与正文混在一起、状态栏时常看不见、冷启动无引导。本设计把 UX 从「能跑」推到「愿意天天用」,**不重做协议、不引入全屏 TUI 框架为默认依赖**,用分阶段的输入编排 + 视觉层级 + 中断式交互重构解决问题。
---
## 1. 目标与非目标
### 1.1 目标
1. **对话感**:用户始终知道「现在轮到谁」——自己输入 / Agent 思考 / 工具执行 / 等你确认。
2. **可控感**:长任务可取消、可排队下一条、可看进度;误操作有后悔路径。
3. **可读感**:Assistant 正文、工具轨迹、系统提示三者视觉分离;关键信息一眼扫到。
4. **低摩擦**:首次使用、恢复会话、LOCAL 信任、提问与审批,步骤少、文案短、默认合理。
5. **兼容脚本**:打印模式 / JSON / 非 TTY 行为保持稳定;交互优化**不得**破坏 CI 退出码与 stdout 纪律。
### 1.2 成功标准(可验收)
| 场景 | 验收 |
|---|---|
| 冷启动 | 5 秒内看到身份(谁/什么模式)+ 可输入提示 + 一条最短帮助 |
| 一轮对话 | 工具调用可折叠扫读;正文不被工具日志淹没 |
| 执行中 | 状态始终可见;可 `/cancel`;可预输入下一条(队列) |
| `ask_user_questions` | 序号/方向键/多选可用;不破坏主 REPL 输入状态 |
| LOCAL 审批 | 一眼看清工具+参数摘要;`y/n/always` 语义清晰 |
| 恢复会话 | 最近轮次可读摘要,而非裸 `id/phase` 字符串墙 |
| 非 TTY / `-p` | 与现网一致,无 spinner/无交互假设 |
### 1.3 非目标
- 不做 Electron 式 GUI,不做完整全屏 TUI(多窗格、鼠标拖拽布局)。
- 不在本期引入 React/`ink` 为**硬依赖**(可作为后续可选评估,见 §8)。
- 不重做 `mao-user` 元数据管理;会话删除/置顶等仍引导到 `mao-user`。
- 不做 Side Task 多会话同屏 attach(技术设计 Phase 4)。
- 不改变后端 WS 协议语义(除非为 UX 发现的硬伤单独开后端任务)。
---
## 2. 现状诊断(基于源码)
对照实现:`agent-cli/src/repl/repl.ts`、`render/repl-renderer.ts`、`commands/chat.ts`、`local/approval.ts`、`util/ansi.ts`。
### 2.1 痛点地图
| ID | 痛点 | 用户体感 | 根因 | 严重度 |
|---|---|---|---|---|
| P1 | **执行中锁输入** | Agent 跑着只能干等或 `/cancel`,不能先写好下一条 | `inputLocked` + `rl.pause()`;无消息队列 | P0 |
| P2 | **状态栏经常消失** | 流式输出时底部进度没了,像卡住 | `setStatus` 要求 `atLineStart`;`content_delta` 一写就清状态 | P0 |
| P3 | **工具与正文平铺** | 长任务刷屏,结论难找 | `▸ tool` 与正文同级行式输出,无折叠/分组 | P0 |
| P4 | **提问打断 REPL** | `ask_user_questions` 新建第二个 `readline`,主循环状态脆弱 | `askQuestionsInTty` 独立 `createInterface` | P0 |
| P5 | **提问交互原始** | 只能手打序号;无高亮、无默认项、无 Esc 取消语义 | 纯文本 `question()` | P1 |
| P6 | **冷启动空白** | 只有 `› `,不知能 `/help`、不知当前会话 | 无 welcome banner / 无 slash 提示 | P1 |
| P7 | **历史回放过干** | resume 只有「首行+工具名」文本墙 | `summarizeMessages` + stderr 分隔线 | P1 |
| P8 | **登录密码可见** | `login` 的 `hidden` 参数未真正隐藏输入 | `cmdLogin` 里 `_hidden` 未接线;`promptHidden` 也未吞回显完善 | P1 |
| P9 | **斜杠面窄且无补全** | 无 `/clear`、`/compact` 提示、`/agent`、无 Tab | 硬编码少量命令 | P2 |
| P10 | **Todo 不可见** | 任务规划只在 `/todo` 才看 | 无 live Todo 条 | P2 |
| P11 | **审批文案偏运维** | 规则、deny-list、信任路径对人类不友好 | 技术错误直接 stderr | P1 |
| P12 | **Markdown 流式撕裂** | 半截 `**` / 代码围栏渲染错乱 | `renderMarkdownLite` 按 delta 片段处理 | P2 |
| P13 | **Ctrl+C 心智负担** | 「有任务取消 / 无任务再按一次退出」需学习 | 双击窗口 + 文案偏短 | P2 |
| P14 | **会话切换成本高** | 必须退出重开才能换会话 | 首版「一进程一会话」简化 | P2(可接受,但要降低摩擦) |
### 2.2 设计文档与实现的体验债
技术设计 §9 明确:**首版行式滚动、单行状态栏、不做 ink**——这对「协议优先」正确,但也直接把体验债留到了现在。Phase 1/3 能力已落地,**体验专项应视为独立 Phase U(UX)**,与协议 Phase 解耦。
### 2.3 用户旅程(当前)
```
安装 → login(密码可能明文)→ mao-agent
→ 一行「新建会话」→ 空白 ›
→ 打字 → 锁输入 → 工具刷屏 + 正文交织 → 状态栏时有时无
→ Agent 提问 → 第二个 readline 抢 stdin
→ 结束 → 一行 meta → ›
→ /exit
```
目标旅程见 §4。
---
## 3. 设计原则
1. **角色清晰**:每一屏时刻只突出一个「当前焦点」(输入 / 流式正文 / 工具块 / 模态提问)。
2. **输出分级**:
- L0 正文(Assistant)——默认最大字号对比度
- L1 工具轨迹 —— 次级、可折叠摘要
- L2 系统/连接/压缩 —— 最弱 dim,一行够用
3. **模态优先于并行**:提问与审批用**显式模态**占住输入权,结束后干净交还 REPL;禁止叠两个 readline。
4. **TTY 增强、管道不变**:所有花活(spinner、颜色、队列预输入)仅 TTY + 非 print;`-p`/JSON 零装饰。
5. **渐进披露**:默认安静;需要细节时 `/verbose`、展开工具、`--thinking`、`--trace-file`。
6. **文案像人对人**:少堆协议字段名;错误给出「下一步做什么」。
7. **可撤销默认**:取消、拒绝审批、Esc 退出模态,比「强制完成」更重要。
8. **架构不绑死 UI**:继续坚持 `SessionRunner → CliEvent → Renderer`;UX 改动尽量落在 `repl/` + `render/` + 薄编排层。
---
## 4. 目标体验(叙事)
```
$ mao-agent
mao-agent 会话 #128 · 通用助手 · gpt-4o · CLOUD
输入消息开始;/help 查看命令。Ctrl+C 取消当前任务。
› 帮我看看 README 总结三句话
💭 思考中… 3s · Context 12%
▸ read_file README.md
210 lines · 0.2s
这份 README 描述了……(三句话)……
✔ 完成 · 8s · Context 18% · 1 tool
› _
```
执行中用户可继续打字(灰色预览「已排队」),回车进入队列;Agent 结束后自动发送下一条。
Agent 提问时进入模态面板,选完后回到同一 `›`。
---
## 5. 信息架构与视觉规范
### 5.1 屏幕分区(逻辑,非全屏 TUI)
| 区域 | 内容 | 行为 |
|---|---|---|
| Header(会话开始时一次) | 产品名、sessionId、Agent、Model、Mode、workspace(LOCAL) | 静态打印,不重绘 |
| Transcript | 用户回合分隔、正文、工具块、系统一行提示 | 只追加,进入 scrollback |
| Status(TTY) | spinner + 阶段文案 + 已用时 + Context% | **独立于正文行**:用 stderr 最后一行或「正文下方保留行」策略(§6.2) |
| Input | `› ` 或模态 `? ` | 单一 stdin 所有者 |
### 5.2 回合分隔
每轮用户消息前打印弱分隔(可选):
```
── 你 ────────────────────────────────────────
› 帮我看看 README…
── Agent ─────────────────────────────────────
```
默认开启轻量版(仅在回合开始印一条 `──`);`--compact-ui` 可关掉。
### 5.3 工具块(默认折叠)
```
⏺ shell npm test
⎿ exit 0 · 12.4s
```
- 默认:Claude Code / Codex 式 `⏺` 标题 + `⎿` 一行摘要(截断)。
- `/verbose` 或环境 `MAO_AGENT_VERBOSE=1`:多行预览。
- `file_change` 归入回合末汇总,中途只 dim 一行路径。
- 用户回合整行深灰块回显(底栏输入框提交后写入 transcript,避免和 readline 双份)。
### 5.4 颜色与符号
- 保持现有 ANSI 色板(cyan 工具、dim 次要、red 错误、yellow 系统)。
- **减少 emoji 依赖**:工具用 `⏺`/`⎿`,输入用 `❯`;`--ascii` 退回 `*` / `|` / `>`。保留 `✔`/`✖`/`⚠`。
- 遵守 `NO_COLOR` / `--color` / 非 TTY 规则(已有)。
### 5.5 Markdown
- **流式阶段**:不对半截 markdown 做结构变换,原样输出或仅做安全转义。
- **回合结束**(可选 Phase U2):对完整 assistant 缓冲做一次 lite 渲染(标题/粗体/行内代码)。
- 代码围栏:围栏行 dim;围栏内不着色(与现状一致)。语法高亮仍非目标。
---
## 6. 交互模型专项设计
### 6.1 输入所有权状态机(核心)
```
┌─────────────┐
│ IDLE │◄──────────────────────────────┐
│ › 可输入 │ │
└──────┬──────┘ │
│ submit prompt │
▼ │
┌─────────────┐ ask/approval ┌──────┴──────┐
│ RUNNING │──────────────────────►│ MODAL │
│ 可预输入排队 │◄──────────────────────│ 独占 stdin │
└──────┬──────┘ 答完/取消 └─────────────┘
│ terminal phase
▼
┌─────────────┐
│ DRAIN_QUEUE │──有队列──► 自动 runPrompt ──► RUNNING
└─────────────┘
│无队列
└──► IDLE
```
规则:
1. **全局唯一** `readline` / 输入驱动器;模态不得 `createInterface` 第二次。
2. `RUNNING` 时:键入进入 `queuedPrompt`(显示 `… 已排队(回车追加,Ctrl+C 清空队列)`);不立刻 `send_message`。
3. `MODAL` 时:暂停队列写入;模态取消 = 按产品策略发 fail/空答(对齐 `--on-question`)。
4. 退出进程前若有队列:提示「有未发送草稿,确认退出?」
### 6.2 状态栏可见性修复(P0)
现状:状态写在「行首」且被 `content_delta` 清掉。
方案(二选一,推荐 A):
**A. stderr 粘性状态行(推荐)**
- 正文继续走 stdout。
- 状态始终 `\r\x1b[K` 写在 stderr;每次 stdout 写入前清 stderr 状态,写入后**立刻重画**(不要求 `atLineStart`)。
- 多行 stdout 增量时:每个 chunk 后重画,80ms 节流。
**B. 保留底行(需轻微 ANSI 光标管理)**
- 打印正文前 `scroll` 上推,底行固定状态;复杂度更高,留作 U2。
验收:流式打字过程中,用户仍能看到 `思考中/运行 shell/等待 LLM` + 秒数。
### 6.3 取消与中断(P13)
| 输入 | RUNNING | IDLE | MODAL |
|---|---|---|---|
| Ctrl+C | 发 `cancel`;清空队列;提示「已取消」 | 第一次提示「再按一次退出」;2s 内第二次退出 | 关闭模态(等同拒绝/取消提问,按协议发结果) |
| `/cancel` | 同 Ctrl+C | 提示无任务 | — |
| Ctrl+D | — | 退出 | 取消模态 |
文案统一短句,避免「等待任务结束…」而无超时提示:若 cancel 后 8s 未终态,提示「仍在收尾,可再等或强制 Ctrl+C 退出进程」。
### 6.4 斜杠命令升级
| 命令 | 作用 | 优先级 |
|---|---|---|
| `/help` | 分组帮助(会话/模型/视图/危险) | 已有,改版 |
| `/session` | 会话信息表格化 | 改版 |
| `/model` | 切换模型;无参列出常用 | 增强 |
| `/todo` | Todo;RUNNING 时自动刷新提示 | 增强 |
| `/context` | context + 建议「接近上限可新开会话」 | 增强 |
| `/cancel` | 取消 | 已有 |
| `/clear` | 清屏(ANSI),不删服务端历史 | U1 |
| `/verbose` | 切换工具详情详细度(会话级) | U1 |
| `/queue` | 查看/清空预输入队列 | U1 |
| `/copy` | 复制上一回合 assistant 文本到剪贴板(有则用,无则打印路径) | U2 |
| `/agent` | 提示改用新进程 + `mao-agent --agent`,不假装热切换 | U1 文案 |
Tab 补全:仅斜杠命令名与 `/model` 候选(U2);无参时列出前缀匹配。
### 6.5 `ask_user_questions` 模态(P4/P5)
对齐 desktop 能力的「终端缩小版」:
```
? Agent 想确认(1/2)
用哪种部署方式?
❯ 1) 蓝绿发布 — 零停机
2) 滚动发布
3) 自定义…
↑↓ 选择 Enter 确认 数字快捷 Esc 跳过/取消(受 --on-question)
```
- 多选:Space 勾选,Enter 提交。
- 自定义:选「自定义」后进入一行输入。
- 实现:在同一输入驱动器上切换 keymap;**禁止**新建 readline。
- 超时:服务端 15min;本地每分钟 stderr 提醒一次剩余时间(可选)。
### 6.6 LOCAL 审批模态(P11)
```
⚠ 需要批准 · shell
cd /opt/mao && npm test
[y] 允许这次 [n] 拒绝 [a] 本会话允许同类
工作区: /opt/mao · 已信任
```
- `a` = 会话内动态追加等价于临时 `--approve-rule`(内存,不写盘),降低重复打扰。
- 拒绝理由简短回传 Agent(已有 `tool_error` 路径)。
- deny-list / 未信任:不要只丢技术长句;模板:
```
✖ 已拦截:工作区未信任
目录: /tmp/x
下一步: 在本目录运行 mao-agent --local 并输入 y,或编辑 ~/.mao/agent-cli/config.json
```
### 6.7 冷启动与 resume(P6/P7)
**新会话 welcome(3 行封顶)**:
```
mao-agent #128 · 通用助手 · gpt-4o · CLOUD
输入消息开始。常用: /help /session /model
```
**resume / `--continue`**:
```
恢复 #128 · 通用助手 · 上次更新 10 分钟前
── 最近对话 ──
你: 帮我改登录页…
Agent: 已改 TopNav… · 工具: edit_file×2
──────────────
›
```
- 默认最近 2~3 轮;`--replay-full` 仍拉更多。
- 每条用户/助手各最多 2 行摘要;工具只计次数。
### 6.8 登录(P8)
- `mao-agent login` 密码必须无回显(TTY 下 `stdin.setRawMode` 或等效)。
- 成功后提示:`之后可直接 mao-agent`;token 过期文案指向 `mao-agent login`。
### 6.9 会话切换摩擦(P14)
短期不实现多会话 attach,但降低成本:
- `mao-agent ls`:高亮最近会话、标注 `last`、显示相对时间(`10m ago`)。
- `mao-agent resume` 打印将恢复哪一条的标题/Agent 再连接。
- welcome 增加:`换会话: mao-agent resume | mao-agent ls`。
---
## 7. 文案与错误体验
### 7.1 语气
- 短、祈使、给下一步。
- 中文为主(与现网一致);标志符/命令保持原文。
### 7.2 常见错误改写示例
| 现状倾向 | 目标文案 |
|---|---|
| `当前任务仍在执行,请等待结束或 /cancel。` | `上一条还在跑。已把你的输入放入队列;或 /cancel 后重说。`(配合队列后) |
| `未知斜杠命令` | `未知命令 /foo。输入 /help 查看列表。` |
| `没有可恢复的 ACTIVE 会话` | `没有可恢复的会话。直接运行 mao-agent 新建一个。` |
| WS 重连失败 N 次 | `连不上服务器(已重试 N 次)。检查网络,或 mao-agent login 后重试。` |
### 7.3 首次 LOCAL 信任
保留 y/N 默认拒绝;说明「允许后 Agent 可在该目录执行命令与写文件」,一句风险够用,不贴长协议。
---
## 8. 技术方案选型(UX 层)
### 8.1 推荐路径:自研「轻交互层」,不默认上 ink
| 方案 | 优点 | 缺点 | 结论 |
|---|---|---|---|
| 继续纯 readline + 行式 | 零依赖、管道友好 | 难做模态/队列/粘性状态 | 仅维持 print 模式 |
| **自研 InputController + AnsiRenderer** | 可控、依赖少、契合现架构 | 需认真处理 raw mode / 测 TTY | **主路径** |
| ink / React TUI | 组件化快 | React 运行时、包体、与现有 CLI 风格冲突 | U3 可选 POC,不阻塞 U1/U2 |
### 8.2 模块划分(建议新增)
```
agent-cli/src/
ui/
input-controller.ts # 唯一 stdin:IDLE/RUNNING预输入/MODAL keymap
modal-ask.ts # ask_user_questions UI
modal-approval.ts # LOCAL 审批 UI
welcome.ts # banner / resume 摘要格式化
render/
repl-renderer.ts # 强化:工具折叠、粘性状态、回合分隔
status-line.ts # 从 renderer 抽出,便于测节流
repl/
repl.ts # 变薄:委托 InputController + 队列
```
`SessionRunner` / WS **尽量不动**;若队列自动发送,只在 `repl` 层连续调用 `runPrompt`。
### 8.3 测试策略
- 单测:状态机转换、队列、状态行节流、markdown 流式不撕裂、文案快照。
- 集成:mock WS 下模拟 `ask_user_questions` 模态键序(可注入假 stdin)。
- 手工验收清单见 §10。
- 不强制 Playwright;TTY raw mode 以单测 + 脚本验收为主。
### 8.4 配置项(可选)
`~/.mao/agent-cli/config.json` 增补(均有默认):
```json
{
"ui": {
"verboseTools": false,
"showTurnDividers": true,
"asciiOnly": false,
"queuedInput": true
}
}
```
CLI 覆盖:`--verbose-tools`、`--ascii`、`--no-queue`。
---
## 9. 分期落地(Phase U)
### U0 — 止血(0.5~1 天,强烈建议先做)
- 粘性状态栏(§6.2A)
- 登录密码隐藏
- welcome 三行 + `/help` 提示
- 取消后超时提示
- `ls` / resume 相对时间与标题可读性
**验收**:流式输出时仍能看到状态;新用户知道有 `/help`。
### U1 — 交互主路径(3~5 天)
- `InputController` + 消息队列(P1)
- 统一模态:ask + approval(P4/P5/P11)
- 工具默认折叠 + `/verbose`
- `/clear` `/queue`
- 错误文案改写
**验收**:执行中可排队;提问不再双 readline;长任务刷屏明显减轻。
### U2 — 润色(已落地)
- 回合结束 markdown 再渲染(流式阶段原样输出,块边界按可视行数一致才回写)
- 斜杠 Tab 补全(含 `/model` 模型名、`/queue clear`)
- Todo 在状态区一行 live 摘要(`Todo 2/5`)
- `/copy` 复制上一回合回复(无剪贴板命令时回落到打印)
- 底栏 Composer(备用屏 + 顶栏固定 + 滚动区 + 圆角输入框),对齐 Cursor Agent / Claude Code 的「对话在上、输入钉底」;高度不够时回退 readline。
- 用户回合整行深灰块回显(底栏输入框提交后写入 transcript,避免和 readline 双份)。
- 底行状态方案 B:半行流式时用光标保存/恢复把状态钉在最后一行;无 `rows` 时不在正文行 `\r`,避免擦掉回复(不再用换行把旧状态推进历史)。
- resume 摘要按角色对齐排版
### U3 — 可选评估(结论:不做)
- **不引入 ink / React。** 包体、运行时与现有零依赖 CLI 风格冲突;U1 的 `InputController` + 手写 ANSI 已覆盖边框输入框的核心诉求(队列、模态、Tab)。若未来强诉求全屏面板,再单独 POC,不作为默认路径。
---
## 10. 手工验收清单
- [ ] `mao-agent` 冷启动 ≤3 行引导 + 底栏 `❯` 输入框
- [ ] 发送长回复:状态秒数持续更新
- [ ] 执行中输入第二句并回车:显示已排队;结束后自动发送
- [ ] 执行中 Ctrl+C:取消且队列清空
- [ ] Agent `ask_user_questions`:方向键选择;Esc/取消行为符合 `--on-question`
- [ ] LOCAL 审批:`y`/`n`/`a`;deny-list 文案含下一步
- [ ] `mao-agent login` 密码无回显
- [ ] `mao-agent -p "…"` stdout 无装饰;退出码不变
- [ ] `NO_COLOR=1` 无颜色码
- [ ] resume 可见最近对话摘要
---
## 11. 风险与约束
| 风险 | 缓解 |
|---|---|
| raw mode 在某些 SSH/tmux 异常 | 检测失败则降级纯 readline,并提示 |
| 队列自动发送误触 | 回车才入队;Ctrl+C 清空;`/queue` 可编辑策略先只支持清空 |
| 状态行与用户滚动冲突 | 仅用 `\r` 单行;不抢 scrollback 历史 |
| 与技术设计「一进程一会话」冲突预期 | 文档/welcome 写清;用 `ls`/`resume` 降摩擦 |
| 范围膨胀到全屏 TUI | 严格按 U0→U1→U2;U3 单独决策 |
---
## 12. 与现有文档的关系
| 文档 | 关系 |
|---|---|
| `2026-08-20-mao-agent-cli-technical-design.md` | 协议/架构 SSOT;本文不修改其 Phase 1~3 结论,只把 §9「体验后置」展开为可执行 UX 专项 |
| `2026-06-25-ask-user-questions-design.md` | 后端/产品语义;本文定义 CLI 侧交互壳 |
| `2026-06-08-center-panel-approval-design.md` | desktop 审批 UX 参考;CLI 模态对齐其决策语义,不抄 GUI 布局 |
建议在技术设计文首「关联文档」中增加本文链接;发版用户可见改动写入根 `CHANGELOG.md` → `### 终端 CLI(mao-agent)`。
---
## 13. 开放问题(评审时拍板)
1. **队列是否默认开启?** 建议默认开,提供 `--no-queue`。
2. **模态 Esc 对 `ask_user_questions`**:发空答 / 显式 cancel 事件 / 等同 `--on-question=fail`?需与后端现有 result schema 对齐后定一条。
3. **会话内 `a` 永久批准**:仅内存 vs 写入 config?建议 U1 仅内存。
4. **是否允许 U3 ink?** 默认否;U2 完成后维持该结论,不引入 React 运行时。
---
## 14. 附录:优先级与痛点回溯
| 痛点 | 归属阶段 |
|---|---|
| P2 状态栏消失 | U0 |
| P6 冷启动 | U0 |
| P8 密码可见 | U0 |
| P7 历史干 | U0 |
| P1 锁输入 | U1 |
| P3 工具刷屏 | U1 |
| P4/P5 提问 | U1 |
| P11 审批文案 | U1 |
| P9 斜杠 | U1/U2 |
| P10 Todo live | U2 |
| P12 Markdown | U2 |
| P13 Ctrl+C | U0/U1 |
| P14 换会话 | U0 降摩擦 |
---
**文档结束。** 评审通过后建议直接按 U0 → U1 拆任务实现;本文件只描述体验与交互合约,不替代具体 PR 中的实现说明。