Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions docs/specs/right-edge-rail/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# 右侧图标栏 + 右栏分区改造 — 总览

参考 openchamber 的右侧竖排图标栏形态,对 codeg 工作区做两项改造:

> 参考效果图(openchamber 右栏 + 最右图标栏):[openchamber-reference.png](./openchamber-reference.png)
> — 右栏自上而下为:会话(上下文 %)、项目(agents)、轮次统计、**子代理**(可折叠、
> 右侧计数、每行"名称 + 状态")、**任务**("已完成/总数"进度 + 每行任务);
> 最右缘为全高竖排图标栏。

1. **最右侧竖排图标栏**:取代现在钉在窗口右上角的横排按钮(终端 / 右栏开关 / 设置),
变成贴窗口右缘、全高、占位的独立竖条;右栏各 tab 直达。
2. **右栏"会话详情"tab 内新增分区**:把消息区左上角浮动的"智能体计划"任务列表与
子代理列表,以分节形式并入右栏会话详情(浮层本身保留)。

## 分期

| 期 | 内容 | spec |
|---|---|---|
| s1 | 最右侧竖排图标栏(新组件 + 挂载 + 退役旧右上角簇) | [s1-right-edge-rail.md](./s1-right-edge-rail.md) |
| s2 | 清理右缘避让机制(window-chrome 常量、aux tab 条塌陷逻辑) | [s2-reserve-cleanup.md](./s2-reserve-cleanup.md) |
| s3 | 会话详情 tab 新增"任务"与"子代理"分区 | [s3-session-details-sections.md](./s3-session-details-sections.md) |
| s4 | i18n 十语言文案 + 测试与验收 | [s4-i18n-acceptance.md](./s4-i18n-acceptance.md) |

## 已确认的决策(用户拍板)

- 任务列表以**会话详情 tab 内分区**呈现(不另开 tab、不合并成新 tab)。
- 消息区左上角的浮动计划卡 / 子代理浮层**保留**,与右栏分区数据同源。
- 图标栏内容:**右栏各 tab + 终端 + 设置**;左栏切换仍留在左上角 `LeftEdgeChrome`。
- 图标栏实现:**占位的独立竖条**(布局中真实的右缘列,非 fixed 悬浮),
Windows/Linux 原生标题按钮保持 fixed 于右上角,图标栏顶部预留 `h-10` 拖拽区让位。

## 关键现状(探索结论)

- 右上角横排按钮:`src/components/layout/right-edge-chrome.tsx`,
由 `src/app/workspace/layout.tsx:1217-1231` 以 fixed overlay 钉住。
- 避让体系:`src/lib/window-chrome.ts` 的 `RIGHT_CHROME_CLUSTER=116` /
`rightChromeReserve` / `rightChromeClusterWidth`,消费方:
`workspace/layout.tsx:328`(中列 reserve)、`conversation-detail-panel.tsx:2331`、
`aux-panel.tsx:192`(tab 条塌陷 `shouldCollapseAuxTabs`)。
- 右栏:`src/components/layout/aux-panel.tsx`,4 tab;状态在
`src/contexts/aux-panel-context.tsx`(`AuxPanelTab`、localStorage
`workspace:right-sidebar`)。
- 浮动任务卡:`src/components/chat/agent-plan-overlay.tsx`;子代理浮层:
`src/components/chat/sub-agent-overlay.tsx`;共栈容器在
`src/components/message/message-list-view.tsx:1612-1644`。
- 子代理数据:`extractDelegationSources`(`message-list-view.tsx:409-467`)、
`useDelegationCardModel`、`src/contexts/delegation-context.tsx`。
- 会话详情 tab:`src/components/layout/aux-panel-session-details-tab.tsx` →
`SessionDetailsContent`(`src/components/conversations/session-details-content.tsx`)。

## 不动的东西

- 后端 / Rust 层零改动;数据全部来自既有 store/context。
- 移动端(`MobileFolderWorkspaceShell`、`folder-title-bar.tsx`、抽屉)不动。
- 快捷键语义(`toggle_aux_panel`、`toggle_terminal`、`open_settings`)不变。
- 左栏 `LeftEdgeChrome`、`WindowControls`、`StatusBar` 位置不变。
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions docs/specs/right-edge-rail/s1-right-edge-rail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# s1 — 最右侧竖排图标栏

## 目标

新建贴窗口右缘、全高、占位的竖排图标栏,取代 `RightEdgeChrome` 的右上角横排按钮。
形态对齐 openchamber:一列图标,点哪个面板开哪个,当前激活项高亮。

## 新组件

`src/components/layout/right-edge-rail.tsx` — `RightEdgeRail()`

- 结构:`<aside>` 竖排 flex 列,宽 `RIGHT_EDGE_RAIL_WIDTH`(见 s2,默认 40px),
全高,右边框分隔,背景与右栏 strip 一致(`bg-muted` + `ws-*` 背景图规则对齐)。
- 顶部 `h-10 shrink-0` 预留区,`data-tauri-drag-region`:
Windows/Linux 原生标题按钮(`WindowControls`,仍 fixed 右上角)压在这段上,
macOS/其他 则该段也可拖窗。
- 图标按钮自上而下(桌面,`isConversations` 路由):
1. `session_details` — `ReceiptText`
2. `file_tree` — `Folder`
3. `changes` — `FolderPen`
4. `git_log` — `GitCommit`
5. 分隔线(`h-px bg-border my-1`)
6. 终端开关 — `SquareTerminal`
7. 设置 — `Settings`
- tab 图标点击行为:
- 面板未开 → `openTab(tab)`;
- 面板已开且 `activeTab === tab` → `toggle()` 收起右栏(点当前高亮项 = 关闭);
- 面板已开但 tab 不同 → `setActiveTab(tab)`。
- 无文件夹 / chat 模式(`showFolderTabs === false` 条件,即
`activeFolderId == null || isChatMode`):只显示 `session_details` 图标,
`file_tree/changes/git_log` 隐藏(与 `resolveAuxTabView` 同一判定)。
- 终端图标:`toggleTerminal()`,`activeFolder` 为空时禁用;激活态样式同旧
`bg-accent`。
- 设置图标:`openSettingsWindow()`。
- 激活高亮:当前 `activeTab`(面板开)对应 tab 图标加 `bg-accent text-foreground`;
其余 `text-foreground/70 hover:bg-foreground/10`。图标 `h-4 w-4`。
- tooltip:复用 `Folder.folderTitleBar.withShortcut` + 各 tab 标签;
终端/设置沿用 `toggleTerminal` / `openSettings` + 快捷键提示。
tab tooltip 用 `Folder.auxPanel.tabs.*` 与 `Folder.sessionDetails.menuLabel`。
- 整页路由(`!isConversations`):隐藏 tab 组与终端图标,渲染
`WorkbenchRouteChromeActions`(沿用其现有 props)+ 设置图标,居中竖排。

## 挂载改造

`src/app/workspace/layout.tsx`:

- `FolderWorkspaceShell` 的 shell `ResizablePanelGroup` 之后(同一 flex 行内、
组外)追加 `<RightEdgeRail />`,作为**非缩放占位列**:
shell 容器 `buildShellLayout` 用 `shellWidth`(shellContainerRef 实测)换算,
图标栏放在 shell 组外层 flex 兄弟位,避免参与 resizable 计算。
实现上:`FolderWorkspaceShell` 返回结构外层已是 flex row
(`ResizablePanelGroup` + 预留常量),把 rail 作为最后一个 flex 子项、
`shrink-0`,容器宽度即从 `shellWidth` 中扣除(由 flex 自然完成)。
- `FolderLayoutShell`(1217-1231)删除 `RightEdgeChrome` 挂载与
`right: winLinuxControls ? WINDOW_CAPTION_WIDTH : 0` 定位 div;
保留 `LeftEdgeChrome`、`WindowControls` 两个 overlay。
- `right-edge-chrome.tsx` 删除;`WorkbenchRouteChromeActions` import 移到 rail。
- 中列(`WorkspaceContent` 的 `convReservesRight/fileReservesRight`):
AuxPanel 不再被 overlay 压住,右缘 reserve 改为按"rail 实际占位"扣减——
rail 是占位列,**中列不再需要右 reserve**;相关 reserve 清理归 s2 统一处理,
s1 先保证视觉正确(rail 占位后 overlay 删除)。

## 验收

- [ ] 桌面三平台位:Windows/Linux 标题按钮压在图标栏顶部预留区内,不互相遮挡;
拖该区域可移动窗口。
- [ ] 四个 tab 图标点击可开/切/关右栏,激活高亮随 `activeTab` 变化。
- [ ] chat 会话与无文件夹态只显示会话详情图标。
- [ ] 终端图标开关底部终端面板;设置图标打开设置。
- [ ] 整页路由(任务/自动化)下 tab/终端图标消失、显示路由页控件 + 设置,无错位。
- [ ] 右栏开/关、左栏开/关、缩放(zoomLevel 90/150)下图标栏不重叠、不被裁剪。
- [ ] 快捷键 `toggle_aux_panel` 行为不变。
- [ ] `pnpm eslint .` 通过;新组件有渲染单测(各态图标显隐、点击 → context 调用)。
65 changes: 65 additions & 0 deletions docs/specs/right-edge-rail/s2-reserve-cleanup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# s2 — 清理右缘避让机制

## 背景

旧设计里右上角 chrome 是 fixed overlay,浮在"当前右缘列"(AuxPanel 或中列)之上,
所以各处要 `rightChromeReserve` 预留宽度。s1 把 chrome 变成**占位竖条**后,
overlay 不复存在,这套避让全部作废。本期待清干净,避免留下"幽灵留白"。

## 清理清单

`src/lib/window-chrome.ts`:

- 删除 `RIGHT_CHROME_CLUSTER`、`rightChromeReserve`、`rightChromeClusterWidth`。
- 新增 `export const RIGHT_EDGE_RAIL_WIDTH = 40`(rail 占位宽,供
`window-controls` 对齐、测试与文档引用;rem 缩放不适用——rail 图标固定 px 尺寸
或用常量派生,实现时若需随缩放增长,参照 `scaleCluster` 加
`rightEdgeRailWidth(zoom)`)。
- `WINDOW_CAPTION_WIDTH`、macOS/左侧常量不动。
- `src/lib/window-chrome.test.ts`:删除 right 侧三组断言,补 rail 常量断言。

`src/components/layout/aux-panel.tsx`:

- `shouldCollapseAuxTabs` 删除 `rightReserve` 形参(仅剩 panel 宽 vs 分段控件宽),
或整体保留函数但传 0——**选择删除形参**,同步 `aux-panel.test.tsx`:
合并 `WIN_LINUX_RESERVE` 用例(不再有 win/linux 差异),保留
"宽面板不塌陷 / 窄面板塌陷 / 未测量不塌陷"。
- 删除 `rightChromeReserve` import 与 `rightReserve` 计算;tab 条右缘拖拽区不变。
- 顶部注释(66-77 行说明文字)同步改写:塌陷只由面板自身宽度决定。

`src/app/workspace/layout.tsx`:

- `WorkspaceContent`:删除 `rightReserve`、`convReservesRight`、`fileReservesRight`
及把 reserve 传给列头的逻辑(列头不再为右缘留白)。
`leftReserve` 保留(左 overlay 仍在)。
- `FolderLayoutShell`:确认已无 `RightEdgeChrome`(s1 完成),
`WINDOW_CAPTION_WIDTH` 仅 `WindowControls` 用。

`src/components/conversations/conversation-detail-panel.tsx:2331`:

- 该处 `rightChromeReserve` 用于会话面板头部避让右 overlay——
overlay 没了,删除该 reserve;`leftChromeReserve` 保留。

`src/components/tasks/tasks-chrome-actions.tsx:23`:

- 注释提到 `RIGHT_CHROME_CLUSTER`,改为指向 rail(s1 的
`WorkbenchRouteChromeActions` 新落点)。

`src/contexts/aux-panel-context.tsx`:

- `resolveAuxMinWidth`:Windows/Linux 的 260 下限起因是"overlay + caption 不溢出到
中列";rail 占位后右栏不再被 overlay 压,但 caption 按钮仍 fixed 在右上且
Win/Linux 下宽 138px > rail 40px——caption 只压 rail 顶部预留区(40px 内),
**不**再需要为 caption 撑宽右栏。minWidth 统一回 `MIN_WIDTH=200`;
删除 `resolveAuxMinWidth`/`detectPlatform` 相关分支(若平台 hook 因此无他用以
一并清理 import,注意 `noUnusedLocals`)。

## 验收

- [ ] 全库 `rg rightChromeReserve|RIGHT_CHROME_CLUSTER|rightChromeClusterWidth` 零命中。
- [ ] 右栏最窄拖到 200px:tab 条塌陷为下拉 picker(mac/win 行为一致),
内容不溢出、不被 rail 遮挡。
- [ ] 右栏关闭时中列(会话/文件列)头部不再多出 116/138px 幽灵留白。
- [ ] zoom 90/150 无回归(左 overlay 仍正常避让)。
- [ ] `pnpm eslint .`、`pnpm test` 通过;`window-chrome.test.ts`、`aux-panel.test.tsx`
更新后全绿。
79 changes: 79 additions & 0 deletions docs/specs/right-edge-rail/s3-session-details-sections.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# s3 — 会话详情 tab 新增"任务"与"子代理"分区

## 目标

右栏"会话详情"tab(`aux-panel-session-details-tab.tsx`)在现有
`SessionDetailsContent` 之下新增两个分区,样式对齐 openchamber:
小节标题行(图标 + 名称 + 右侧计数),其下逐行列出条目。

- **任务**:当前会话最新的智能体计划(TodoWrite / plan block)。
- **子代理**:当前会话委派出去的子代理列表。

消息区左上角的浮动 `AgentPlanOverlay` / `SubAgentOverlay` 保留不动。

## 共享件抽取

1. `src/lib/delegation-sources.ts`(新)
- 把 `message-list-view.tsx:409-467` 的 `collectDelegationSources` /
`extractDelegationSources` 原样迁入(依赖的 `isDelegateToAgentToolName`、
`isRefusedResume`、`parseResumeTaskId`、`normalizeToolName` 留在原模块或一并迁入)。
- `message-list-view.tsx` 改 import,行为零变化(有既有测试兜底)。
2. 计划行共享组件
- `agent-plan-overlay.tsx` 抽出 `StatusIcon` 与单条目行
(状态图标 + 文案 + 状态/优先级 Badge)为 `PlanEntryRow`,
放 `src/components/chat/plan-entry-row.tsx`;浮层与右栏分区共用。
- 浮层现有视觉不得变化(回归看现有测试 + 快照)。

## 右栏数据接入(`aux-panel-session-details-tab.tsx`)

当前活动会话解析逻辑(tab → runtimeConversationId → `byConversationId`)已在此文件,
新分区挂在同一组件里:

- **任务分区**:
- 实时:`liveMessage`(runtime store 已有)→ `getLatestPlanEntries`
(从 `agent-plan-overlay.tsx` 一并导出或迁入共享模块)。
- 历史回退:live 无 plan 时,用 `src/lib/agent-plan.ts` 从已加载 turns
(`localTurns`)解析最近一次 plan-like 工具调用(与 `message-list-view`
传给浮层的 `entries/planKey` 同一函数)。
- 计数:`completed/total`。无计划时分区整体隐藏(与浮层一致:没数据不占位)。
- **子代理分区**:
- 数据:`DelegationContext`(`delegation-context.tsx` 的绑定 map)中
`parentConversationId === 当前会话` 的绑定,∪ 最近 assistant turn 的
`extractDelegationSources`(turns 来自 runtime store 的会话 detail/turns,
与浮层同源;两者按 `parentToolUseId`/taskId 去重合并)。
- 行渲染:复用 `SubAgentOverlay` 的行视觉——把其 `SubAgentOverlayRow` 抽成
导出组件 `DelegationRow`(`src/components/chat/delegation-row.tsx`),
两处(浮层 + 分区)共用;点击经 `useSessionViewerHost` 打开子会话
(aux-panel 不在 `MessageListView` 内,host 为 `null` 时走
`SubAgentSessionDialog` 本地兜底——该组件已支持此态)。
- 计数:条目数。列表为空时分区隐藏。
- 空态:两个分区都空时,只显示原会话详情内容,不出现空小节标题。

## 视觉规格

- 分区标题行:`text-xs font-medium uppercase tracking-wide text-muted-foreground`
(与 `SessionDetailsContent` 的 `tokensHeading` 小节一致)+ 左侧小图标
(任务 `ListTodoIcon`、子代理 `BotIcon`)+ 右侧计数(`text-xs text-muted-foreground`)。
- 分区间以 `border-t pt-4` 分隔;任务条目复用 `PlanEntryRow`;
子代理条目复用 `DelegationRow`(去掉外层卡片的 `border`,改列表行)。
- 全部置于既有 `ScrollArea` 内(跟随 `SessionDetailsContent` 一个滚动容器,
不另开滚动区)。

## i18n key(文案实体在 s4)

- `Folder.sessionDetails.tasksHeading`("任务")、
`Folder.sessionDetails.subAgentsHeading`("子代理")。
- 行内状态/优先级/状态 Badge 复用 `Folder.chat.agentPlanOverlay.*` 与
`Folder.chat.delegation.*` 现有 key。

## 验收

- [ ] 流式会话中智能体创建/更新计划 → 右栏任务分区实时跟随更新;
浮层同步更新,两处计数一致。
- [ ] 打开历史会话(含 TodoWrite 计划)→ 无 live 时右栏显示回退解析的计划。
- [ ] 子代理运行中显示运行态图标,完成/失败状态与消息流内委派卡一致;
点击行打开子会话查看器。
- [ ] 切换 tab / 切换会话时分区随活动会话切换(复用 tab store 的 activeTabId)。
- [ ] 右栏收起时中列浮层照常工作(回归);浮层展开/折叠互不影响。
- [ ] 新单测:live→历史回退优先级、去重合并、空态隐藏、点击打开 viewer;
`pnpm eslint .`、`pnpm test` 全绿。
56 changes: 56 additions & 0 deletions docs/specs/right-edge-rail/s4-i18n-acceptance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# s4 — i18n 十语言文案 + 最终验收

## 新增文案

命名空间 `Folder.sessionDetails`,新增 2 个 key(10 个语言文件同步):

| key | en | zh-CN |
|---|---|---|
| `tasksHeading` | Tasks | 任务 |
| `subAgentsHeading` | Sub-agents | 子代理 |

译文约定(对齐各语言既有同概念文案,不自造词):
- zh-TW:任務 / 子代理;ja:タスク / サブエージェント;
ko:작업 / 하위 에이전트;参照各文件既有关键词。
- es/fr/pt/ar/de:`es.json` "Tareas"/"Subagentes"、`fr.json` "Tâches"/
"Sous-agents"、`pt.json` "Tarefas"/"Subagentes"、`de.json` "Aufgaben"/
"Unter-Agenten"、ar 参考既有 `Folder.chat.subAgentOverlay.title` 译法。

图标栏 tooltip 全部复用现有 key(`Folder.folderTitleBar.*`、
`Folder.auxPanel.tabs.*`、`Folder.sessionDetails.menuLabel`),不新增。
`Folder.chat.agentPlanOverlay.*` / `Folder.chat.delegation.*` 复用,不新增。

各语言文件的插入位置:对应 `Folder.sessionDetails` 对象内、按 en.json 的键序
就近插入(tokensHeading/timestampsHeading 之后)。

## 测试与验收命令

```bash
pnpm eslint .
pnpm test # vitest 全量
pnpm build # 静态导出
```

## 总体验收清单

视觉(桌面 Windows,桌面实跑截图对照 openchamber 参考图):

- [ ] 窗口右缘出现全高竖排图标栏:4 个右栏 tab 图标 + 分隔线 + 终端 + 设置;
顶部 h-10 与原生标题按钮共存,可拖窗。
- [ ] 原右上角横排按钮簇消失;左缘切换按钮不变。
- [ ] 打开右栏 → 图标栏上当前 tab 高亮;点高亮项收起右栏。
- [ ] 右栏会话详情 tab 内:标识/token/时间戳之后出现"子代理"与"任务"分区
(有数据才显示),条目与消息区浮层一致,点击子代理行打开子会话。
- [ ] 消息区左上角浮动计划卡/子代理浮层仍在,功能不变。
- [ ] chat 会话、无文件夹、整页路由(任务看板/自动化)、zoom 90/150、
右栏 200px 最窄 各态无布局破损。
- [ ] 移动端窗口(<768px)与 server/web 模式正常(rail 仅桌面渲染)。

代码:

- [ ] s1/s2/s3 各自验收项全过。
- [ ] `rg rightChromeReserve|RIGHT_CHROME_CLUSTER|rightChromeClusterWidth` 零命中。
- [ ] `rg right-edge-chrome` 零命中(组件删除后无残留 import)。
- [ ] eslint / vitest / build 三件套全绿;新增测试覆盖:rail 渲染与点击、
shouldCollapseAuxTabs 新签名、分区数据合并、extractDelegationSources
迁移后回归。
Loading
Loading