Web Shell sidebar and standalone session actions
贡献角色Issue 认领者、修复实现者与验证者;已修复上游审查的 Critical,并按后续建议提交修改;新 head 的 CI 与复审进行中
先离开当前无工作区会话,再安全删除
Web Shell 原先禁用当前无工作区会话的删除入口,因为 daemon 会拒绝删除仍有客户端附着的会话。我的修复仅允许空闲时发起删除,在确认后等待严格校验的 detach 完成,再按原 ID 删除;其他标签页仍在使用时,服务端保护继续生效。上游审查发现删除未结束时弹窗仍可关闭,我修复这一竞态,并通过暂停真实 daemon 请求验证。之后又按审查建议提交了后续修改;PR 仍开放,新 head 的 CI 与复审正在进行。
- Issue
- #12669
- Pull Request
- #12738
- 本次贡献的提交
- e226eb362d删除当前无工作区会话前先完成离开cf7377b6ef补充端到端验证截图与说明588cb890fd删除期间锁定确认弹窗的关闭入口a2b39eb405按审查建议补充删除进度、就绪状态和回归测试
- 涉及模块
- Web Shell sidebar and standalone session actions
项目与系统背景
Web Shell 在侧栏列出无工作区会话。daemon 会拒绝删除仍有活动提示或客户端附着的会话;批量删除接口在 HTTP 200 响应的逐项 errors[] 中报告 session_busy。
较早的 #12636 改动禁用了当前行的 Delete。维护者将先离开再删除的另一方案留给后续 Issue #12669。当前标签页可以 detach,但其他标签页仍可能附着在同一会话上。
问题表现与影响
在未修改的源码基线上,当前无工作区会话行虽然显示 Delete,却始终禁用。若只放开按钮,本标签页仍附着时就会请求删除,并收到 daemon 的 session_busy。
普通 New task 的返回值不能证明 detach 成功:clearSession 会吞掉 detach 异常,SDK 在缺少 clientId 时还会把 detach 当作空操作。侧栏列表计数也可能滞后于实时状态。
上游对 PR 首版的审查另发现一项 Critical:异步 detach 或删除进行中,Cancel 等关闭入口仍能关掉确认弹窗,但删除会继续执行。
问题原因
客户端缺少一条针对当前行的有序流程:先确认删除,再离开准确的原会话,证明 detach 已完成,最后请求删除固定的原 ID。daemon 的繁忙保护本身正确,应当保留。
已有回调丢弃了 New task 的执行结果,而普通 clearSession 路径可能掩盖 detach 失败,两者都不足以充当删除请求的前置保证。
修复方案
侧栏两处 Delete 入口现在允许空闲的当前无工作区会话进入原有确认框。确认时再次检查 App 实时运行状态和原会话 ID;运行中的工作仍受保护。
删除专用、可等待的回调复用 createNewSession({ kind: 'global' }),并启用严格的 clearSession 检查:要求预期会话 ID 和两处匹配的非空 clientId,上报 detach 失败,等待 detach 完成后才按固定原 ID 请求批量删除。
只有 removed 或 notFound 才移除列表行。逐项 session_busy 或请求失败时保留行并提示错误;已离开时还会刷新列表。daemon 的繁忙保护及独立的 /delete 选择器均未修改。
上游审查后,我在操作期间禁用弹窗的所有关闭入口,并为 onClose 加上同步 busy 防护;detach 或删除未结束时确认弹窗保持可见。
按审查建议,提交 a2b39eb405 在删除进行中显示进度(Deleting... 与 aria-busy),会话附着就绪前保持 Delete 禁用,把离开失败和导航取消统一成同一条提示,移除可选回调的无效分支,并补上重试、刷新和严格 detach 的回归测试;英文和中文设计文档同步更新。
设计取舍
只有用户确认后才开始离开,因此取消对话框不会触发 detach。操作锁定一个原 ID,严格 detach 未完成或失败时绝不发送删除请求。
界面不依据可能过期的 clientCount 提前禁用删除。若另一标签页使会话仍然繁忙,交由 daemon 判定;没有强制删除或无条件重试来削弱这层保护。
已确认的删除不能在异步工作继续时呈现为已取消。审查后加入的 busy 防护关闭了这处界面竞态,没有改变 daemon 的删除规则。
验证证据
- 01
首版修复前,基线组件测试确认当前行的 Delete 被禁用。首版实现后,四个定向测试文件的 1570 项测试全部通过,全仓类型检查和构建通过。最初的本地 code review 未发现后来由上游指出的弹窗竞态。
- 02
使用隔离真实 daemon、构建后的 Web Shell 与 Chrome 验证了单标签顺序:取消确认不发送请求;确认后先收到 detach HTTP 204,再收到批量删除 HTTP 200,removed 含原 ID,列表行消失。
- 03
双 Chrome context 下,第一标签页 detach 后 clientCount 从 2 降至 1,随后批量删除以 HTTP 200 返回 errors[] 中的 session_busy;原行保留,页面显示错误。第二标签页 detach 后计数从 1 降至 0,从保留的对话框重试成功移除该行。detach 故障注入与活动提示由定向测试覆盖,未在本次真实运行中验证。
- 04
针对上游 Critical,旧版在暂停真实 daemon detach 期间可复现误导性的 Cancel,放行后删除仍继续。提交 588cb890fd 的定向回归测试修复前失败、修复后通过。真实 daemon 与 Chrome 暂停 detach 和 delete 请求时,Cancel、Esc、遮罩和关闭按钮都无法关掉弹窗。以普通 merge 合入新版上游主线、未改写历史后,在 a179cd17af 上全仓构建、类型检查及 50 项相关组件测试通过。
- 05
a2b39eb405 的本地验证:四个定向 Web Shell 测试文件 1572/1572 通过,另外六个受影响的侧栏文件 87/87 通过;全仓构建与类型检查、改动文件的 lint 与格式、空白检查和提交钩子均通过。用隔离的真实 daemon 与 Chrome 暂停请求时,界面显示 Deleting... 与 aria-busy;会话加载期间 Delete 保持禁用;在浏览器里注入 detach HTTP 503 后,列表行保留,也没有发出删除请求。这个 503 是在浏览器里注入的,不等于真实 daemon 的传输故障。
- 06
截至 2026-09-27 00:49 UTC,PR #12738 在 a2b39eb405 上仍为 OPEN、MERGEABLE,reviewDecision 为 CHANGES_REQUESTED,mergeStateStatus 为 BLOCKED。新 head 的 CI 仍在运行:9 项通过、7 项跳过、5 项待完成,暂无失败;上一个 head 已结束的检查结果不能沿用。审查者此前确认 Critical 已修复,但最新提交的 review 为 COMMENTED,不是新的批准。仍有 13 条审查讨论未解决,其中 4 条因新提交被标为 outdated。补充的端到端报告已发布在 PR 上。本地未运行完整 preflight、其他操作系统或全新冻结依赖安装。
- 07
此前的视觉检查虽已通过,但报告显示与基线相比没有截图差异,因此不能把它当作新 Delete 流程的验证。上述浏览器交互证据来自本地隔离 daemon 的实际运行。
上游进度
- Issue 认领
认领评论已发布;尚无维护者正式指派或方案批准
- 修复与本地验证
首版 1570 项定向测试通过;Critical 以红绿回归、50 项相关测试及暂停真实 daemon 检查修复;后续提交通过 1572 项定向与 87 项侧栏测试
- Pull Request
#12738 已提交,关联 Fixes #12669;端到端报告及补充报告另发评论
- 上游审查
Critical 已确认修复,审查建议已提交修改,但 CHANGES_REQUESTED 仍有效;最新 review 为 COMMENTED,尚未重新批准
- 上游 CI
新 head a2b39eb405:9 项通过、7 项跳过、5 项待完成,暂无失败
- 合并
尚未合并;MERGEABLE 只表示无冲突,mergeStateStatus 仍为 BLOCKED