---
url: /wave-agent/specs/ui/transcript-outline.md
description: >-
  会话内容区左边缘的竖排刻度大纲：每条用户消息一项，悬停显示这条问的是什么，点击跳到该轮问答；窗口留白不足时自动隐藏；三端（desktop / VSCE /
  JetBrains）共用
---

# 功能规格说明：会话消息大纲

> 本规格描述「在一条长会话里跳回某一轮问答」的导航入口。形态对齐 Codex 桌面端：内容区左边缘一列等距短刻度，一个刻度 = 一条用户消息，悬停出预览卡，点击落位。作用域是**当前会话已加载的内容**；按内容查找某一句话见 [transcript-find.md](./transcript-find.md)。

## 用户场景与测试

### 用户故事：会话消息大纲（优先级：P2）

作为用户，我希望在长会话里一眼看到「我问过哪几件事」，点一下就跳回那一轮问答，以便在一条跑了几十轮、每轮都带大段工具输出的会话里不用靠滚轮找自己的问题。

**为什么是这个优先级**：会话只会越跑越长（工具调用、后台任务输出、子代理结果都在往里堆），而现在的导航入口只有「往上滚」和吸顶条（只能看到上一条被滚过去的用户消息，且只能点回最近的一条）。对齐 Codex 桌面端已经验证过的形态；不引入新的数据依赖——大纲项完全由会话里已有的用户消息派生。

**独立测试**：打开一条几十轮的会话，验证左边缘出现一列刻度、刻度数等于其中的用户消息数；上下滚动验证高亮刻度跟着变到视口顶附近的那一轮；悬停任意刻度验证预览卡出现且内容就是该轮的用户消息；点击某个刻度验证滚到那一轮且不再被流式内容拽回底部；把面板拖窄到阈值以下验证刻度整体消失，拖回去验证重新出现；在会话仍处于流式生成时点击刻度，验证落位不被新内容打断。

**验收场景**：

1. **假设**会话内容区已加载且其中**至少两条**用户消息，**当**用户查看内容区左边缘，**则**必须显示一列竖排刻度大纲，位置在内容列**左侧的留白里**（距滚动面左边缘约 20px，与消息列之间留有明显间距，不与气泡贴在一起）、**不占用正文宽度**（正文列的可用宽度与无大纲时完全一致）；每条可选用户消息对应一个刻度。
2. **假设**会话只有一条用户消息，或者没有任何用户消息，**当**查看内容区，**则**不显示大纲（一条刻度没有导航价值，不该占位）。
3. **假设**大纲已显示，**当**判断「哪些消息成为刻度」，**则**只列用户消息中**带文本**的那些：注入型隐藏消息（`isMeta` 的规则提醒、钩子上下文、任务通知等）与没有文本块的用户消息（纯任务通知）都不列——与吸顶条「能否作为锚点」的判据必须是**同一个**，不得出现「吸顶条认它、大纲不认它」的分叉。
4. **假设**大纲已显示，**当**用户滚动内容区，**则**必须把「当前这一轮」的刻度标为高亮态（更长、对比度更高的刻度，其余为浅色短刻度）；「当前这一轮」的判据是**视口顶部之上最近的那条用户消息**，与吸顶条用的是同一个判据，两者在任何滚动位置下都必须指向同一条消息。
5. **假设**大纲已显示，**当**用户把指针悬停在某个刻度上（或键盘把焦点移上去），**则**必须在该刻度右侧弹出预览卡，**卡片里只有这一条用户消息的文本**（最多 3 行，超出截断；不显示助手回答、不做「标题 + 正文」两段式——这么小一块地方，两段内容只会互相重复）；预览卡**不得溢出内容区**——宽度随列宽自适应，窄列下收窄到「列宽 − 24px」，垂直方向贴住刻度的位置并对屏幕边缘做夹取。
6. **假设**用户点击某个刻度，**当**该刻度对应的消息在已加载的消息里，**则**必须立即把该消息落位到视口内（不播放长距离平滑滚动动画），并**同时松开「跟随新内容」的状态**：随后到达的流式内容、工具输出、压缩提示都不得把视口拽回底部。
7. **假设**目标消息位于虚拟列表尚未渲染的区段，**当**用户点击该刻度，**则**仍必须落位成功——定位必须按消息在列表中的位置计算，不得依赖目标行是否已挂载在 DOM 上。
8. **假设**大纲已显示，**当**会话正在流式生成（新消息、工具输出不断追加），**则**大纲必须随新增的用户消息增长、且不打断用户正在进行的悬停与阅读；已在列表中的刻度不得因流式刷新而跳动或重排。
9. **假设**会话消息是分页加载的（历史还有更早的页未取），**当**用户查看大纲，**则**大纲只包含**已加载**消息里的用户消息；用户上翻触发更早一页加载后，大纲必须随之增长（更早的刻度补充在上方），不得报错、不得重置当前高亮。
10. **假设**内容列**还没撑满最大宽度**（800px，窄分屏、IDE 侧栏、手机远控页），或撑满之后两侧留白**不足 40px**，**当**查看内容区，**则**整个大纲**不显示**——刻度必须与消息列之间有实际的间距，没有这片留白就不画（与 Codex 一致：不给窄版形态、不做折叠抽屉），内容列宽度与无大纲时完全一致；把窗口拉到留白足够后大纲必须重新出现。
11. **假设**大纲已显示且用户消息数量较多（几十条），**当**渲染刻度，**则**刻度必须**等距**排布（不按每条消息的实际高度成比例）、**密排**（相邻刻度的视觉间距约 20px，是一列短横而不是几个散点），间距随条数向下自适应收缩；常见长度（几十轮）必须在视口高度内排完——大纲自身不出现滚动条、不裁掉末尾的刻度。条目极多时压缩到 2px 下限即止，不抽样丢项。
12. **假设**用户切换会话（或该分屏换了会话），**当**新会话内容渲染出来，**则**大纲必须按新会话的用户消息重建，不得残留上一会话的刻度、高亮位置或展开的预览卡。

## 边界情况

* **超长用户消息**：预览卡只取开头数行，不得把整段长文本塞进卡片；悬停不得因截断长文本而卡顿。
* **一屏内多轮问答**：视口里同时可见多条用户消息时，高亮取「视口顶部之上最近的那条」，不随视口内可见的其他用户消息来回跳。
* **会话为空 / 首屏加载中**：消息尚未到达时按场景 2 处理，不显示占位刻度。
* **与查找条、吸顶条共存**：三者同屏互不遮挡；查找条跳转与大纲跳转都要松开跟随状态（同一条语义），互不覆盖对方的结果。
* **无悬停设备**（触屏、手机远控页）：不做长按/点击出预览的替代交互；这类形态通常已落到「窄于阈值不显示」的情形。
* **IDE 侧栏的默认宽度**：VS Code / JetBrains 侧栏默认只有 400px 上下，连消息列的 800px 上限都到不了，按场景 10 大纲**默认不出现**；把面板拉宽到 ≥ 880px 左右才会看到。这是有意为之（窄栏里正文最宝贵、也放不下目录与正文之间的间距），不视为缺陷。

## 非目标（明确排除）

* **跨会话导航**：大纲只作用于当前会话，切换会话/查看历史会话列表不属于本规格。
* **按助手消息或工具调用建刻度**：刻度只有一层，只对应用户消息；不提供「展开看这一轮调了哪些工具」的树形结构。
* **窄屏替代入口**：窄于阈值时不提供任何替代入口（不隐藏成按钮、不做抽屉），与 Codex 的行为保持一致。
* **键盘跳转快捷键**（上一条/下一条用户消息）：独立需求，不在本规格内。
* **搜索/过滤大纲项**：按关键字过滤刻度不在本规格内，找某句话见 [transcript-find.md](./transcript-find.md)。
