news 2026/9/11 6:16:36

qwen-code 多工作区制品归属:/workspaces/:workspace 限定路由与 Web Shell e2e 验证

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
qwen-code 多工作区制品归属:/workspaces/:workspace 限定路由与 Web Shell e2e 验证

qwen-code 多工作区制品归属:/workspaces/:workspace 限定路由与 Web Shell e2e 验证

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

导读

本文围绕 qwen-code 仓库中的端到端验证文档 .qwen/e2e-tests/2026-08-04-secondary-artifact-workspace-ownership.md 展开,系统梳理"次级工作区(secondary workspace)制品归属"这一多工作区能力的设计目标、三组核心验证场景、源码级路由实现以及最终的自动化与生产环境双重验证结果。读完本文,你将掌握qwen serve--workspace注册下/workspaces/:workspace前缀限定路由的工作原理,理解制品面板与定时任务如何按工作区隔离归属,并了解如何用"同路径哨兵文件"与"隔离定时任务夹具"完成一次可复现的多工作区 e2e 验证。

一、问题背景:多工作区下的制品归属缺失

qwen-code 的qwen serve自 0.21.3 起支持重复--workspace注册,使单个 daemon 可同时托管多个工作区,并通过 Web Shell 对外提供服务(基线信息见 .qwen/e2e-tests/2026-08-04-secondary-artifact-workspace-ownership.md#baseline)。但在该 e2e 任务开展前,组件行为是"失败优先(failure-first)"的,存在两个明确的归属缺陷:

  • 制品面板无归属所有者:当一个制品标签页无法确定它属于哪个工作区时,会退回到根工作区(primary workspace)的动作与路由,导致次级工作区中打开的制品可能被错误地以主工作区身份读写。
  • 定时任务详情缺少次级workspaceId:调度任务明细没有携带次级工作区标识,前端无法把该任务路由到其真正所属的工作区,跨工作区管理调度任务(不止主工作区,而是每个已注册项目)的能力不完整。

这两点正是本次 e2e 验证要修复并锁定的核心目标:让"次级会话的制品"与"次级工作区的定时任务"严格走自己的工作区路由,任何归属不明或归属丢失的情况都必须失败关闭(fail-closed),而不是静默降级到主工作区。

二、验证方案:本地双工作区搭建

验证的第一步是构造一个完全隔离、可对照的双工作区环境。文档给出了四个步骤:

  1. 创建相互隔离的主/次临时工作区:两个工作区在磁盘上完全独立。
  2. 在两个工作区放置同名相对路径哨兵文件、但内容不同:例如artifact-owner.txt,主工作区写入PRIMARY_WORKSPACE_SENTINEL_8494,次级工作区写入SECONDARY_WORKSPACE_SENTINEL_8494。用同路径不同内容的方式,可以精确检验路由是否把请求送达了正确的工作区——只要返回字节不属于当前工作区,就能立刻暴露路由泄漏。
  3. 为两个运行时创建各自独立的持久化定时任务夹具(distinct durable scheduled-task fixtures):主/次各有一个独立的 cron 任务,用于验证任务 CRUD 是否只影响各自工作区。
  4. 以两个--workspace标志启动生产构建的dist/cli.js serve,监听 loopback,并挂载生产 Web Shell 产物:
node dist/cli.js serve \ --workspace /path/to/primary \ --workspace /path/to/secondary \ --port <loopback-port>

注意:本仓库为只读环境,以上命令仅用于说明可复现验证的启动方式;实际执行需在本地检出中完成。

三、场景一:次级工作区文件操作

操作:打开一个次级会话的制品(artifact),并下载/预览其中的哨兵文件。

预期

  • 请求必须携带工作区限定前缀,即目标是/workspaces/<secondary>/file...,而不是根路由/file
  • 返回的字节必须是次级哨兵内容,永远不能是主工作区的哨兵

这一预期的实现落点在 packages/cli/src/serve/routes/workspace-file-read.ts 中。从源码可见,registerWorkspaceQualifiedFileReadRoutes注册了一整组工作区限定读路由:

app.get('/workspaces/:workspace/file', ...); // 读取文件内容 app.get('/workspaces/:workspace/file/bytes', ...); // 读取文件原始字节 app.get('/workspaces/:workspace/stat', ...); // 文件状态 app.get('/workspaces/:workspace/list', ...); // 目录列表 app.get('/workspaces/:workspace/glob', ...); // glob 匹配

每个请求首先通过resolveWorkspaceRuntimeFromParam把路径参数:workspace(工作区 id 或绝对路径)解析为已注册运行时,解析失败即短路返回,随后通过setWorkspaceRouteContext把运行时绑定到本次请求上下文,再进入真正的文件处理逻辑。配套的写路由在 packages/cli/src/serve/routes/workspace-file-write.ts,同样以/workspaces/:workspace/file/write/file/edit/file/upload的限定前缀形式注册。

而路径前缀的解析/保护逻辑集中在 packages/cli/src/serve/acp-http/index.ts,其中定义了PLURAL_WS_PREFIX = '/workspaces/',并实现了对/workspaces/<selector><suffix>的匹配与选择器提取,同时显式拒绝%2e%2e之类的编码穿越(如/workspaces/%2e%2e/acp这类会塌缩到/acp、从而静默绑定到主挂载点的路径)——这正是"次级文件永不落入主工作区"的底层保障之一。

四、场景二:次级工作区定时任务

操作:打开次级工作区的持久化定时任务,依次执行切换启用状态、编辑、删除测试副本。

预期

  • 每一次请求都必须指向/workspaces/<secondary>/scheduled-tasks...
  • 主工作区的任务与任务文件必须保持原样,不受任何影响。

该能力的后端实现在 packages/cli/src/serve/routes/scheduled-tasks.ts 的registerWorkspaceQualifiedScheduledTasksRoutes:它以/workspaces/:workspace为前缀复用registerScheduledTaskCrudRoutes,并通过resolveWorkspaceRuntimeWithLiveCompatibilityFromParam解析目标运行时,随后调用requireTrustedWorkspaceRuntime执行"必须为受信任工作区"的同一门禁,最后把任务目标指向该工作区的 cron 文件与(启用会话管理时的)bridge,从而让多工作区 Web Shell 可以管理每个已注册项目的调度,而不只是主工作区。文档注释也明确写着:任何读写前都要求该工作区受信任,这一门禁与其他限定路由一致。

前端侧,定时任务的面板与 CRUD 交互位于 packages/web-shell/client/components/dialogs/ScheduledTasksDialog.tsx,它通过@qwen-code/web-shell/daemon-react-sdkuseWorkspaceActions拿到按工作区隔离的动作集合,并基于DaemonWorkspaceCapability等类型感知当前工作区能力,从而把"次级任务"与"主任务"在 UI 上区分开。

五、场景三:归属丢失(fail-closed)

操作:保持一个制品标签页打开,在延迟读取尚未返回时,通过能力夹具(capability fixture)将次级工作区移除或标记为不可用。

预期

  • 面板显示本地化的"工作区不可用"(workspace-unavailable)状态。
  • 延迟到达的响应被直接忽略。
  • 不会有任何请求被重试到主工作区路由上——即绝不静默降级。

这是三条预期中最关键的一条,它定义了归属丢失时的失败语义:与其把请求错误地落到主工作区造成数据污染,不如放弃本次响应并向用户明确展示工作区已不可用。验证文档同时要求,生产构建的 Web Shell 产物中必须包含新的 stale-owner(陈旧所有者)守卫逻辑,并且GET /capabilities必须分别广播主/次两个运行时的独立 id(见 packages/cli/src/serve/capabilities.ts 中按工作区切分的能力声明结构),前端才能依据能力变化判断"我打开的这个制品所属工作区是否还在"。

六、自动化验证结果

验证文档记录了 2026-08-04 的完整结果,结论为PASS,分为三层:

6.1 Failure-first 预演(3 个预期失败)

在修复前先跑一轮,捕获 3 个预期失败与 29 个既有通过用例,精确复现了三类缺陷:

  • 主哨兵泄漏到了无所有者的制品标签页(即归属缺失时误用根工作区路由);
  • 次级限定客户端未被使用(qualified client 没有接入次级会话);
  • 定时任务列表缺少workspaceId字段。

6.2 聚焦归属套件(413/413 通过)

修复后的聚焦测试覆盖了六处受影响测试文件(解析器、turn 输出、制品面板、嵌套 subagent、应用标签页传播等),413 个用例全部通过;全量 Web Shell 套件为167 个文件、2,777 个测试全部通过;Web Shell lint 与 TypeScript typecheck、包级 Web Shell 构建、仓库根生产构建均通过;改动文件通过 Prettier(包级格式检查仍报告 5 个未改动的基线文件:BranchPickerPopover.module.cssGitModePopover.module.cssGitDialog.module.cssPlanExecutionView.module.cssindex.html,与本次改动无关)。

七、生产双工作区验证

自动化之外,文档还记录了在生产构建上的真实双工作区验证——用构建后的 CLI 以两个受信任工作区加载复制出的生产 bundle:

  • GET /capabilities广播了主、次两个不同的运行时 id,且产物中的 JS 包含新的 stale-owner 守卫。
  • 同路径哨兵对照GET /file?path=artifact-owner.txt返回PRIMARY_WORKSPACE_SENTINEL_8494(SHA-256818d5f4f…);GET /workspaces/<secondary-id>/file?path=artifact-owner.txt返回SECONDARY_WORKSPACE_SENTINEL_8494(SHA-2560e9fac79…);次级字节路由只返回次级哨兵字节。主/次哈希不同,直接证明两条路由落到了不同的磁盘目录。
  • 持久任务 CRUD 隔离:次级任务的 list/update/delete 全部走/workspaces/<secondary-id>/scheduled-tasks...;更新只改变次级任务的名称与启用状态,主任务保持存在、启用且未变更;删除次级任务后只有次级列表被清空,主任务仍在;验证完毕后两个测试任务均被清理。
  • daemon 请求日志独立记录了限定的 file、bytes 以及 scheduled-task 的 POST/GET/PATCH/DELETE 路由及成功状态,作为第三方证据。

八、关于视觉证据的说明

按文档记录,本次验证中应用内浏览器运行时未报告可用的浏览器实例,因此没有截取到 UI 截图,也没有用合成截图替代——这是刻意为之的严谨做法:宁可缺失也不伪造证据。生产服务器对当前 Web Shell bundle 返回 HTTP 200,DOM 行为则由上述聚焦套件与全量套件覆盖。基于此,本文亦不额外插入任何与"次级工作区制品面板"相关的演示图片,避免引入无法核实的视觉材料。

九、总结

"Secondary artifact workspace ownership" 这次 e2e 验证为 qwen-code 的多工作区 Web Shell 钉住了三项可验证的行为契约:

  1. 次级制品严格走/workspaces/<secondary>/file...路由,同路径哨兵文件 + SHA-256 哈希是防止"读错工作区"的最直观证据;
  2. 次级定时任务 CRUD 严格走/workspaces/<secondary>/scheduled-tasks...,主工作区任务零影响;
  3. 归属丢失必须 fail-closed:显示本地化"工作区不可用"、忽略延迟响应、绝不重试到主路由。

对应实现可分别回溯到 packages/cli/src/serve/routes/workspace-file-read.ts、packages/cli/src/serve/routes/workspace-file-write.ts、packages/cli/src/serve/routes/scheduled-tasks.ts 与 packages/cli/src/serve/acp-http/index.ts 中的PLURAL_WS_PREFIX解析保护逻辑。对于希望自行复现或扩展该验证的读者,可直接以本文第二节的本地搭建步骤为起点,复用"双哨兵文件 + 隔离任务夹具 + 限定路由日志"三件套,在qwen serve的多工作区能力上继续加固。

【免费下载链接】qwen-codeAn open-source AI coding agent that lives in your terminal.项目地址: https://gitcode.com/GitHub_Trending/qw/qwen-code

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 6:15:34

SSM框架核心技术解析与Java企业级开发实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 6:13:29

国产宇航级SSD技术突破与应用实践

1. 航天存储的特殊性与挑战航天器存储系统需要面对极端环境考验&#xff0c;包括但不限于&#xff1a;宇宙射线辐射&#xff1a;地球轨道上的辐射强度是地面的100-1000倍温度剧烈变化&#xff1a;向阳面与背阴面温差可达150℃机械振动&#xff1a;发射阶段承受10-15G的振动加速…

作者头像 李华
网站建设 2026/9/11 6:09:52

大模型Prompt工程实战:从调试到对齐监控

我注意到输入内容中存在严重问题&#xff1a;标题“GPT-6 Astra 的使用焚诀”及所附热搜词、网络热词中&#xff0c; GPT-6 Astra 并非真实存在的公开模型 ——OpenAI 官方从未发布、命名或确认过 “GPT-6” 或 “Astra” 这一组合型号&#xff1b;截至2024年第三季度&#x…

作者头像 李华
网站建设 2026/9/11 6:09:43

MicroPython Pico硬件看门狗WDT实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华