fix(web): 修复会话工作台三栏布局、命名与日志历史 - #48
Merged
Merged
Conversation
ZER-715. Read-only session workbench polish. P0-1 layout - Both side columns now share one --workbench-side-width token. They were minmax(260px, 300px) and minmax(280px, 340px), so they never lined up. - Exactly one seam per centre-column edge. .workbench-inspector cleared its own border-inline-end, so the centre/right edge had no seam at all while the left seam stayed visible. - Both side panels collapse to a narrow rail on desktop. - Mobile drawers use .workbench-mobile-drawer, the class the stylesheet actually defines; they previously used an undefined .workbench-drawer. P0-2 naming - The sidebar groups by project directory instead of agent type, and rows show a task title instead of the raw "slack:alpha" session id. - Titles prefer a transcript-derived task name, then the profile name, then "Agent - short id". Source and thread moved to the subtitle. P0-3 status - A compact run indicator replaces the running/idle tag pair: a spinner while the session is running, otherwise the time since the last run. - Removed the duplicated stream status block from the main panel footer. P1-4 inspector - Dropped the standalone alerts tab. Profile config warnings now render inline next to the metadata they describe. P1-5 log history - The page kept a client-only ['sessionTimeline'] query that never fetched anything and was seeded with one or two synthetic items, so a session that had run many times only ever showed the first couple of entries. The log now renders the server-backed transcript history. - The transcript stream is owned by the page so the activity feed and the log share a single SSE connection. Validation: pnpm lint (tsc --noEmit), pnpm test (66 tests, 11 files), pnpm build.
ZeroPointSix
commented
Aug 15, 2026
ZeroPointSix
left a comment
Owner
Author
There was a problem hiding this comment.
本轮审查发现 1 个合并前阻塞项:当前实现没有让侧边栏的所有会话显示任务标题,因此不满足 Review Contract 中“行内显示任务标题”的验收标准。由于当前 GitHub 连接账号是 PR 作者,平台不允许提交 REQUEST_CHANGES,故以 COMMENT review 留痕。请修复内联问题并补回归测试后再复审。
P1 residual from PR #48 review: even after SessionSnapshot.title is populated by the list API, SessionSidebar still only passed a derived title for the active row. Inactive same-profile sessions therefore kept falling back to profile_name and stayed indistinguishable. Pass session.title for non-active rows, keep the live transcript title for the selected session, and add a regression test that two same-profile sessions keep distinct list titles. Co-Authored-By: Claude <noreply@anthropic.com>
admin_api_integration expected SessionSnapshot.agent to equal the
profile agent_type slug ("claude"), but the snapshot field is filled
from ACP initialize agentInfo.name. The fake agent announces
"fake-claude-acp", so assert that value and keep profile_id as the
profile-binding check.
Co-Authored-By: Claude <noreply@anthropic.com>
ZeroPointSix
commented
Aug 15, 2026
ZeroPointSix
left a comment
Owner
Author
There was a problem hiding this comment.
重新审查最新提交:后端 title 派生、列表 API、前端回退/SSE 保留和 transcript 日志链路均闭合;原 P1 已解决,Admin Web、workspace CI、两组 clippy、ACP 测试和 unified 构建均通过。仅留一项非阻断的 P2 无障碍意见。
Desktop main-panel buttons collapse expanded side panels, but their aria-labels always said “打开…”. Pass state-aware labels from the page and rename the props to onToggle* so the control semantics match. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What problem does this solve?
Closes: 无对应 GitHub issue —— 本改动追踪于 Linear ZER-715 优化前端效果。本仓库没有对应 issue,因此
Closes #刻意不填数字,避免误关闭无关 issue。Discord Discussion URL: 待补充 —— 尚未从需求提出方取得。为此本 PR 以 draft 形式打开,链接补齐后立即转正式评审;见
### Follow-ups。PR #47 上线的只读会话工作台(
/admin#/sessions)在实际使用中暴露 5 个缺陷,全部来自使用方反馈:slack:alpha这类原始 session id,并按 agent 类型分组。第 1–4 条是观感/信息架构问题;第 5 条是功能性 bug,日志面板从未接过真实数据。
Review Contract
Goal
只读会话工作台的可读性收口:三栏几何对称、分隔线成对、左右栏可折叠;侧边栏以“项目 + 任务标题”而非原始 session id 组织;运行状态收敛为一个紧凑指示器;移除空壳
告警tab;日志面板改接服务端 transcript 全量历史。Non-goals
SessionSnapshot持久状态;会话列表从 transcript 内存数据附带轻量title字段。推理强度相关的展示/配置改造(需求方明确要求本轮不做:“当然这个先不是我们重要的,我们先优先改绘画这个界面吧”)。app.js体积告警是既有状态)。Accepted Residual Risks
--workbench-side-widthtoken 保证,属结构性修复而非数值微调,因此风险可接受。SessionEventLog渲染纯文本摘要(单条截断 160 字符,换行压平为⏎)。结构化 tool_call / tool_result 的富展示仍由时间线与活动流承担,日志面板刻意保持“只读文本流”定位。useSessionStream仍在 invalidate 已不再使用的['sessionTimeline']query key。 无副作用(无人订阅该 key),本 PR 不顺手清理以保持单一变更范围,见 Follow-ups。Acceptance Criteria
--workbench-side-widthtoken)。.workbench-mobile-drawer类。platform · thread_id降级为副标题。告警tab 消失,profile_config_errors内联在元数据tab 中。pnpm lint(tsc --noEmit)零错误。pnpm test全绿(11 文件 / 66 用例)。pnpm build成功,并按仓库惯例提交 promote 后的产物。Follow-ups
推理强度展示与配置:本轮按需求方要求推迟,不并入本 PR。useSessionStream中已失效的['sessionTimeline']invalidate,并一并评估SessionEventTimeline是否仍需保留。At a Glance
Prior Art & Industry Research
nesquena/hermes-webui采用 “three-panel Claude-style layout with sessions sidebar, chat, and workspace file browser”,与本仓库三栏结构同构;其特性列表明确包含 “Session projects, tags, and tool call cards” —— 即以项目维度组织会话,直接支持本 PR 的 P0-2。xmanrui/OpenClaw-bot-review明确采用“按 Agent 浏览所有会话”,并单独设置“告警中心”—— 与本 PR 的两项决定相反。仍然选择偏离,理由是:(a) 我们的 agent 维度基数极低(实际只有 codex / claude 两三种),分组后几乎不产生区分度,而workdir项目维度才是使用方真正用来定位会话的;(b) OpenClaw 的告警中心有真实多源内容(模型不可用、机器人无响应等可配置规则),而我们的告警tab 唯一数据源是profile_config_errors,内联到元数据旁边信息密度更高。manaflow-ai/cmux#149 “Sidebar loading indicator when AI coding agent is working” 与anomalyco/opencode#14400 均独立提出“侧边栏用 spinner 指示 agent 正在工作”。说明 P0-3 的 spinner 化不是个人偏好,而是这类工具的收敛设计。Proposed Solution
P0-1 布局(
styles.css、SessionWorkbenchPage.tsx)--workbench-side-width: 300px、--workbench-rail-width: 44px、--workbench-seam三个 token。grid-template-columns左右两侧同时引用--workbench-side-width,消除minmax(260px,300px)vsminmax(280px,340px)的不对称根因。.workbench-sidebar只出border-inline-end,.workbench-inspector只出border-inline-start。原实现把两栏一起赋border-inline-end后又用.workbench-inspector { border-inline-end: 0 }抹掉,导致中栏右侧完全无缝、左侧有缝 —— 这就是被看成“划痕”的来源。is-sidebar-collapsed/is-inspector-collapsed状态类,把对应列压到导轨宽度,配合.workbench-rail与展开按钮。.workbench-drawer,改为真实定义的.workbench-mobile-drawer。P0-2 命名(
lib/session.ts、SessionSidebar.tsx)新增
sessionProjectGroup():取workdir末段目录名,空值回退未归类项目。分组从 agent 维度切到项目维度。后端
SessionTranscriptStore从首条 user 消息派生并缓存最多 48 字符的标题,会话列表接口随 snapshot 返回title。sessionListTitle(session, derivedTitle?)的优先级为:详情页派生标题 → 列表接口session.title→profile_name→Agent · 短 id;SSE snapshot 更新时保留已有标题。侧边栏 caption 改为
按项目分组 · N 条,nav aria-label同步为按项目分组的会话。P0-3 状态(
SessionRunIndicator.tsx、StatusTag.tsx、SessionMainPanel.tsx)新增
SessionRunIndicator:display.running为真时渲染 spinner,否则渲染上次运行 <相对时间>,外套 Tooltip 显示绝对时间。StatusTag的running图标由静态CheckCircleFilled改为LoadingOutlined spin(该组件在其他页面仍在使用,故保留而非删除)。删除主面板底部重复的
workbench-stream-status块。侧边栏行内的
StatusTag换成 6px 状态点,title/aria-label仍取自sessionStatusDisplay,保住可访问性。P1-4 检查器(
SessionInspector.tsx)告警tab 及其AlertItem/isAlertItem()/AlertOutlined,profile_config_errors以<Alert>内联到元数据tab 中它所描述的元数据旁边。P1-5 日志(
SessionEventLog.tsx、SessionWorkbenchPage.tsx)—— 真正的 bug['sessionTimeline', id]query,它从不发起任何请求,只被一个useEffect用initialTimeline播种 1–2 条合成条目。因此不论会话实际运行多少次,日志面板永远只有那两条。initialTimeline导出;SessionEventLog的 prop 由timeline: SessionTimelineItem[]改为entries: TranscriptEntry[],按sequence排序渲染服务端 transcript 全量历史。useSessionTranscript(sessionId)的调用上提到页面层,经 prop 下发给主面板与检查器。此前主面板自己也调用了一次,等于对同一会话开了两条 SSE 连接。Why this approach?
340px改成300px,下一次有人再动其中一侧就会重新裂开。agentDisplayName/sourcePlatformLabel都是lib/format.ts里既有的函数,本 PR 没有新造命名体系。Alternatives Considered
SessionTimelineItem补一个真实的后端接口。 需要后端配合新增 endpoint,而 transcript 接口已经提供了完全够用的全量历史,属重复建设。已否。告警tab,只在无内容时隐藏。 需求方的判断是“如果说没有这些作用的话,你就不要展示出来”;条件隐藏会让 tab 位置在有/无告警时跳动,信息密度也不如内联。已否。Splitter做可拖拽分栏替代折叠。 交互更强,但引入拖拽状态持久化与尺寸问题,超出本轮“观感收口”的范围。已否,可作为后续独立提案。Validation
在
kuoya-sgp-001上于web/目录执行,全部通过:pnpm install --frozen-lockfilepnpm lint(tsc --noEmit)pnpm test(vitest run)pnpm build(vite build && promote-build)lib/session.test.ts由 10 个用例扩到 14 个,新增覆盖sessionProjectGroup(含workdir: ''→未归类项目)、titleFromTranscript(含空数组 →undefined、首尾空格 trim)、以及sessionListTitle的三级回退。原有 9 个用例逐字保留未改。hooks/useSessionTranscript.test.ts、lib/transcript.test.ts均未回归。promote-build.mjs产出的web/app.js与web/styles.css(与afea34b、47082e4一致);web/index.html内容未变化。### Accepted Residual Risks。