尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

qwen-code WebShell 非主工作区会话归档加固:能力门控、身份对账与部分失败处理

qwen-code WebShell 非主工作区会话归档加固:能力门控、身份对账与部分失败处理 qwen-code WebShell 非主工作区会话归档加固能力门控、身份对账与部分失败处理【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code本文基于 qwen-code 仓库的设计文档 web-shell-non-primary-session-archive-hardening.md讲解 WebShell 在多工作区daemon 多 workspace场景下如何安全地暴露归档/取消归档操作哪些能力capability与信任条件决定 UI 是否可用、跨工作区如何以(workspaceCwd, sessionId)二元组隔离同名会话以及 HTTP 成功响应中携带的逐会话失败如何被前端对账reconcile。读完后你能理解 qwen-code 会话归档链路从 UI 门控到 daemon 执行、再到状态收敛的完整契约。一、变更定位补齐既有 UI 路径不动 API 契约设计文档的 Summary 明确了这次加固的边界WebShell 已经在从已注册的 secondary非主工作区列出 active 与 archived 会话daemon 已经暴露了workspace-qualified 的 archive/unarchive 路由本次变更只是完成既有的 UI 路径不修改归档 REST API、SDK 类型定义、持久化格式、以及删除delete行为。也就是说这是一次典型的契约不变、行为补齐的加固API 形状、协议字段、落盘格式全部保持稳定变更集中在能力门控、身份隔离与错误对账三个层面。相关协议背景可参考 qwen-serve-protocol.md 与 会话生命周期说明。二、能力与信任边界三条件门控归档 UI文档规定的门控规则是条件适用范围说明session_archive能力所有会话归档 UI缺失时不暴露归档入口也不查询 archived 目录workspace_qualified_rest_core能力secondary 工作区非主工作区额外要求受信任的运行时trusted runtimesecondary 工作区非信任工作区不开放写操作并且受信任 secondary 工作区的 active 行只暴露 Archive 操作这些行对 pin置顶、group分组、rename重命名、export导出、delete删除保持既有的load-only仅加载处理本次加固不改变这一点。最后一个关键细节是当所需能力缺失时archived 目录根本不发起查询——门控发生在数据请求之前而不是渲染阶段。从源码可以印证这套门控。能力声明在 capabilities.ts 中session_archive: { since: v1 },即session_archive自 v1 能力集起可用workspace_qualified_rest_core是另一条用于工作区限定 REST 通道的能力位两者在 WebShell 客户端分别被消费。侧边栏 WebShellSidebar.tsx 中对能力的判断形如connection.capabilities?.features?.includes(session_archive),能力版本的演进规则可参考 能力与版本化文档。三、身份模型以 (workspaceCwd, sessionId) 作为会话唯一键文档的 Identity and Reconciliation 部分规定WebShell 中合并后的会话集合与瞬态行状态一律用(workspaceCwd, sessionId)二元组识别一个会话。这一规则覆盖去重deduplicationReact key 生成当前选中态current selection忙碌态busy state未读完成标记unread completion导出进行中状态export-in-flight state。目的是保证不同工作区中 sessionId 相同的两个会话完全独立——选中一个工作区的sess-abc绝不能误伤另一个工作区同 id 的会话。WebShellSidebar.tsx 中的会话键生成正是这个契约的落地return ${workspaceCwd ?? }\0${sessionId};用\0分隔 workspace 路径与 session id避免纯字符串拼接产生歧义碰撞。secondary 工作区会话的查询与合并逻辑集中在 useOtherWorkspaceSessions.ts其中每个查询以workspaceCwd为单位维护archiveState: active等状态。四、部分失败与响应后对账成功 HTTP 响应里的逐会话错误文档对错误语义的定义是核心设计点之一workspace-qualified 的 archive / unarchive 响应可能在 HTTP 2xx 成功响应中报告逐会话失败。WebShell 会把对应的errors[]条目呈现给用户并且在操作落定后总是重新对账reconcile主工作区的 active/archived 目录以及所选工作区的目录。幂等的alreadyArchived与alreadyActive结果被视为成功。这段契约与 daemon 侧的结果结构严格对应。session-archive.ts 定义了批量结果类型export interface DaemonArchiveSessionsResult { archived: string[]; alreadyArchived: string[]; resolvedConflicts: string[]; notFound: string[]; errors: Array{ sessionId: string; error: unknown }; } export interface DaemonUnarchiveSessionsResult { unarchived: string[]; alreadyActive: string[]; resolvedConflicts: string[]; notFound: string[]; errors: Array{ sessionId: string; error: unknown }; }几个实现细节值得注意批量部分成功是常态而非异常。archiveDaemonSessions/unarchiveDaemonSessions对每个 session 独立执行并归桶archived / alreadyArchived / notFound / error整体请求仍是 200失败信息走errors[]字段。因此客户端不能只看状态码必须消费errors[]——这正是文档要求 WebShell surface a matchingerrors[]entry 的原因。幂等语义内置。目标会话已处于目标状态时已在归档目录 / 已在活跃目录结果落入alreadyArchived/alreadyActive桶不计入errors[]对调用方而言是成功。id 规范化后再去重。批量入口先sessionIds.map(normalizeSessionIdForLookup)再Set去重见 session-archive.ts保证不同大小写写法不会重复执行。冲突处理。当会话同时出现在 active 与 archived 目录时默认拒绝并提示以resolveConflicts: true重试见 sessionLocationError显式开启后冲突结果会记入resolvedConflicts桶。每次批量操作后写 stderr 审计行。logSessionArchiveResult输出requested/archived(alreadyArchived)/notFound/errors的完整计数与 id 列表见 session-archive.ts便于运维侧核对前端呈现与后端实际变更是否一致。WebShell 侧的写操作入口在 WebShellSidebar.tsx分别调用archiveSessionsData([sessionId])与unarchiveSessionsData([sessionId])操作完成后触发对主工作区与会话目录的重查即文档所说的 always reconciles ... after the operation settles。五、daemon 侧的执行安全协调锁与写入租约归档/取消归档最终通过 SessionArchiveCoordinator 的互斥锁串行化到同一会话的并发维护操作runExclusiveMany对批内所有规范化后的session id 加互斥标记若某 id 正处于排他迁移中则抛SessionArchivingError锁键经过normalizeSessionIdForLookup规范化——源码注释说明这是为了防止大小写不敏感文件系统中不同拼写的调用者 id 绕过锁、在 restore 进行中误删 transcript 文件session-archive.tssealMaintenanceAndWait支持 daemon drain 阶段封存维护操作封存后新请求抛DaemonDrainingError实际的存储变更在runWithDaemonWriterLease内完成先获取 daemon 写入租约processKind: daemon、takeoverPolicy: certified执行变更前用assertOwnedAndUnchanged断言存储未被外部修改变更后再更新关联的 scheduled task 生命周期归档会disableTasksForSessions取消归档会enableTasksForSessions见 updateScheduledTaskForMaintenance。这套机制保证了文档承诺的删除行为不变archive / unarchive / delete 共用同一套协调与租约原语互不干扰。六、验证矩阵文档声明的测试覆盖文档 Verification 一节声明了两层回归WebShell 层覆盖成功与部分失败响应、能力缺失、非信任工作区、幂等结果、equal-id同 id 不同工作区场景下的 current / busy 状态隔离、以及操作后对账。对应的测试文件包括 SessionOverviewPanel.test.tsx、WebShellSidebar.collapse-persist.test.tsx、WebShellSidebar.workspace-removal.test.tsx 与 useOtherWorkspaceSessions.test.tsx。daemon 层回归归档并取消归档一个与主工作区 id 相同的 secondary 会话同时断言主工作区的会话文件与 bridge 状态保持未变。daemon 侧归档逻辑的单测见 session-archive.test.ts多工作区路由行为见 multi-workspace-sessions.test.ts 与 qwen-serve-routes.test.ts。七、小结这次加固可以用三句话概括其设计契约门控前置没有session_archive以及 secondary 工作区所需的workspace_qualified_rest_core 受信任运行时归档 UI 不出现、archived 目录不查询secondary 行仅开放 Archive其余操作维持 load-only。身份隔离所有前端会话状态以(workspaceCwd, sessionId)为键同名会话跨工作区互不可见。失败可感知、状态最终一致HTTP 200 中的errors[]逐条呈现alreadyArchived/alreadyActive幂等成功操作落定后强制对账所有相关目录。对二次开发者的启示在于多租户/多作用区的写操作 UI能力位应同时作为数据请求开关而非仅按钮开关批量接口应以逐目标结果桶changed / already / notFound / errors为契约核心客户端对账逻辑与结果桶一一对应才能既容忍部分失败又不丢失状态一致性。【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表