Skip to content

功能规格说明:桌面端布局与分屏 ​

拆分自 desktop-app.md(CodeWave IDE 桌面端总纲),本文档仅承载该主题的用户故事与验收场景;跨主题的边界情况与非目标按主题分发至各文件。

用户场景与测试 ​

用户故事:侧边栏收起/展开(优先级:P1) ​

作为用户,我希望点击侧边栏顶部标题旁的收起按钮把侧边栏完全收起(聊天区占满整个宽度),需要时再通过对话顶栏最左侧的展开按钮恢复,以便在专注对话内容时获得最大横向空间(与 Claude Code Desktop 的侧边栏收起体验一致)。

为什么是这个优先级:侧边栏固定宽度常驻占位,对话内容多时挤占阅读与预览空间;收起/展开是桌面端基础布局能力,且状态需跨会话/重启保持。

独立测试:点侧边栏收起按钮验证侧边栏完全收起(不渲染、不预留空位、不遮挡内容)且聊天区占满;点对话顶栏最左侧展开按钮验证恢复;双分屏下验证收起/展开全局同步、展开按钮只在最左侧 pane 顶栏出现;重启应用验证状态保持。

验收场景:

  1. 假设应用以 desktop 宿主运行,当用户点击侧边栏顶部标题旁的收起按钮,则侧边栏完全收起——不渲染、不预留左侧空位、不遮挡内容,聊天区占满整个宽度。
  2. 假设侧边栏已收起,当用户查看对话顶栏最左侧,则显示展开按钮(悬停提示「展开侧边栏」),点击后侧边栏恢复显示。
  3. 假设侧边栏已收起且账户卡片菜单(已登录为点击个人信息行热区弹出的纯功能菜单、未登录为「更多」按钮菜单)处于展开态,当收起生效,则菜单随侧边栏一并消失,不残留弹出菜单。
  4. 假设桌面端存在多个分屏(pane),当任一分屏中收起/展开侧边栏,则状态全局同步(所有 pane 一致收起或展开)。
  5. 假设桌面端存在多个分屏,当侧边栏已收起,则展开按钮只出现在最左侧 pane 的顶栏,右侧 pane 不重复渲染。
  6. 假设用户收起侧边栏后切换会话,当切换完成,则收起状态保持。
  7. 假设用户收起侧边栏后重启应用,当应用重新加载,则收起状态保持(持久化保存)。

用户故事:会话列表滚动、入口固定(优先级:P1) ​

作为用户,我希望左侧会话多到一屏放不下时只有「会话列表」这一块滚动,「新对话」「插件市场」入口与底部账户卡片始终固定可见,以便我随时能新建对话、进入插件市场或查看套餐用量,而不必先把列表滚回顶部。

为什么是这个优先级:会话条目长期累积,很容易超过一屏;入口一旦随列表滚走,用户就同时失去新建对话与插件市场这两个最主要的动作入口,而这两个入口在内容态下同样高频使用。

独立测试:造一棵远超一屏的会话树(多分组、多条目),滚动列表到底部,验证「新对话」「插件市场」入口与底部账户卡片的位置在整个滚动过程中不变且始终可点、侧边栏自身滚动位置恒为 0(内容不被整体滚走);把窗口高度压缩到很矮后重复验证固定入口与账户卡片仍完整可见、压缩由会话列表承担。

验收场景:

  1. 假设侧边栏会话树内容高度超过可视高度,当用户滚动会话列表,则只有会话列表区域滚动(滚动条只出现在该区域内),侧边栏本身不滚动——顶部窗口行/品牌行、「新对话」「插件市场」入口在整个滚动过程中位置不变、始终可点。
  2. 假设侧边栏会话树内容高度超过可视高度,当查看侧边栏底部,则账户卡片(套餐用量 / API 余额 / 账号)必须完整可见并贴住侧边栏底部,既不被会话列表顶出可视区,也不随列表滚动移动。
  3. 假设会话列表已滚动到末尾(或回到顶部),当用户继续滚动,则滚动停在该列表的边界,不得把侧边栏其余部分或整页一起带走;列表内条目不越界渲染到固定入口/账户卡片区域之上。
  4. 假设窗口高度被压缩到很矮(会话列表可视高度随之变小),当用户查看侧边栏,则固定入口与账户卡片必须保持自身完整高度、互不挤压,高度压缩全部由会话列表区域承担(其可滚动高度相应变小,列表照常可滚动到底)。
  5. 假设侧边栏处于无会话/空会话状态(列表内容不足一屏),当用户查看侧边栏,则布局与固定入口位置不变,不出现多余滚动条或元素位移。
  6. 假设会话列表已滚动到中间位置,当用户点击固定入口(「新对话」/「插件市场」)或切换主题,则入口行为与列表未滚动时一致,列表滚动位置不影响入口可用性与视觉。

用户故事:并排多对话(优先级:P2) ​

作为用户,我希望用 Cmd/Ctrl+Click 或拖拽把侧边栏里的会话在新分屏中打开,让 2 条甚至更多会话并排展示、各自独立交互,以便我对照多个任务的进展或同时推进多条对话。

为什么是这个优先级:多会话并行已让后台会话持续生成,并排展示把「并行」从后台能力升级为可见的多任务工作台;但不影响单会话基础体验。

独立测试:进行两条会话后,Cmd/Ctrl+Click 侧边栏另一条会话,验证出现两个并排分屏、各自独立输入与流式;继续 Cmd/Ctrl+Click 第三条验证三分屏;关闭其中一个分屏,验证剩余分屏重排且被关闭分屏的会话在后台继续运行。

验收场景:

  1. 假设侧边栏已有至少一条会话,当用户 Cmd+Click(macOS)/ Ctrl+Click(Windows)某条未在任何分屏展示的会话,则必须在聊天区右侧新增一个分屏并展示该会话,原有分屏保持不动;普通点击(无修饰键)保持替换焦点分屏语义不变。
  2. 假设已有两个分屏,当用户继续 Cmd/Ctrl+Click 其他会话,则必须继续向右追加分屏。
  3. 假设目标会话已在某个分屏中展示,当用户 Cmd/Ctrl+Click 该会话,则不得重复新增,改为聚焦并高亮已有该会话的分屏。
  4. 假设多个分屏并排,当用户在任一分屏的输入框发送消息,则消息必须进入该分屏绑定的会话;各分屏的消息流、流式状态、任务列表、消息队列与确认交互互不影响,多个分屏可同时流式生成。
  5. 假设多个分屏并排,当用户普通点击侧边栏会话,则必须替换「焦点分屏」展示的会话;焦点分屏为最近一次交互(点击或输入)的分屏并有可见标识,从未交互时焦点为第一个分屏;其他分屏的会话不受影响。
  6. 假设某分屏正在流式生成,当用户关闭该分屏,则分屏关闭但会话在后台继续生成(侧边栏运行中标识保留),剩余分屏重排;仅剩一个分屏时不提供关闭入口。
  7. 假设新增分屏后焦点行各分屏宽度将低于最小宽度,当用户 Cmd/Ctrl+Click,则必须改为放入其他行:仅一行时自动在下方新建第二行放置(窗口高度不足新建行时才拒绝并给出轻量提示);已有两行时加入另一行,另一行也不足时才拒绝并给出轻量提示。
  8. 假设用户拖拽侧边栏会话条目进入聊天区,当拖拽悬停在任一分屏上,则必须按该分屏的水平中线显示插入位置指示(悬停左半指示插入其前、右半指示插入其后,与拖拽分屏头部重排的指示规则一致;悬停于分屏间隙时指示吸附到该间隙,悬停越过最右分屏时指示最右追加位置);当松手,则在指示位置插入新分屏展示被拖会话。
  9. 假设用户拖拽侧边栏会话条目,当松手位置位于最右分屏的右半或其右侧,则在最右侧追加新分屏(与 Cmd/Ctrl+Click 等效)。
  10. 假设用户拖拽新增分屏,则被拖会话已在某分屏展示时不重复新增、改为聚焦该分屏;拖拽松手位置为显式目标行,与拖拽分屏头部移入该行一致——不做宽度拒绝,直接插入松手指示位置,行内容量低于最小宽度时该行横向滚动。

用户故事:新会话并排打开(优先级:P3) ​

作为用户,我希望新建空白会话时能一步并排打开(而不是先替换当前分屏、再从侧边栏把被顶掉的会话重新 Cmd/Ctrl+Click 出来),以便直接开始一场与现有会话并排的新对话。

为什么是这个优先级:并排多对话已覆盖已有会话的并排入口,新会话并排是纯效率增强——少了「替换再找回」的绕路,不影响任何既有交互。

独立测试:先打开一条会话,Cmd/Ctrl+Click 侧边栏「新对话」按钮,验证右侧新增一个分屏展示空白新会话、原分屏保持不动;在新分屏直接发送消息验证会话正常开始;按 Cmd+Shift+N(macOS)/ Ctrl+Shift+N(Windows)验证等效;查看应用菜单栏验证存在对应菜单项并显示快捷键。

验收场景:

  1. 假设聊天区已有至少一个分屏,当用户 Cmd+Click(macOS)/ Ctrl+Click(Windows)侧边栏「新对话」按钮,则必须在聊天区新增一个分屏展示全新空白会话(工作目录取最近工作目录列表首项,与「新对话」一致),原有分屏保持不动,新分屏成为焦点分屏;普通点击(无修饰键)保持替换焦点分屏语义不变。
  2. 假设宽度或行容量不足以新增分屏,当用户 Cmd/Ctrl+Click「新对话」,则必须沿用 Cmd/Ctrl+Click 会话条目的自动溢出规则:仅一行时自动在下方新建第二行放置(窗口高度不足时才拒绝),已有两行时加入另一行(另一行也不足时才拒绝),拒绝时给出轻量提示。
  3. 假设已存在一个新会话状态(未发消息、未在生成)的分屏,当用户再次 Cmd/Ctrl+Click「新对话」,则不得重复新增,改为聚焦该分屏。
  4. 假设任一分屏正在流式生成,当用户 Cmd/Ctrl+Click「新对话」,则必须照常新增分屏(与「新对话」按钮 streaming 期间可用一致),后台会话继续生成不受影响。
  5. 假设用户按下 Cmd+Shift+N(macOS)/ Ctrl+Shift+N(Windows)或点击应用菜单栏对应菜单项,则行为必须与 Cmd/Ctrl+Click「新对话」按钮完全等效(含溢出、去重、聚焦规则)。
  6. 假设新会话分屏已并排打开,当用户在其中发送首条消息,则会话在该分屏正常开始(工作目录选择器在新会话状态照常显示,行为与「新对话」替换出的新会话一致)。

用户故事:分屏重排与调宽(优先级:P2) ​

作为用户,我希望拖拽分屏头部调整左右顺序、拖拽分屏间的分隔条调整宽度,以便把更关注的会话放在显眼位置并分配更多空间(与 Claude Code Desktop 的 pane 布局体验一致)。

为什么是这个优先级:多分屏并排后,会话的重要性与信息量不同,重排与调宽是工作台的基本布局能力;但不影响分屏的开合与独立交互。

独立测试:打开三个分屏,拖拽第三个分屏的头部到最左侧验证顺序交换;拖拽相邻分屏间的分隔条验证两侧宽度此消彼长;拖到最小宽度以下验证被钳制;新增/关闭分屏后验证已有手动宽度按比例保持。

验收场景:

  1. 假设已有至少两个分屏,当用户按住某分屏头部左右拖拽,则必须实时显示插入位置指示,放下后分屏按新顺序排列;各分屏绑定的会话与状态不随位置变化。
  2. 假设已有至少两个分屏,当用户拖拽相邻分屏之间的分隔条,则两侧分屏宽度必须此消彼长地跟随调整,且任一分屏不得小于 360px 最小宽度(拖到极限时钳制)。
  3. 假设用户已手动调整过分屏宽度,当新增或关闭分屏,则现有分屏的相对宽度比例必须保持(新增时等比压缩腾出空间、压缩后低于最小宽度则拒绝新增;关闭时释放的宽度等比分配给剩余分屏);从未手动调宽时维持等宽分配。
  4. 假设窗口变窄导致现有分屏低于最小宽度,则不得强制关闭或重排分屏(沿用分屏最小宽度既有规则)。
  5. 假设聊天区只有一个分屏,当用户按住该分屏头部拖动,则该头部不得成为拖拽源——不显示抓取光标、不起拖、不显示插入位置指示(无重排目标,也没有可移入的第二行);分屏数量达到两个及以上时头部才成为重排把手。
  6. 假设分屏头部的会话标题可点击改名(见 session-management.md「会话自定义标题(重命名)」),当用户把鼠标停在标题上,则高亮反馈只能覆盖标题文字本身(标题不撑满剩余宽度);当用户按住标题右侧的头部空白区拖拽,则必须照常起拖(标题是点击入口,不得吃掉头部的拖拽把手区域);当用户按住标题文字本身拖拽,则按点击改名优先、否决这次拖拽。

用户故事:分屏上下两行(优先级:P2) ​

作为用户,我希望把分屏拖拽到聊天区上/下边缘形成上下两行分屏,以便横向空间拥挤时利用垂直空间对照更多会话(与 VS Code 编辑器分组上下拆分的体验一致)。

为什么是这个优先级:两行布局是多分屏在有限宽度下的空间扩展;不影响单行分屏与行内既有交互。

独立测试:打开两个分屏,拖拽其中一个分屏头部到聊天区下边缘,验证显示落位区域高亮并在松手后形成上下两行;拖拽行间分隔条验证行高调整与最小高度钳制;把下行分屏拖回上行验证空行消失;已有两行时验证不再出现创建第三行的高亮。

验收场景:

  1. 假设当前仅一行且已有至少两个分屏,当用户拖拽某分屏头部悬停到聊天区的上/下边缘条带(取行高的 25% 与 48px 的较大者),则必须显示覆盖该侧一半高度的大面积半透明高亮(VS Code 编辑器分组拖拽落位高亮样式),预览「松手后此处将新建第二行」;唯一分屏的头部不是拖拽源,因此单分屏拖拽不会出现该落位高亮(把唯一分屏移到自己独占的新行等于布局不变)。拖拽侧边栏会话不受此限:单个分屏时把会话拖到边缘同样显示落位高亮,松手即新建第二行并在其中打开该会话(见本故事场景 7)。
  2. 假设落位高亮已显示,当用户松手,则被拖分屏必须移出原行并成为目标行成员:新建行时被拖分屏独占新行、原行与新行对半分出高度,行间出现可拖拽分隔条;移入已有行时按该行的列插入指示位置插入;分屏绑定的会话与状态不随位置变化。
  3. 假设已有两行分屏,当用户继续拖拽分屏悬停于最上方行的上边缘或最下方行的下边缘,则不得再显示创建新行的高亮(分屏行数上限为两行);悬停于某行内部时按该行既有列插入规则指示。
  4. 假设已存在两行,当用户拖拽行间水平分隔条,则上下行高必须此消彼长地跟随调整,且任一行不得低于 280px 最小行高(拖过极限时钳制)。
  5. 假设某行只剩一个分屏,当该分屏被拖出该行或关闭,则该行必须消失、其高度归并给剩余行;「始终保留至少一个分屏」规则不变。
  6. 假设新建第二行将导致任一行低于最小行高,当用户拖拽到边缘,则必须拒绝并给出轻量提示,布局不变。
  7. 假设用户 Cmd/Ctrl+Click 或拖拽侧边栏会话新增分屏,当已存在两行,则 Cmd/Ctrl+Click 默认加入焦点分屏所在行,焦点行宽度不足时加入另一行;仅一行且宽度不足时自动在下方新建第二行放置(窗口高度不足时才拒绝);拖拽侧边栏会话悬停到行边缘时同样显示新行落位高亮,松手即在新建行中打开该会话;拖拽松手在某行内部时直接插入该行(不做宽度拒绝,与拖拽分屏头部移入一致),仅去重规则与新增分屏一致。

用户故事:启动即单个分屏——欢迎/空态由分屏布局统一承载(优先级:P2) ​

作为桌面端用户,我希望应用启动后的「尚未开始会话」界面(欢迎页、工作目录选择、新对话输入卡)与开始会话后的界面处于同一套分屏布局——由一个未绑定会话的空分屏承载,以便会话开始前后布局稳定一致、过渡不重构,后续功能(如设置页导航替换会话侧栏)只需在分屏布局上实现。

为什么是这个优先级:当前首个会话绑定前走独立的非分屏布局,会话开始瞬间整棵布局切换(侧边栏重挂、渲染实例身份切换)——两套布局并存是「根实例 vs 分屏实例」双身份类缺陷与过渡闪烁的温床。合并为「启动即单个分屏」是对用户近乎无感的布局一致性重构:欢迎页视觉不变,收益在消除布局切换,并为后续设置页布局统一铺路。

独立测试:全新启动(无最近目录)验证主区即呈现单个空分屏(欢迎页 + 工作目录选择),无分屏关闭入口与分隔条;从欢迎态发送首条消息或直接点开历史会话,验证界面不出现布局整体切换/欢迎内容先卸载再挂载/可见闪烁,侧边栏分组展开状态不重置;布局就绪前验证只显示加载占位、不闪现非分屏布局;欢迎态与会话态分别打开/关闭设置页与会话看板,验证主区始终处于分屏布局;删除唯一分屏内的会话,验证回到与启动一致的单个空分屏。

验收场景:

  1. 假设桌面端应用启动完成(工作目录、侧边栏会话树已就绪),当查看主区,则必须呈现「单个未绑定会话的分屏」布局——分屏区容纳一个分屏,不提供分屏关闭入口与分屏分隔条;欢迎页(品牌标识、输入卡、工作目录选择器)渲染在该分屏内,与「新会话并排打开」产生的空会话分屏为同一形态。
  2. 假设用户处于启动欢迎态(空分屏内输入卡可见),当发送首条消息或从侧边栏打开一条历史会话,则该分屏就地绑定会话并开始输出;界面不得发生主区布局整体切换、欢迎内容先卸载再挂载、可见闪烁或侧边栏重建(分组展开状态与收起状态保持不变)。
  3. 假设应用启动、主区布局尚未到达(握手窗口),当查看界面,则只显示加载占位,不得闪现「欢迎页 + 侧边栏」的非分屏布局形态,也不得提前绑定历史会话。
  4. 假设用户打开设置页或会话看板后关闭,当返回主区,则回到打开前所在的分屏(空分屏或已绑定会话的分屏),与关闭前状态一致;设置页与会话看板在欢迎态与会话态下均以分屏区的替换形态呈现,不出现独立的非分屏页面布局。
  5. 假设用户处于欢迎态且侧边栏已收起(macOS 含红绿灯让位),当查看最左分屏顶栏,则「展开侧边栏」按钮与 macOS 红绿灯让位段必须与绑定会话后完全一致——让位与展开控件由最左分屏顶栏承载,欢迎态不得例外。
  6. 假设唯一分屏内展示的会话被删除或该分屏被关闭,当完成删除/关闭,则该分屏回到与全新启动一致的单个空分屏新会话态(「始终保留至少一个分屏」规则不变),仍处于分屏布局,而非回到独立的非分屏形态。

边界情况 ​

  • 会话列表与固定入口的高度竞争:侧边栏可视高度不足时,压缩只由会话列表区域承担(其可滚动高度随之变小,极端情况下逼近 0 仍可滚动),固定入口与账户卡片保持自身完整高度;不得出现固定入口被压扁、账户卡片被顶出可视区,或换成整条侧边栏一起滚动。
  • 分屏中会话被删除:侧边栏删除某会话时,展示该会话的分屏必须一并关闭;若它是唯一分屏,则该分屏回到新会话状态(始终保留至少一个分屏,不销毁其他分屏的 agent)。
  • 窗口缩窄:窗口变小导致现有分屏低于最小宽度时不强制关闭分屏,最小宽度仅约束「新增分屏」与「手动调宽」动作。
  • 已打开面板的分屏旁再拖入会话:面板组为会话级,同一会话同一时刻仅在一个分屏显示,不存在跨分屏共享实例;新增分屏的最小宽度校验在扣除各分屏已打开面板宽度后的剩余空间内计算,不足时同样拒绝新增。

非目标(明确排除) ​

  • 分屏布局跨重启持久化:重启应用回到单分屏新会话状态(与每次启动全新开始一致)。
  • IDE 插件端分屏:并排多对话为 desktop 独有,VSCE/JetBrains 维持单视图。
  • 分屏内标签页:一个分屏同一时刻只绑定一条会话,不做分屏内多标签。
  • 三行及以上的布局:分屏区最多两行;分屏内部的面板仅一行(消息区右侧并排),不换行到第二行。
  • 分屏两行布局跨重启持久化:分屏行划分与行高随「每次启动全新开始」规则不持久化。