Skip to content

chore(serve): remove the /demo debug page - #8805

Merged
wenshao merged 7 commits into
mainfrom
chore/remove-daemon-demo-page
Aug 10, 2026
Merged

chore(serve): remove the /demo debug page#8805
wenshao merged 7 commits into
mainfrom
chore/remove-daemon-demo-page

Conversation

@wenshao

@wenshao wenshao commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Removes the daemon's /demo debug page and folds its remaining infrastructure back into the health route.

The daemon has shipped a real browser UI for a while now: qwen serve locates the bundled Web Shell assets at startup and serves them from the root path, so opening the daemon in a browser already lands on a full client with chat, session list, workspace inspection, and permission handling. /demo stayed behind as a 663-line self-contained HTML console covering the same ground with none of the reach.

The demo handler shared a module with /health, so that module is now health-only and drops the port accessor it needed solely to render the page. The rate-limit exemption list, the --allow-origin '*' boot warning, and the daemon documentation lose their /demo arms. The loopback self-origin regression test was already asserting through /health — only its title mentioned the demo — so its coverage is untouched.

Why it's needed

The page is not just dead weight, it actively misroutes work. It is the only place in the tree that pairs an event log with daemon HTTP traffic, so anything that presents as "the event stream is noisy" or "the console renders this wrong" gets attracted to it even when the observation came from somewhere else. #8762 is the clearest case: the flooding was found while driving /review through the Web Shell, and the fix landed entirely inside the demo page's rendering — its own risk note says no Web Shell changes. The real client kept whatever behaviour it had, and a page nobody drives the daemon through got three rounds of tests.

Nobody depends on it either. Releases bundle the Web Shell next to the CLI bundle, and the daemon dev script starts the Web Shell dev server rather than the demo page, so neither the shipped path nor the development path passes through /demo. Protocol-level debugging does not regress: subscribing to a session's event stream yields the same raw frames the Events tab was printing, which is what anyone actually inspecting the wire format reaches for.

Reviewer Test Plan

How to verify

  • Start a daemon on the loopback default and open it in a browser. The root path serves the Web Shell as before; /demo no longer exists. On a tokenless loopback daemon a browser navigating to the old URL is caught by the SPA fallback and gets the Web Shell rather than a dead link, while a non-navigation request returns 404. Once a token is configured — with or without --require-auth — that navigation is refused with 401 instead, because the SPA fallback sits behind the bearer.
  • /health behaves exactly as before in both gating modes: reachable without a token on a loopback bind, and gated behind the bearer on a non-loopback bind or with --require-auth. Deep probes (?deep=1) still return the aggregate daemon counters.
  • Rate limiting still exempts /health, and the daemon still starts and serves its API surface unchanged.
  • Confirm the daemon docs no longer point a reader at a page that does not exist — the quickstart, observability, and runtime pages now describe the Web Shell mount and point at the session event stream for raw-frame debugging.

Local results:

  • npx vitest run src/serve in the CLI package: 4221 passed, 1 skipped, across 147 files. One run had two unrelated flakes (workspace-generation.test.ts failing with Parse Error: Expected HTTP/, RTSP/ or ICE/, a socket-level hiccup); a clean re-run was fully green.
  • npx tsc --noEmit in the CLI package introduces no new errors — the ones it reports (missing qrcode-terminal types, a stale session-service declaration) are already present on main.
  • ESLint and Prettier clean on every touched file. The two user-facing docs show large diffs only because Prettier reflows Markdown table column widths once the longest cell shrinks; both files were already Prettier-clean before the change.
  • Smoke-checked against a real assembled app rather than only unit fixtures: the Web Shell directory resolves to the built assets, the root path returns the shell, /health returns {"status":"ok"}, /demo returns 404 for a plain request and the SPA shell for a browser-style document navigation.

Evidence (Before & After)

N/A — no user-visible UI changes. The only surface removed is a debug page superseded by the Web Shell.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

Unit tests and a supertest-level smoke check against createServeApp with the built Web Shell assets present.

Risk & Scope

  • Main risk or tradeoff: anyone who had bookmarked the demo page loses it. That is the point of the change. On a tokenless loopback daemon the URL degrades to the Web Shell via the SPA fallback; with a token configured it returns 401, since that fallback is mounted behind the bearer. The health route module was renamed, so an out-of-tree importer of it would need to follow the rename.
  • Not validated / out of scope: the Web Shell itself is unchanged; the usage_update frame cadence that motivated fix(serve): stop usage_update frames from flooding the demo event log #8762 is unchanged and remains correct protocol behaviour. Windows and Linux were not exercised locally — CI covers them.
  • Breaking changes / migration notes: GET /demo is gone. It was a debug affordance, not part of the wire protocol, and no SDK or client code referenced it.

Linked Issues

Follow-up to #8762.

中文说明

这个 PR 做了什么

删除 daemon 的 /demo 调试页,并把它残留的基础设施收回到 health 路由里。

daemon 早就带了真正的浏览器 UI:qwen serve 启动时会定位随包的 Web Shell 资源并从根路径提供服务,所以用浏览器打开 daemon 本来就落在一个完整的客户端上——聊天、会话列表、workspace 检查、权限处理都有。/demo 只是留下来的一个 663 行自包含 HTML 控制台,覆盖同样的场景却完全没有这些能力。

demo 处理器原本和 /health 共用一个模块,现在这个模块只剩 health,并去掉了仅为渲染页面而需要的端口访问器。限流豁免名单、--allow-origin '*' 的启动告警、以及 daemon 文档都去掉了各自的 /demo 分支。loopback 同源回归测试本来就是打 /health 的——只有标题里提到 demo——所以它的覆盖没有受影响。

为什么需要

这个页面不只是死代码,它会实实在在地把工作引到错误的地方。它是仓库里唯一把事件日志和 daemon HTTP 流量放在一起的地方,所以任何表现为"事件流太吵"或"控制台渲染不对"的问题都会被它吸过去,哪怕现象根本来自别处。#8762 是最清楚的例子:刷屏是在通过 Web Shell 跑 /review 时发现的,修复却完全落在 demo 页的渲染里——它自己的风险栏就写着不改 Web Shell。真正的客户端行为一点没变,而一个没人用来驱动 daemon 的页面得到了三轮测试。

也没有人依赖它。发布产物把 Web Shell 打包在 CLI bundle 旁边,daemon 开发脚本启动的是 Web Shell 的 dev server 而不是 demo 页,所以无论发布路径还是开发路径都不经过 /demo。协议层调试能力没有退化:订阅会话事件流拿到的就是 Events 标签在打印的那些原始帧,真要看线协议的人本来也是用它。

审阅者测试计划

如何验证

  • 用默认 loopback 启动 daemon 并在浏览器里打开。根路径照旧提供 Web Shell;/demo 不再存在。在无 token 的 loopback daemon 上,浏览器访问旧 URL 会被 SPA 兜底接住、拿到 Web Shell 而不是死链,非导航类请求返回 404。一旦配置了 token(无论是否带 --require-auth),该导航会改为 401,因为 SPA 兜底位于 bearer 之后。
  • /health 在两种网关模式下行为完全不变:loopback 绑定下无 token 可达,非 loopback 绑定或带 --require-auth 时由 bearer 把关。深度探测(?deep=1)仍返回 daemon 聚合计数。
  • 限流仍然豁免 /health,daemon 仍正常启动并提供不变的 API 面。
  • 确认 daemon 文档不再把读者指向一个不存在的页面——quickstart、可观测性和 runtime 三页现在描述的是 Web Shell 的挂载方式,并把原始帧调试指向会话事件流。

本地结果:

  • CLI 包内 npx vitest run src/serve:147 个文件,4221 通过、1 跳过。其中一次有两个无关抖动(workspace-generation.test.tsParse Error: Expected HTTP/, RTSP/ or ICE/,socket 层面的偶发);干净重跑全绿。
  • CLI 包内 npx tsc --noEmit 没有新增错误——它报的那些(缺 qrcode-terminal 类型、一处陈旧的 session service 声明)在 main 上本来就有。
  • 所有改动文件 ESLint 与 Prettier 干净。两份面向用户的文档 diff 偏大,只是因为最长单元格变短后 Prettier 会重排 Markdown 表格列宽;这两个文件在改动前就已经是 Prettier 干净的。
  • 不只跑单测,还对真实组装出来的 app 做了冒烟:Web Shell 目录解析到构建产物,根路径返回外壳,/health 返回 {"status":"ok"},/demo 对普通请求返回 404、对浏览器式文档导航返回 SPA 外壳。

证据(改动前后)

N/A —— 没有用户可见的 UI 变化。唯一移除的界面是一个已被 Web Shell 取代的调试页。

测试平台

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

环境(可选)

单元测试,以及在 Web Shell 构建产物存在的前提下对 createServeApp 做的 supertest 级冒烟检查。

风险与范围

  • 主要风险或权衡:收藏了 demo 页的人会失去它。这正是本次改动的目的。在无 token 的 loopback daemon 上该 URL 会经 SPA 兜底降级到 Web Shell;配置了 token 时返回 401,因为兜底挂在 bearer 之后。health 路由模块被重命名,树外若有引用需要跟着改。
  • 未验证 / 范围之外:Web Shell 本身没有改动;引出 fix(serve): stop usage_update frames from flooding the demo event log #8762usage_update 帧节奏没有改动,它本来就是正确的协议行为。Windows 和 Linux 未在本地跑——由 CI 覆盖。
  • 破坏性变更 / 迁移说明:GET /demo 不再存在。它是调试用的便利设施,不属于线协议,没有任何 SDK 或客户端代码引用它。

关联 Issue

#8762 的后续。

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.83% 83.83% 89.76% 83.03%
Core 87.85% 87.85% 89.39% 86.35%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.83 |    83.03 |   89.76 |   83.83 |                   
 src               |   84.97 |    81.29 |   88.49 |   84.97 |                   
  cli.ts           |   95.68 |    84.11 |     100 |   95.68 | ...60-561,565-566 
  gemini.tsx       |    72.8 |    77.39 |   80.76 |    72.8 | ...1299-1303,1424 
  ...ractiveCli.ts |   86.74 |    81.15 |   88.13 |   86.74 | ...2955,2961,3026 
  ...liCommands.ts |   89.33 |     85.6 |      90 |   89.33 | ...01,518,552,674 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   71.19 |    73.65 |   90.84 |   71.19 |                   
  acpAgent.ts      |   70.59 |    73.45 |   90.37 |   70.59 | ...29,12234-12236 
  ...k-reporter.ts |     100 |    80.95 |     100 |     100 | 77,80,115,135     
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |     100 |      100 |     100 |     100 |                   
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   97.04 |    95.71 |   93.33 |   97.04 |                   
  filesystem.ts    |   97.04 |    95.71 |   93.33 |   97.04 | ...21-122,242-243 
 ...ration/session |   91.49 |    86.98 |   96.71 |   91.49 |                   
  Session.ts       |   90.51 |    85.18 |   95.94 |   90.51 | ...90,10717-10721 
  ...entTracker.ts |    96.8 |    89.36 |      90 |    96.8 | 137-143,221       
  ...projection.ts |   98.57 |    93.29 |     100 |   98.57 | ...76,333,344,356 
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |   93.44 |    91.74 |     100 |   93.44 | 74,85-88,115-125  
  ...y-replayer.ts |   98.54 |    95.65 |     100 |   98.54 | 241-243           
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    87.32 |     100 |   89.76 | ...54-270,326-328 
  ...lure-guard.ts |   98.32 |    97.75 |     100 |   98.32 | 294-295,340-341   
  tasksSnapshot.ts |    94.3 |     87.5 |     100 |    94.3 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   96.01 |    94.15 |   96.66 |   96.01 |                   
  ...ageEmitter.ts |   95.95 |       96 |     100 |   95.95 | 52-59             
  PlanEmitter.ts   |     100 |       90 |     100 |     100 | 66                
  base-emitter.ts  |   78.26 |       75 |     100 |   78.26 | 23-24,26-28       
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   99.18 |    96.47 |     100 |   99.18 | 355-356           
 ...ession/rewrite |    91.8 |    89.13 |   94.44 |    91.8 |                   
  LlmRewriter.ts   |    82.4 |     86.2 |     100 |    82.4 | ...,88-89,166-170 
  ...Middleware.ts |   96.96 |    88.09 |     100 |   96.96 | 144,152-154       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/agent-view    |   89.03 |    81.37 |   89.09 |   89.03 |                   
  ...t-cli-argv.ts |     100 |      100 |     100 |     100 |                   
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  ...sor-client.ts |   80.38 |    72.54 |   76.66 |   80.38 | ...22-626,652-656 
  ...or-process.ts |   96.61 |    89.47 |   84.61 |   96.61 | 129-130,150-151   
  ...sor-runner.ts |    84.9 |     75.6 |      85 |    84.9 | ...44,468,471-481 
  ...sor-server.ts |   85.71 |    83.06 |   95.45 |   85.71 | ...67-468,471-488 
  ...isor-store.ts |   97.73 |    81.16 |     100 |   97.73 | ...92,594,607,643 
  ...nal-bridge.ts |   93.98 |     91.3 |   83.33 |   93.98 | 228-238           
 src/commands      |   90.81 |    79.71 |   66.66 |   90.81 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   55.55 |      100 |       0 |   55.55 | 18-22,30-40       
  extensions.tsx   |   96.77 |      100 |      50 |   96.77 | 39                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   98.66 |      100 |      50 |   98.66 | 86                
  serve.ts         |   89.84 |    77.45 |     100 |   89.84 | ...52,855-858,870 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   88.91 |     88.5 |   90.54 |   88.91 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |   95.21 |    96.73 |   88.88 |   95.21 | ...18-221,266-269 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.87 |    96.35 |     100 |   95.87 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   93.96 |    85.44 |   94.23 |   93.96 | ...1229,1236-1237 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.49 |    96.51 |     100 |   98.49 | 115-116,161       
  ...tact-store.ts |   93.51 |    87.65 |     100 |   93.51 | ...71,288-289,337 
  pairing.ts       |      75 |      100 |      50 |      75 | 22-28,59-70       
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |    77.5 |    86.95 |      75 |    77.5 | 72-84,93-97       
  runtime.ts       |   82.43 |    86.44 |     100 |   82.43 | ...87-191,251-253 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |    85.8 |    82.17 |      88 |    85.8 | ...85,591-594,606 
  ...ure-format.ts |   93.65 |    82.45 |     100 |   93.65 | ...42,48-49,74-75 
  status.ts        |   78.57 |    59.25 |   66.66 |   78.57 | ...36-137,150-161 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.82 |    87.64 |   87.09 |   88.82 |                   
  consent.ts       |   72.53 |       90 |   42.85 |   72.53 | ...86-142,157-163 
  disable.ts       |     100 |       90 |     100 |     100 | 30                
  enable.ts        |     100 |    91.66 |     100 |     100 | 38                
  install.ts       |   82.95 |    81.57 |      75 |   82.95 | ...96-199,202-211 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |     87.5 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |      75 |    53.84 |     100 |      75 | ...27-131,133-137 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...amples/starter |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-64              
 src/commands/mcp  |   90.31 |    84.61 |   83.33 |   90.31 |                   
  add.ts           |    99.3 |    96.07 |     100 |    99.3 | 154-155           
  approve.ts       |   76.19 |     87.5 |   66.66 |   76.19 | ...,89-99,114-124 
  list.ts          |   93.15 |    84.84 |      80 |   93.15 | ...78-180,198-199 
  reconnect.ts     |   78.85 |    66.66 |   85.71 |   78.85 | 42-55,169-191     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   87.54 |    87.89 |   88.33 |   87.54 |                   
  agent-prompt.ts  |   93.64 |    91.71 |   97.22 |   93.64 | ...2465,2589-2669 
  base-tree.ts     |   76.16 |    80.76 |   77.77 |   76.16 | ...50-371,373-386 
  capture-local.ts |   68.57 |     90.9 |      75 |   68.57 | 107-111,158-189   
  ...k-coverage.ts |   50.71 |       35 |   66.66 |   50.71 | ...40-245,279-289 
  cleanup.ts       |   89.12 |    82.22 |   83.33 |   89.12 | ...99-504,506-507 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   96.35 |    91.73 |      96 |   96.35 | ...1929,1957-1979 
  cost-ledger.ts   |   94.67 |    95.86 |   78.57 |   94.67 | ...04-505,545-555 
  drive.ts         |   76.07 |    85.71 |   81.81 |   76.07 | ...90-492,497-499 
  extract-step.ts  |   91.36 |    90.62 |   88.88 |   91.36 | ...90-707,714-729 
  fetch-pr.ts      |    76.7 |    68.75 |   63.63 |    76.7 | ...95,417,450-455 
  findings.ts      |   89.35 |    89.13 |   95.45 |   89.35 | ...15-918,927-928 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  match-remote.ts  |   85.54 |     92.3 |   66.66 |   85.54 | 67-72,131-136     
  mock-provider.ts |   95.44 |    90.25 |   89.47 |   95.44 | 145,690-709       
  parse-args.ts    |   99.66 |    96.55 |     100 |   99.66 | 404               
  plan-diff.ts     |   64.04 |      100 |   66.66 |   64.04 | 127-163           
  pr-context.ts    |   81.77 |    80.86 |   92.85 |   81.77 | ...1043,1072-1074 
  presubmit.ts     |   83.75 |    92.72 |   88.88 |   83.75 | ...77-578,655-685 
  ...ish-assets.ts |   77.18 |    82.14 |   71.42 |   77.18 | ...85-531,533-544 
  repo-context.ts  |   94.92 |    90.82 |     100 |   94.92 | ...67-368,376-377 
  ...ve-anchors.ts |   77.77 |    88.88 |      75 |   77.77 | ...77-182,194-211 
  run.ts           |   82.16 |    87.12 |   91.66 |   82.16 | ...52,468-516,529 
  save-artifact.ts |    89.9 |    81.81 |   94.11 |    89.9 | ...08-311,404-407 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...59-773,775-797 
  submit.ts        |    84.1 |     84.7 |    90.9 |    84.1 | ...66,555,582-618 
  test-delta.ts    |   87.13 |    91.46 |      75 |   87.13 | 206-237,477-485   
  test-efficacy.ts |   88.04 |    84.12 |   95.45 |   88.04 | ...2602,2610-2630 
  test-plan.ts     |   91.44 |    91.39 |   89.47 |   91.44 | ...38-839,903-920 
 ...w/__fixtures__ |     100 |      100 |     100 |     100 |                   
  ...r-default.mjs |     100 |      100 |     100 |     100 |                   
  ...der-empty.mjs |     100 |      100 |     100 |     100 |                   
  ...der-named.mjs |     100 |      100 |     100 |     100 |                   
 ...nds/review/lib |   96.99 |    94.81 |   97.76 |   96.99 |                   
  agent-briefs.ts  |   98.96 |      100 |      50 |   98.96 | 719-720           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  assets.ts        |     100 |      100 |     100 |     100 |                   
  authorization.ts |    92.4 |    92.59 |     100 |    92.4 | 127-133           
  budget.ts        |     100 |    96.87 |     100 |     100 | 456,487           
  coverage.ts      |   94.48 |    94.57 |      96 |   94.48 | ...72-489,526-537 
  deadline.ts      |   98.03 |     92.1 |     100 |   98.03 | ...71,220,531,561 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.01 |     100 |   98.73 | ...41,264,290-291 
  effort.ts        |     100 |      100 |     100 |     100 |                   
  gh.ts            |   86.42 |    91.83 |      75 |   86.42 | ...52,289-290,317 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  ledger.ts        |     100 |      100 |     100 |     100 |                   
  local-diff.ts    |    84.4 |    88.46 |     100 |    84.4 | ...63-473,475-483 
  ...ry-context.ts |   96.19 |    94.93 |     100 |   96.19 | ...90-491,496-499 
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |     100 |     87.5 |     100 |     100 | 92                
  prompt-record.ts |   97.88 |    93.87 |     100 |   97.88 | 260-261,267       
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  remote-match.ts  |   97.26 |    91.42 |     100 |   97.26 | 49-50             
  report.ts        |   94.68 |    93.75 |     100 |   94.68 | 189-193           
  ...ry-context.ts |     100 |    98.66 |     100 |     100 | 184               
  retirement.ts    |     100 |    92.39 |     100 |     100 | ...28,308-309,449 
  review-footer.ts |     100 |      100 |     100 |     100 |                   
  roster.ts        |     100 |    95.71 |     100 |     100 | 145,163,208       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  stale-bundle.ts  |   98.11 |    94.04 |     100 |   98.11 | 416,457,497-498   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.59 |    94.56 |     100 |   96.59 | ...08,297-298,323 
  ...pace-scope.ts |     100 |    96.96 |     100 |     100 | 172               
  workspaces.ts    |     100 |     95.9 |     100 |     100 | ...27,452,499,512 
  worktree.ts      |     100 |      100 |     100 |     100 |                   
 ...mands/sessions |   91.56 |    86.95 |   83.33 |   91.56 |                   
  common.ts        |     100 |      100 |     100 |     100 |                   
  list.ts          |   90.96 |    86.66 |   81.81 |   90.96 | 208-219,221-222   
 src/config        |   94.84 |    89.76 |   96.22 |   94.84 |                   
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   89.35 |    83.56 |     100 |   89.35 | ...97-298,314-315 
  ...eMcpImport.ts |   87.91 |    81.52 |     100 |   87.91 | ...63-371,453-454 
  compile-cache.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   88.93 |    88.59 |   83.33 |   88.93 | ...2451,2453-2461 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.02 |    88.88 |     100 |   83.02 | ...02-209,232-240 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |   96.49 |     93.4 |      95 |   96.49 | ...77-578,632-633 
  ...le-watcher.ts |   90.86 |    83.65 |   95.83 |   90.86 | ...23-325,370,418 
  ...resh-state.ts |   90.57 |    97.29 |   93.75 |   90.57 | 137-142,146-152   
  ...ime-reload.ts |     100 |    69.69 |     100 |     100 | ...12-113,122-123 
  hot-reload.ts    |     100 |    89.13 |     100 |     100 | 47,172-178,238    
  keyBindings.ts   |   97.43 |       50 |     100 |   97.43 | 236-239           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.96 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   93.33 |    93.33 |     100 |   93.33 | ...42-147,216-217 
  session-id.ts    |     100 |      100 |     100 |     100 |                   
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   91.27 |    92.64 |      90 |   91.27 | ...1030,1032-1033 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...ngsWatcher.ts |   95.54 |    88.34 |     100 |   95.54 | ...28,277-278,293 
  ...d-env-keys.ts |     100 |      100 |     100 |     100 |                   
  ...l-settings.ts |     100 |      100 |     100 |     100 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...precedence.ts |   98.79 |     92.3 |     100 |   98.79 | 62                
  ...tedFolders.ts |   92.53 |    93.47 |     100 |   92.53 | ...36-337,373-384 
 ...nfig/migration |   95.23 |    77.77 |   83.33 |   95.23 |                   
  index.ts         |   95.65 |     87.5 |     100 |   95.65 | 117-118           
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.91 |      100 |     100 |   94.91 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |      100 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
  v5-to-v4.ts      |      96 |      100 |     100 |      96 | 94-95,99          
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |    71.8 |    70.31 |   66.66 |    71.8 |                   
  ...tputBridge.ts |   71.95 |    70.96 |   68.42 |   71.95 | ...08-409,417-420 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/hooks         |     100 |      100 |     100 |     100 |                   
  ...elete-hook.ts |     100 |      100 |     100 |     100 |                   
 src/i18n          |   85.98 |    81.92 |   89.65 |   85.98 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languages.ts     |   93.07 |     92.3 |   85.71 |   93.07 | ...35,164-169,184 
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |   80.98 |    77.27 |   84.12 |   80.98 |                   
  session.ts       |   84.97 |    76.31 |   96.07 |   84.97 | ...1048,1057-1067 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...31-632,635-636 
 ...active/control |   75.54 |    89.83 |      80 |   75.54 |                   
  ...rolContext.ts |    6.06 |        0 |       0 |    6.06 | 57-99             
  ...Dispatcher.ts |   91.95 |    92.98 |   88.88 |   91.95 | ...54-372,392,395 
  ...rolService.ts |    6.89 |        0 |       0 |    6.89 | 46-188            
 ...ol/controllers |    44.9 |    66.19 |   55.26 |    44.9 |                   
  ...Controller.ts |    42.4 |      100 |   83.33 |    42.4 | 101-105,140-223   
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   55.01 |    67.14 |   58.33 |   55.01 | ...15-624,639-644 
  ...Controller.ts |   49.23 |       60 |      50 |   49.23 | ...07-108,111-121 
  ...Controller.ts |   37.92 |    60.71 |   46.66 |   37.92 | ...41-653,662-691 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |    98.1 |    94.13 |   95.23 |    98.1 |                   
  ...putAdapter.ts |   97.98 |     93.2 |   98.07 |   97.98 | ...1415,1431-1432 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.49 |      100 |   90.47 |   98.49 | 85-86,126-127     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   87.31 |    75.32 |   88.23 |   87.31 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.01 |       76 |   93.33 |   88.01 | ...49-350,361-364 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/runtime       |   99.61 |    95.04 |     100 |   99.61 |                   
  ...livery-ipc.ts |     100 |     90.9 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  cpu-percent.ts   |     100 |      100 |     100 |     100 |                   
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
 src/serve         |    87.5 |    83.78 |   90.45 |    87.5 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.43 |    93.05 |     100 |   93.43 | ...20-321,324-326 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    98.07 |     100 |     100 | 672               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...op-mcp-ipc.ts |   81.06 |    73.68 |   94.11 |   81.06 | ...37-242,267,289 
  ...nt-service.ts |    94.1 |    86.89 |     100 |    94.1 | ...75-477,484,486 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   88.59 |    93.68 |   96.29 |   88.59 | ...95-207,451-454 
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   87.27 |     85.2 |     100 |   87.27 | ...10,816-820,838 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   92.42 |    84.44 |    97.1 |   92.42 | ...1466,1520-1524 
  ...e-grouping.ts |     100 |    94.28 |     100 |     100 | 71,137            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |    90.1 |    77.83 |   94.73 |    90.1 | ...1014,1021-1026 
  daemon-logger.ts |    82.2 |    77.42 |   91.76 |    82.2 | ...1720,1747-1753 
  ...y-pressure.ts |     100 |    96.96 |     100 |     100 | 135               
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.57 |     90.8 |     100 |   98.57 | ...1411,1413-1414 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |   93.37 |    85.18 |     100 |   93.37 | 114-117,195-202   
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...d-provider.ts |   92.06 |    86.95 |     100 |   92.06 | ...72,287-293,316 
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  ...h-settings.ts |   94.94 |    90.37 |     100 |   94.94 | ...30,708,724,734 
  fast-path.ts     |   90.99 |    81.38 |   95.45 |   90.99 | ...33-542,608-609 
  ...ration-sse.ts |   42.55 |    33.33 |     100 |   42.55 | 23-24,30,33-56    
  health-query.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-144             
  ...e-observer.ts |   89.89 |    83.24 |      96 |   89.89 | ...11-512,541-543 
  ...back-binds.ts |     100 |    88.88 |     100 |     100 | 32                
  ...-workspace.ts |    90.9 |    85.71 |     100 |    90.9 | ...30-131,142-143 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |     100 |    86.95 |     100 |     100 | 36,66,92          
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.68 |    88.29 |     100 |   92.68 | ...89-291,303-305 
  ...qwen-serve.ts |   83.96 |    80.01 |   75.26 |   83.96 | ...7436,7442-7443 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   94.22 |    88.99 |     100 |   94.22 | ...27,531-532,572 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   90.58 |    91.18 |   71.81 |   90.58 | ...2716,2730-2734 
  ...-admission.ts |   98.24 |     94.8 |     100 |   98.24 | 79-80,303-304     
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    95.23 |     100 |     100 | 12                
  ...-admission.ts |   98.71 |    89.65 |     100 |   98.71 | 68                
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |    93.3 |    76.83 |     100 |    93.3 | ...20,823,836-838 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   92.18 |    88.37 |     100 |   92.18 | ...21-224,267-270 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.58 |       79 |     100 |   98.58 | 106,134,174,177   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   93.89 |     87.5 |     100 |   93.89 | ...18-519,525-526 
  ...e-remember.ts |   98.23 |    92.51 |     100 |   98.23 | ...36,340-345,386 
  ...te-runtime.ts |   83.98 |    90.29 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |   91.63 |    84.26 |     100 |   91.63 | ...71-273,306-307 
 ...serve/acp-http |   77.89 |    79.56 |   93.03 |   77.89 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.55 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   73.19 |    76.77 |      94 |   73.19 | ...5165,5213-5219 
  index.ts         |   82.23 |    80.11 |   91.07 |   82.23 | ...2341,2425-2426 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   87.73 |    76.21 |    97.5 |   87.73 |                   
  ...r-emulator.ts |   93.27 |    77.77 |     100 |   93.27 | ...53-256,282-283 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |    6.12 |    57.89 |   46.15 |    6.12 |                   
  ...helpers.d.mts |       0 |        0 |       0 |       0 | 1                 
  ...e-helpers.mjs |   97.64 |    70.96 |     100 |   97.64 | 22-23             
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-124             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  ...re-server.mjs |       0 |        0 |       0 |       0 | 1-59              
  ...ols-smoke.mjs |       0 |        0 |       0 |       0 | 1-268             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
  ...al-chrome.mjs |       0 |        0 |       0 |       0 | 1-223             
 src/serve/fs      |   86.39 |    80.74 |     100 |   86.39 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 204               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...x-registry.ts |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.64 |     73.8 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.42 |    89.18 |     100 |   90.42 | 161-169           
  text-cursor.ts   |   88.23 |       90 |     100 |   88.23 | 74-77,92-95       
  ...ile-system.ts |   86.16 |    79.55 |     100 |   86.16 | ...2510,2520-2521 
 src/serve/live    |   77.28 |    69.21 |   89.91 |   77.28 |                   
  ...en-context.ts |   95.74 |    81.25 |     100 |   95.74 | ...0,66-67,99-100 
  ...-workspace.ts |   88.63 |    82.53 |     100 |   88.63 | ...40-241,253-254 
  discovery.ts     |   85.77 |    76.92 |      90 |   85.77 | ...49-250,255-256 
  ...structions.ts |     100 |      100 |     100 |     100 |                   
  ...oordinator.ts |   82.67 |    76.75 |   97.01 |   82.67 | ...1319,1351-1353 
  ...-installer.ts |   45.17 |    81.96 |   68.18 |   45.17 | ...80-381,395-407 
  ...oordinator.ts |   76.17 |     64.4 |   85.36 |   76.17 | ...1858,1949-1950 
  ...controller.ts |   67.82 |    79.31 |   72.72 |   67.82 | ...66-278,287-295 
  ...ak-to-user.ts |   96.66 |      100 |   83.33 |   96.66 | 37-38             
  ...sk-service.ts |   86.22 |    59.64 |   93.33 |   86.22 | ...1152,1175-1182 
  ...task-tools.ts |      99 |      100 |   85.71 |      99 | 205-206           
  ...redentials.ts |   96.26 |    93.47 |     100 |   96.26 | 91-94             
  ...me-session.ts |   65.63 |    57.24 |   88.88 |   65.63 | ...2270,2275-2282 
  ...up-context.ts |   94.83 |    77.58 |     100 |   94.83 | ...18,327-330,350 
  ...ion-source.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/serve/routes  |   85.53 |    79.99 |   94.71 |   85.53 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...nel-notify.ts |   86.45 |       88 |     100 |   86.45 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.71 |    83.33 |     100 |   85.71 | 101-108           
  goals.ts         |   98.92 |     90.9 |     100 |   98.92 | 146               
  health.ts        |   99.09 |    91.17 |     100 |   99.09 | 147               
  live-setup.ts    |   33.33 |     37.5 |      50 |   33.33 | ...18-123,130-135 
  live.ts          |    82.4 |    71.42 |     100 |    82.4 | ...-94,96-101,121 
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.29 |    82.94 |   92.59 |   87.29 | ...1275,1318-1319 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   85.41 |    81.79 |   91.04 |   85.41 | ...4730,4732-4733 
  sse-events.ts    |   86.82 |    85.71 |   94.11 |   86.82 | ...16-927,930,937 
  usage-stats.ts   |     100 |    95.45 |     100 |     100 | 118               
  ...space-auth.ts |   85.55 |    75.64 |     100 |   85.55 | ...21-326,331,345 
  ...el-control.ts |   86.26 |    78.94 |     100 |   86.26 | ...17-318,339-347 
  ...management.ts |   90.92 |    79.69 |     100 |   90.92 | ...81-482,501-502 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.11 |    79.31 |      90 |   83.11 | ...1033,1039,1042 
  ...extensions.ts |   88.15 |    74.95 |   92.98 |   88.15 | ...2027,2072-2073 
  ...-file-read.ts |      91 |    80.91 |     100 |      91 | ...20-621,624-625 
  ...file-write.ts |   84.44 |    64.51 |     100 |   84.44 | ...73-275,355-357 
  ...t-branches.ts |   75.43 |    66.66 |     100 |   75.43 | ...13-618,627-634 
  ...e-git-diff.ts |   97.32 |    90.56 |     100 |   97.32 | 161-162,189-191   
  ...ce-git-log.ts |     100 |    93.18 |     100 |     100 | 52,77,188         
  workspace-git.ts |   77.08 |    89.65 |     100 |   77.08 | 97-118            
  ...github-prs.ts |   88.26 |    63.46 |     100 |   88.26 | ...38-239,264-265 
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...management.ts |   87.41 |    84.13 |     100 |   87.41 | ...1660,1680-1685 
  ...cp-control.ts |    73.2 |    67.54 |   85.71 |    73.2 | ...27-633,644-645 
  ...ace-models.ts |   95.53 |    89.74 |     100 |   95.53 | ...52-157,296-297 
  ...ermissions.ts |    77.9 |    72.41 |     100 |    77.9 | ...69-277,298-316 
  ...e-settings.ts |   75.04 |    72.99 |     100 |   75.04 | ...79-690,696-697 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |    76.9 |    87.15 |     100 |    76.9 | ...29-354,360-394 
  ...ace-status.ts |   82.94 |     74.5 |     100 |   82.94 | ...84-486,490-491 
  ...pace-tools.ts |   75.94 |    69.69 |   66.66 |   75.94 | ...59-164,193-194 
  ...pace-trust.ts |   78.92 |    66.21 |      80 |   78.92 | ...38-343,351-352 
  ...pace-voice.ts |   91.33 |    80.92 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |    90.8 |     88.4 |   96.57 |    90.8 |                   
  access-log.ts    |   98.68 |     97.1 |     100 |   98.68 | 115,186           
  ...er-helpers.ts |   63.82 |    77.96 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    81.81 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.29 |       75 |     100 |   97.29 | 17                
  ...r-response.ts |    86.5 |    72.34 |     100 |    86.5 | ...47,764,827-836 
  fs-factory.ts    |     100 |    92.59 |     100 |     100 | 34,42,103,159     
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.13 |    95.09 |     100 |   95.13 | ...66-168,423-428 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |      95 |     87.5 |     100 |      95 | 182-188           
  ...on-archive.ts |   89.55 |    87.83 |   97.14 |   89.55 | ...32-836,888-889 
  ...ion-export.ts |     100 |    94.44 |     100 |     100 | 64                
  session-list.ts  |   93.55 |    91.01 |     100 |   93.55 | ...79,681-687,827 
  telemetry.ts     |   99.02 |    97.44 |     100 |   99.02 | ...25,639,781-783 
 src/serve/voice   |    92.7 |    91.48 |   97.67 |    92.7 |                   
  ...ice-config.ts |   84.81 |       30 |     100 |   84.81 | 91-100,104-105    
  voice-ws.ts      |   91.58 |    93.44 |      96 |   91.58 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.21 |     100 |     100 | 176               
 ...kspace-service |   90.65 |    87.73 |   91.11 |   90.65 |                   
  index.ts         |   90.13 |    87.04 |   89.74 |   90.13 | ...1464-1468,1471 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.48 |    89.33 |      98 |   92.48 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 105-118           
  ...killLoader.ts |   97.19 |    85.29 |     100 |   97.19 | 142,153-154       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   79.55 |    88.29 |   83.33 |   79.55 | ...48,178,245-246 
  ...mandLoader.ts |   97.77 |    92.15 |     100 |   97.77 | 176,183-184       
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.23 |    96.72 |     100 |   98.23 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  prompt-stash.ts  |   96.66 |    92.85 |     100 |   96.66 | 34-35             
  ...tree-lease.ts |   88.23 |    86.48 |     100 |   88.23 | ...94-199,232-233 
  ...low-loader.ts |     100 |    96.15 |     100 |     100 | 88                
  setup-github.ts  |    90.8 |    80.95 |     100 |    90.8 | ...49-450,457-458 
  ...-args-file.ts |   93.93 |    91.66 |    87.5 |   93.93 | 208-210,224-230   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.89 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |    90.4 |    87.87 |     100 |    90.4 | ...81,288,353-358 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   91.77 |    87.11 |   97.22 |   91.77 | ...99-901,904-906 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |     86.8 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.77 |   94.73 |   88.28 | ...1362,1366-1373 
  ...tGenerator.ts |   98.24 |    85.71 |     100 |   98.24 | 47                
  ...teRenderer.ts |     100 |      100 |     100 |     100 |                   
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 96-99             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |   94.09 |    79.16 |   77.77 |   94.09 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...mised-lock.ts |     100 |      100 |   66.66 |     100 |                   
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   73.08 |    75.43 |   67.41 |   73.08 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   74.29 |    72.05 |   68.57 |   74.29 | ...4112,4228-4234 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |    30.3 |      100 |       0 |    30.3 | 26-76             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   70.08 |    71.73 |   66.66 |   70.08 | ...01,324,377-382 
  ...inePresets.ts |   96.27 |    83.87 |     100 |   96.27 | ...97,402,410-412 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   58.53 |    66.18 |   51.06 |   58.53 |                   
  AuthDialog.tsx   |   59.01 |     42.1 |   16.66 |   59.01 | ...25,332-354,358 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.21 |    70.73 |   57.69 |   60.21 | ...90,794,803,806 
  useAuth.ts       |    94.6 |    73.52 |     100 |    94.6 | ...21-222,241-247 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |   82.67 |    83.11 |   89.15 |   82.67 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |    93.1 |    95.23 |     100 |    93.1 | 77-82             
  arenaCommand.ts  |   63.89 |    65.71 |   65.21 |   63.89 | ...01-606,691-699 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    77.41 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |    92.3 |    82.75 |     100 |    92.3 | ...,94-99,178,187 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...24-125,133-142 
  ...essCommand.ts |   68.06 |    54.05 |      75 |   68.06 | ...96-197,211-214 
  ...astCommand.ts |   84.17 |       75 |     100 |   84.17 | ...,91-97,125-130 
  ...ig-command.ts |   93.12 |    88.42 |     100 |   93.12 | ...07-315,321-323 
  ...extCommand.ts |   69.07 |     72.6 |   84.61 |   69.07 | ...78-611,622-623 
  copyCommand.ts   |    98.7 |    96.29 |     100 |    98.7 | 66-67,172,272,323 
  ...or-command.ts |   85.95 |    80.55 |   88.88 |   85.95 | ...68-274,298-309 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |    87.87 |     100 |     100 | ...63,231-232,245 
  ...ryCommand.tsx |   81.64 |    87.67 |    90.9 |   81.64 | ...73-278,325-332 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   65.37 |    81.88 |   94.11 |   65.37 | ...85-535,538-672 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...rt-command.ts |   82.97 |    78.57 |     100 |   82.97 | 47-52,67-70,91-96 
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   52.31 |    56.25 |   69.23 |   52.31 | ...09,277-329,390 
  forgetCommand.ts |     100 |       90 |     100 |     100 | 59                
  forkCommand.ts   |     100 |    94.11 |     100 |     100 | 96,147            
  goalCommand.ts   |   72.81 |    86.84 |   66.66 |   72.81 | ...63-168,277-280 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...oryCommand.ts |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.13 |    65.71 |   85.71 |   81.13 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  ...figCommand.ts |   52.83 |    81.25 |      70 |   52.83 | ...74-319,321-330 
  initCommand.ts   |   91.86 |       80 |     100 |   91.86 | 48,83-88          
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   94.44 |    90.14 |     100 |   94.44 | ...13-214,241-251 
  learn-command.ts |     100 |      100 |     100 |     100 |                   
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   84.78 |    82.47 |     100 |   84.78 | ...1071,1105-1110 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...ns-command.ts |   98.83 |    81.81 |     100 |   98.83 | 100               
  ...berCommand.ts |     100 |     87.5 |     100 |     100 | 46                
  renameCommand.ts |   89.06 |    88.37 |     100 |   89.06 | ...72-176,202-209 
  ...oreCommand.ts |   90.96 |    86.04 |     100 |   90.96 | ...41-146,177-178 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |   73.04 |     82.3 |      90 |   73.04 | ...20-547,561-565 
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   92.92 |       85 |   66.66 |   92.92 | ...72-177,276-281 
 src/ui/components |   71.52 |    79.07 |   79.85 |   71.52 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |    88.7 |       75 |     100 |    88.7 | 36,38-43,45       
  ...odeDialog.tsx |   87.24 |    72.22 |   33.33 |   87.24 | ...85,233-238,245 
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   95.65 |    66.66 |     100 |   95.65 | 27,52             
  ...TextInput.tsx |   88.65 |    90.41 |     100 |   88.65 | ...84-286,300-302 
  Composer.tsx     |   94.49 |    66.66 |     100 |   94.49 | ...-72,84,139,153 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  CronPill.tsx     |     100 |    93.75 |     100 |     100 | 19                
  ...ification.tsx |      84 |       60 |     100 |      84 | 23-24,40-42       
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |       0 |        0 |       0 |       0 | 1-598             
  DiffDialog.tsx   |    53.5 |     37.5 |   69.23 |    53.5 | ...32-737,747-760 
  ...ngsDialog.tsx |       0 |        0 |       0 |       0 | 1-195             
  EffortDialog.tsx |   97.36 |      100 |     100 |   97.36 | 55-56             
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   76.99 |    66.66 |      50 |   76.99 | ...96,233,255-260 
  ...ngSpinner.tsx |   68.42 |    85.71 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   93.51 |    81.81 |     100 |   93.51 | 37-38,106-109,123 
  Header.tsx       |   98.65 |    94.73 |     100 |   98.65 | 173,175           
  Help.tsx         |   98.33 |       90 |     100 |   98.33 | ...25,382,448-449 
  ...emDisplay.tsx |   79.28 |    66.99 |     100 |   79.28 | ...08,511,514-520 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   83.26 |    82.23 |      80 |   83.26 | ...2231,2257,2331 
  ...Shortcuts.tsx |     100 |       88 |     100 |     100 | 98,119            
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   96.28 |     94.8 |      50 |   96.28 | ...01,459-463,466 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   81.95 |    71.27 |     100 |   81.95 | ...1045,1050-1066 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |       0 |        0 |       0 |       0 | 1-56              
  ...onsDialog.tsx |       0 |        0 |       0 |       0 | 1-1004            
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |       0 |        0 |       0 |       0 | 1-39              
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   93.58 |    83.78 |     100 |   93.58 | ...,70-71,195-197 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   92.06 |    86.36 |   83.33 |   92.06 | ...,70-72,120-123 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.49 |    73.89 |   69.23 |   71.49 | ...1244,1250-1251 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |       0 |        0 |       0 |       0 | 1-40              
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-172             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   95.67 |    87.09 |     100 |   95.67 | ...24-125,275-277 
  ...inalImage.tsx |     100 |    93.93 |     100 |     100 | 75,129            
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |   55.05 |    69.09 |      50 |   55.05 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   69.48 |    33.33 |   66.66 |   69.48 | ...51,269,277-279 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    42.3 |    68.69 |   73.68 |    42.3 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |       0 |        0 |       0 |       0 | 1-166             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |   85.34 |    84.91 |   92.98 |   85.34 |                   
  ...sksDialog.tsx |   81.87 |    82.77 |   85.71 |   81.87 | ...1853,1965-1971 
  ...TasksPill.tsx |   78.84 |    94.28 |     100 |   78.84 | 64,109-129        
  ...gentPanel.tsx |   97.08 |    86.31 |     100 |   97.08 | 132,442-446,520   
  agent-forest.ts  |    99.2 |    93.93 |     100 |    99.2 | 258               
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
  ...e-overlay.tsx |    88.2 |    76.47 |     100 |    88.2 | ...36-138,140-142 
 ...nts/extensions |   84.32 |    76.78 |   83.33 |   84.32 |                   
  ...gerDialog.tsx |   82.15 |    76.08 |     100 |   82.15 | ...91-198,258,260 
  TabBar.tsx       |   97.29 |    88.88 |     100 |   97.29 | 33                
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   46.26 |       85 |   58.82 |   46.26 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |       0 |        0 |       0 |       0 | 1-145             
  ...nListStep.tsx |   75.26 |    88.37 |   66.66 |   75.26 | ...53,174,203-209 
  ...electStep.tsx |       0 |        0 |       0 |       0 | 1-83              
  ...nfirmStep.tsx |   16.32 |      100 |       0 |   16.32 | 28-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
 ...xtensions/tabs |   71.92 |    68.21 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.44 |   83.33 |   75.49 | ...77,782-783,820 
  SourcesTab.tsx   |   71.67 |    70.47 |   77.77 |   71.67 | ...28,547,621-633 
 ...tensions/views |   50.97 |    52.38 |   20.83 |   50.97 |                   
  ...tionsView.tsx |   73.75 |    56.36 |   66.66 |   73.75 | ...30,353,369-374 
  ...tionsView.tsx |   43.45 |    44.82 |    6.66 |   43.45 | ...98-405,408-420 
  ...etailView.tsx |    9.56 |      100 |       0 |    9.56 | 40-67,70-158      
 ...mponents/hooks |   87.11 |    81.37 |   91.89 |   87.11 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.91 |    63.44 |   70.58 |   40.91 |                   
  ...ealthPill.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   90.26 |    86.89 |   85.57 |   90.26 |                   
  ...ionDialog.tsx |   89.23 |     84.9 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   94.11 |    95.91 |   76.92 |   94.11 | ...47-349,352-355 
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   81.73 |     65.9 |      75 |   81.73 | ...10-214,222,245 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   91.87 |    82.63 |     100 |   91.87 | ...49-651,658-660 
  ...upMessage.tsx |   98.38 |    95.38 |     100 |   98.38 | 188-191,422       
  ToolMessage.tsx  |   93.06 |    86.32 |   93.75 |   93.06 | ...1037,1082-1084 
 ...ponents/shared |   86.29 |    82.41 |   94.17 |   86.29 |                   
  ...ctionList.tsx |     100 |      100 |      75 |     100 |                   
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  ...rBoundary.tsx |     100 |      100 |     100 |     100 |                   
  MaxSizedBox.tsx  |   84.71 |    86.95 |      90 |   84.71 | ...67-568,685-686 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...ontroller.tsx |     100 |    83.33 |     100 |     100 | 73,93-95          
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   81.48 |    84.84 |     100 |   81.48 | 46-66,73-76       
  StaticRender.tsx |     100 |      100 |     100 |     100 |                   
  TextInput.tsx    |    80.8 |    67.24 |      80 |    80.8 | ...36-240,252-258 
  ...ontroller.tsx |     100 |    81.81 |     100 |     100 | 59-62             
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   91.49 |    86.66 |   83.33 |   91.49 | ...18-846,859,959 
  text-buffer.ts   |   85.98 |    81.81 |   97.91 |   85.98 | ...2664,2762-2763 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |       0 |        0 |       0 |       0 |                   
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-681             
 ...ents/subagents |       0 |        0 |       0 |       0 |                   
  constants.ts     |       0 |        0 |       0 |       0 | 1-71              
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |       0 |        0 |       0 |       0 | 1-190             
  types.ts         |       0 |        0 |       0 |       0 | 1-125             
  utils.ts         |       0 |        0 |       0 |       0 | 1-102             
 ...bagents/create |       0 |        0 |       0 |       0 |                   
  ...ionWizard.tsx |       0 |        0 |       0 |       0 | 1-299             
  ...rSelector.tsx |       0 |        0 |       0 |       0 | 1-85              
  ...onSummary.tsx |       0 |        0 |       0 |       0 | 1-331             
  ...tionInput.tsx |       0 |        0 |       0 |       0 | 1-177             
  ...dSelector.tsx |       0 |        0 |       0 |       0 | 1-63              
  ...nSelector.tsx |       0 |        0 |       0 |       0 | 1-58              
  ...EntryStep.tsx |       0 |        0 |       0 |       0 | 1-78              
  ToolSelector.tsx |       0 |        0 |       0 |       0 | 1-253             
 ...bagents/manage |   14.14 |    53.19 |    37.5 |   14.14 |                   
  ...ctionStep.tsx |       0 |        0 |       0 |       0 | 1-103             
  ...eleteStep.tsx |       0 |        0 |       0 |       0 | 1-62              
  ...tEditStep.tsx |       0 |        0 |       0 |       0 | 1-124             
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |       0 |        0 |       0 |       0 | 1-73              
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-341             
 ...mponents/views |    70.1 |    72.89 |   61.11 |    70.1 |                   
  ContextUsage.tsx |   71.49 |    64.86 |      80 |   71.49 | ...30-436,473-567 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   84.16 |    81.83 |   85.13 |   84.16 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.83 |    68.51 |   42.85 |   93.83 | ...44,281-285,317 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   85.65 |    84.85 |     100 |   85.65 | ...1612-1614,1620 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   80.77 |       80 |    92.3 |   80.77 | ...31-434,443-446 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...edContext.tsx |     100 |      100 |      50 |     100 |                   
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 156-157           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 235-236           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
  ...rtContext.tsx |     100 |      100 |     100 |     100 |                   
 src/ui/daemon     |   88.35 |    73.51 |   95.45 |   88.35 |                   
  ...ui-adapter.ts |   88.35 |    73.51 |   95.45 |   88.35 | ...74,792-793,879 
 src/ui/editors    |       0 |        0 |       0 |       0 |                   
  ...ngsManager.ts |       0 |        0 |       0 |       0 | 1-67              
 src/ui/hooks      |   85.49 |    82.95 |   88.01 |   85.49 |                   
  ...dProcessor.ts |   85.53 |    85.13 |     100 |   85.53 | ...-970,1017-1018 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...87-288,293-294 
  ...dProcessor.ts |   85.75 |     68.4 |   81.81 |   85.75 | ...1464,1485-1489 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.ts |     100 |      100 |     100 |     100 |                   
  ...ng-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...oice-input.ts |   92.36 |    81.95 |   66.66 |   92.36 | ...00,502-503,658 
  ...ke-repaint.ts |     100 |      100 |     100 |     100 |                   
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      52 |    63.63 |     100 |      52 | ...59,67-70,76-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   86.44 |    88.48 |     100 |   86.44 | ...14-515,525-541 
  ...ifications.ts |   87.82 |    96.77 |     100 |   87.82 | 138-152           
  ...tIndicator.ts |   88.28 |    81.57 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.89 |    77.55 |     100 |   94.89 | 164-168,257,263   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   95.45 |    83.01 |     100 |   95.45 | ...60-161,285-288 
  ...ompletion.tsx |   97.09 |    87.09 |     100 |   97.09 | ...23-324,334-335 
  ...dMigration.ts |    92.1 |    88.88 |     100 |    92.1 | 42-44             
  useCompletion.ts |   96.29 |    90.56 |     100 |   96.29 | ...17-218,222-223 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   78.26 |       50 |     100 |   78.26 | ...2,75-79,96-104 
  ...eteCommand.ts |   89.52 |    90.69 |     100 |   89.52 | ...98-106,114-115 
  ...ialogClose.ts |   36.11 |       10 |     100 |   36.11 | ...89-195,202-207 
  useDiffData.ts   |       0 |        0 |       0 |       0 | 1-87              
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.72 |    92.98 |     100 |   93.72 | ...87-291,314-320 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |    63.9 |    76.47 |   66.66 |    63.9 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |    93.33 |     100 |     100 | 62                
  ...ggestions.tsx |   96.47 |    78.94 |     100 |   96.47 | 121,155-156       
  ...miniStream.ts |   86.08 |    81.23 |   76.92 |   86.08 | ...5198-5200,5202 
  ...BranchName.ts |     100 |    94.44 |     100 |     100 | 54                
  ...oryManager.ts |   98.38 |    98.85 |     100 |   98.38 | 141-144           
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |   22.58 |      100 |      50 |   22.58 | 11-32,44-85       
  ...gIndicator.ts |     100 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   10.52 |      100 |       0 |   10.52 | 36-75             
  ...cpApproval.ts |   93.12 |    86.11 |     100 |   93.12 | ...24-127,139-140 
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |   83.14 |    78.57 |     100 |   83.14 | 54-63,74-79       
  ...ssageQueue.ts |     100 |     97.4 |     100 |     100 | 175,262           
  ...delCommand.ts |     100 |       96 |     100 |     100 | 61                
  ...ouseEvents.ts |   94.89 |       95 |   83.33 |   94.89 | 78-82             
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derUpdates.ts |    87.4 |    78.78 |     100 |    87.4 | ...71,321-333,381 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   89.48 |    88.88 |     100 |   89.48 | ...54-456,489-499 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   95.26 |    77.14 |     100 |   95.26 | 120-121,223-228   
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.22 |     100 |   97.12 | ...92-193,247-250 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |    97.29 |     100 |     100 | 82                
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   93.28 |    80.95 |     100 |   93.28 | ...96,153-154,164 
  ...oryCommand.ts |   85.48 |    58.33 |     100 |   85.48 | 22-28,40,71       
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.85 |    85.13 |   94.73 |   82.85 | ...78-680,688-724 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   97.13 |    93.33 |     100 |   97.13 | ...78-382,478-485 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   67.34 |    58.82 |   66.66 |   67.34 | 52-53,61-68,79-85 
  ...rminalSize.ts |     100 |      100 |     100 |     100 |                   
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   97.59 |    94.73 |     100 |   97.59 | 17-18             
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |    90.47 |     100 |     100 | 112,134           
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    91.2 |    89.47 |     100 |    91.2 |                   
  ...AppLayout.tsx |    90.9 |     87.5 |     100 |    90.9 | 60-62,110-115,151 
  ...AppLayout.tsx |   91.66 |    92.85 |     100 |   91.66 | 75-80             
 src/ui/models     |   80.72 |       80 |   71.42 |   80.72 |                   
  ...ableModels.ts |   80.72 |       80 |   71.42 |   80.72 | ...,61-71,125-127 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 src/ui/selection  |   86.47 |    79.88 |   96.66 |   86.47 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   92.72 |       90 |     100 |   92.72 | 37-38,67-68       
  ...tion-state.ts |   85.71 |      100 |   88.88 |   85.71 | 51-58             
  ...ction-text.ts |   92.85 |    92.45 |     100 |   92.85 | 30-34,114-115     
  ...selection.tsx |   80.31 |    59.64 |     100 |   80.31 | ...13-314,330-331 
 src/ui/state      |      95 |    81.81 |     100 |      95 |                   
  extensions.ts    |      95 |    81.81 |     100 |      95 | 69-70,89          
 src/ui/themes     |    98.5 |    73.17 |     100 |    98.5 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |   99.23 |    97.05 |     100 |   99.23 | 277-278           
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   88.68 |    84.52 |     100 |   88.68 | ...83-392,397-398 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   87.13 |    85.34 |   95.62 |   87.13 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   79.84 |     75.6 |     100 |   79.84 | ...66,270,328-329 
  ...wnDisplay.tsx |   92.87 |    93.46 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.38 |    81.91 |   95.23 |   92.38 | ...43-746,799-804 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |    96.7 |     87.5 |     100 |    96.7 | 170-177,278       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |    52.9 |    74.15 |    92.3 |    52.9 | ...29,632-641,644 
  commandUtils.ts  |   98.38 |    92.38 |     100 |   98.38 | 108,136-137,343   
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   73.84 |    73.91 |     100 |   73.84 | ...34,36-40,42-46 
  formatters.ts    |   94.87 |    98.18 |     100 |   94.87 | 116-119           
  goal-runtime.ts  |   91.42 |       95 |     100 |   91.42 | 32-34             
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |       95 |     100 |     100 | 44,103            
  historyUtils.ts  |   96.03 |     97.1 |     100 |   96.03 | 103-106           
  ...mage-parts.ts |   97.75 |    94.87 |     100 |   97.75 | 82-83             
  inline-math.ts   |   98.48 |    95.23 |     100 |   98.48 | 129-130           
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   68.81 |       75 |   66.66 |   68.81 | ...27-132,160-161 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  list-mouse.ts    |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |       95 |     100 |     100 | 81                
  ...nUtilities.ts |   98.72 |    94.36 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.51 |    70.16 |   95.12 |   86.51 | ...1286,1326-1332 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   92.85 |    74.19 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   90.43 |    78.33 |     100 |   90.43 | ...59,244,248-249 
  ...red-height.ts |   98.38 |    97.14 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   82.73 |    79.48 |     100 |   82.73 | ...84-606,737-738 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...evel-label.ts |   77.77 |    66.66 |     100 |   77.77 | 18,22-24          
  ...are-cursor.ts |   89.47 |    85.71 |     100 |   89.47 | 39-44             
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  suggestions.ts   |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...e-renderer.ts |   90.61 |    83.44 |     100 |   90.61 | ...80,482-484,607 
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.94 |    95.45 |   94.11 |   97.94 | ...82-283,443-444 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   90.42 |    92.85 |     100 |   90.42 | ...06-207,240-241 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |    92.75 |     100 |     100 | 227-239,331       
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |     60.3 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    66.38 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    50.68 |     100 |   80.42 | ...59-364,376-378 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...ort/formatters |   52.92 |    47.22 |   71.42 |   52.92 |                   
  html.ts          |   84.61 |       50 |     100 |   84.61 | ...53,57-58,62-63 
  json.ts          |     100 |      100 |     100 |     100 |                   
  jsonl.ts         |   82.45 |     37.5 |     100 |   82.45 | ...48,50-51,65-66 
  markdown.ts      |   36.32 |    47.05 |      50 |   36.32 | ...16-219,233-295 
 src/ui/voice      |   81.27 |    79.92 |   81.94 |   81.27 |                   
  ...d-recorder.ts |     6.2 |      100 |       0 |     6.2 | ...33-159,162-163 
  ...o-recorder.ts |   84.61 |    93.33 |   57.14 |   84.61 | ...16-117,131-136 
  ...me-session.ts |   91.09 |     92.1 |     100 |   91.09 | ...99,305,316-319 
  sox-recorder.ts  |    92.7 |    71.87 |     100 |    92.7 | ...34-135,153-154 
  ...ailability.ts |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |     100 |      100 |     100 |     100 |                   
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  ...e-recorder.ts |   88.29 |    67.74 |   81.81 |   88.29 | ...,98-99,112,115 
  voice-refine.ts  |     100 |    93.33 |     100 |     100 | 92                
  ...ream-retry.ts |   86.79 |       70 |     100 |   86.79 | 16-18,48-49,59-60 
  ...am-session.ts |   88.02 |    66.66 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |    81.5 |    87.04 |   92.57 |    81.5 |                   
  ...p-profiler.ts |   98.39 |    92.59 |     100 |   98.39 | 141,185,235       
  acpModelUtils.ts |   97.36 |    95.19 |     100 |   97.36 | ...09-210,214-215 
  apiPreconnect.ts |   96.74 |    94.59 |     100 |   96.74 | 167-170           
  ...ol-call-id.ts |   84.61 |       60 |     100 |   84.61 | 26-27,37-38       
  ...ng-failure.ts |     100 |       95 |     100 |     100 | 72                
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  ...-api-error.ts |     100 |    96.42 |     100 |     100 | 14                
  cleanup.ts       |   84.05 |    94.11 |      80 |   84.05 | 80,111-121        
  commands.ts      |   97.45 |    96.66 |     100 |   97.45 | 153-155           
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.73 |    73.23 |   88.88 |   70.73 | ...27,430-431,438 
  deepMerge.ts     |     100 |    89.65 |     100 |     100 | 41-43,49          
  ...re-runtime.ts |     100 |      100 |     100 |     100 |                   
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...73,371,373-374 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.64 |     100 |   97.56 | 69-70,304-305     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |   92.85 |    86.66 |     100 |   92.85 | ...13-116,164-167 
  ...AutoUpdate.ts |    93.1 |       94 |      90 |    93.1 | 103,108,179-190   
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.68 |    94.28 |     100 |   97.68 | ...64,381-382,427 
  jsonc-editor.ts  |   93.18 |    92.66 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.05 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   89.31 |    77.33 |     100 |   89.31 | ...87,303-304,344 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   94.25 |    91.17 |     100 |   94.25 | ...30,436,439-443 
  ...iveHelpers.ts |   95.13 |    91.79 |     100 |   95.13 | ...53-454,552,565 
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  ...uggestions.ts |   84.29 |    70.83 |     100 |   84.29 | 70-76,92-103      
  processUtils.ts  |    92.3 |       80 |     100 |    92.3 | 45-46             
  readStdin.ts     |   93.67 |    94.11 |   85.71 |   93.67 | 79-83             
  relaunch.ts      |   95.87 |    89.28 |     100 |   95.87 | 103-105,131       
  resolvePath.ts   |     100 |      100 |     100 |     100 |                   
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox-path.ts  |     100 |      100 |     100 |     100 |                   
  sandbox.ts       |   45.87 |    56.93 |   76.92 |   45.87 | ...1040,1052-1075 
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.ts |     100 |      100 |     100 |     100 |                   
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.35 |    89.57 |      90 |   82.35 | ...25-743,750-758 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   39.81 |    77.44 |   62.16 |   39.81 | ...1193,1196-1215 
  ...upProfiler.ts |   98.47 |    94.66 |     100 |   98.47 | 132-133,308       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       90 |     100 |     100 | 23                
  systemInfo.ts    |   95.12 |    90.27 |     100 |   95.12 | ...54-255,260-264 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  ...alSequence.ts |     100 |    97.61 |     100 |     100 | 60                
  ...iffPreview.ts |   76.47 |       25 |     100 |   76.47 | 13,17,23-24       
  ...on-handler.ts |    73.8 |       75 |     100 |    73.8 | 17-18,25-26,67-73 
  ...e-relaunch.ts |   89.61 |    86.66 |      50 |   89.61 | 56-61,83-84       
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   87.75 |       75 |     100 |   87.75 | 47-48,53-54,57-58 
  version.ts       |     100 |    66.66 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |   95.45 |    93.33 |     100 |   95.45 | 54-55             
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   91.63 |    91.02 |      95 |   91.63 |                   
  cleanup.ts       |   95.77 |    95.83 |     100 |   95.77 | 70-72             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   91.91 |    90.47 |    87.5 |   91.91 | 58-62,73,131-135  
  throttledOnce.ts |   86.66 |     86.2 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   87.85 |    86.35 |   89.39 |   87.85 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   90.38 |    84.54 |   94.85 |   90.38 |                   
  ...transcript.ts |   87.63 |    83.52 |     100 |   87.63 | ...80,588,594-598 
  ...ent-resume.ts |   85.59 |    77.55 |   83.33 |   85.59 | ...1793-1797,1800 
  ...ound-tasks.ts |   94.63 |    90.13 |   96.38 |   94.63 | ...1773,1793-1796 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   94.79 |     87.7 |     100 |   94.79 | ...1067,1081-1083 
  ...w-snapshot.ts |   92.12 |    77.14 |     100 |   92.12 | ...65,189,196-198 
 src/agents/arena  |   76.32 |    67.71 |   78.94 |   76.32 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.11 |    64.51 |   78.57 |   75.11 | ...1887,1893-1894 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   78.09 |    85.23 |   76.28 |   78.09 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    90.9 |    85.36 |   93.33 |    90.9 | ...70,672,674-675 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |    91.1 |    86.68 |   89.23 |    91.1 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   85.07 |     76.8 |   77.77 |   85.07 | ...2291,2337-2339 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    89.41 |   83.33 |   93.49 | ...96-497,500-501 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.34 |      100 |    92.3 |   98.34 | 81-82             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...-scheduler.ts |   97.43 |    96.36 |     100 |   97.43 | 128-130           
  ...ow-journal.ts |   91.76 |    75.86 |     100 |   91.76 | ...38-139,179-181 
  ...chestrator.ts |    92.4 |       90 |   83.78 |    92.4 | ...1862,1911-1914 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...low-runner.ts |   94.85 |     87.5 |   92.85 |   94.85 | ...93,260,280-283 
  ...ow-sandbox.ts |   96.85 |    91.28 |     100 |   96.85 | ...1705,1711-1712 
  ...flow-saved.ts |   96.51 |    94.36 |     100 |   96.51 | 134-135,234-237   
  ...flow-stall.ts |    97.9 |    83.33 |     100 |    97.9 | 138-139,236       
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   82.04 |    84.17 |   88.97 |   82.04 |                   
  TeamManager.ts   |   72.02 |    79.41 |   79.24 |   72.02 | ...1632,1655-1656 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   96.02 |    87.23 |     100 |   96.02 | 352-358           
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   89.24 |    82.82 |     100 |   89.24 | ...-994,1038-1039 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    94.26 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    84.21 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.08 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   84.98 |    87.13 |   75.37 |   84.98 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   84.29 |    86.85 |   73.79 |   84.29 | ...8350,8354-8355 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.39 |    91.57 |   88.23 |   94.39 | ...45-446,449-450 
 ...nfirmation-bus |   98.27 |    97.14 |     100 |   98.27 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   92.34 |    88.04 |   93.26 |   92.34 |                   
  baseLlmClient.ts |    88.4 |     83.8 |   81.81 |    88.4 | ...59,672,678-680 
  client.ts        |   91.95 |    87.18 |   91.56 |   91.95 | ...3928,4026-4027 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...96-497,542-548 
  ...lScheduler.ts |   90.04 |    84.67 |   96.15 |   90.04 | ...6215,6243-6259 
  geminiChat.ts    |    94.7 |    90.12 |   95.53 |    94.7 | ...5052,5100-5101 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |       96 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  ...ream-error.ts |     100 |      100 |     100 |     100 |                   
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...lay-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...dispatcher.ts |     100 |      100 |     100 |     100 |                   
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   93.54 |    83.33 |      50 |   93.54 | 49-50             
  ...on-helpers.ts |   93.49 |    78.57 |     100 |   93.49 | ...10-211,228-229 
  ...issionFlow.ts |   98.97 |    96.96 |     100 |   98.97 | 107               
  ...try-policy.ts |     100 |      100 |     100 |     100 |                   
  ...ell-policy.ts |   94.89 |    88.54 |     100 |   94.89 | ...51-252,297-298 
  prompts.ts       |   93.64 |    91.42 |   83.33 |   93.64 | ...1209,1412-1413 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |    97.9 |    81.15 |   88.23 |    97.9 | 117,124-125,130   
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |     92.1 |     100 |     100 | 87,122-139        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...tion-guard.ts |   90.38 |    94.73 |     100 |   90.38 | 68-72             
  ...allIdUtils.ts |   98.41 |    93.47 |     100 |   98.41 | 36,45             
  ...okTriggers.ts |   99.45 |    92.43 |     100 |   99.45 | 182,193           
  ...terruption.ts |     100 |     92.3 |     100 |     100 | 86,104            
  turn.ts          |   98.67 |    93.12 |     100 |   98.67 | ...79,707-708,755 
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   96.33 |    88.12 |   96.15 |   96.33 |                   
  ...tGenerator.ts |   97.24 |    86.72 |   94.87 |   97.24 | ...1429,1458,1469 
  converter.ts     |   96.19 |    89.25 |     100 |   96.19 | ...1329,1550-1552 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   88.78 |    72.36 |   89.47 |   88.78 |                   
  ...tGenerator.ts |   87.18 |    71.83 |   88.88 |   87.18 | ...58-364,382-383 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |    95.6 |    88.74 |    92.3 |    95.6 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   95.52 |    87.88 |   91.89 |   95.52 | ...1195-1196,1224 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.63 |    90.43 |   95.61 |   91.63 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   91.15 |    89.32 |   96.87 |   91.15 | ...1914,2083-2098 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   60.31 |       75 |      50 |   60.31 | ...71,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   95.45 |    91.18 |     100 |   95.45 | ...1301,1309,1408 
  ...ix-caching.ts |   95.23 |    92.85 |     100 |   95.23 | 45-46,69-70       
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   97.19 |    90.44 |   98.36 |   97.19 |                   
  dashscope.ts     |   98.36 |    92.99 |   95.65 |   98.36 | ...93-494,636-637 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.16 |    96.96 |     100 |   99.16 | 198               
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
  zai.ts           |   92.13 |    82.14 |     100 |   92.13 | ...,39-40,135-137 
 src/extension     |   87.27 |    84.01 |   92.52 |   87.27 |                   
  ...ive-safety.ts |     100 |      100 |     100 |     100 |                   
  ...-converter.ts |   80.55 |    73.66 |     100 |   80.55 | ...1133,1179-1180 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |     100 |      100 |     100 |     100 |                   
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   90.85 |    86.38 |   97.87 |   90.85 | ...1218-1224,1268 
  ...ionManager.ts |   82.24 |    80.14 |   81.52 |   82.24 | ...2730,2752-2753 
  ...references.ts |     100 |     90.9 |     100 |     100 | ...05,129,197,200 
  ...onSettings.ts |    92.3 |     94.4 |     100 |    92.3 | ...98-501,570-571 
  ...-converter.ts |    75.9 |    85.36 |   85.71 |    75.9 | ...98,202,214-248 
  github.ts        |   90.42 |    82.66 |     100 |   90.42 | ...0,990-991,1001 
  http-client.ts   |   84.61 |       80 |     100 |   84.61 | 20-21             
  i18n.ts          |   78.26 |       96 |      50 |   78.26 | 104-110,116-123   
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   88.39 |    83.11 |     100 |   88.39 | ...08,494,507-508 
  ...ork-policy.ts |   89.72 |       90 |     100 |   89.72 | ...36,148-154,156 
  npm.ts           |   89.02 |    81.81 |     100 |   89.02 | ...86-688,695-700 
  override.ts      |   94.11 |    93.33 |     100 |   94.11 | 63-64,81-82       
  ...-converter.ts |   94.89 |    90.41 |     100 |   94.89 | ...50-151,222-224 
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  ...ceRegistry.ts |   94.01 |    83.14 |     100 |   94.01 | ...38-344,365-366 
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.95 |    84.21 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |       81 |   89.47 |   85.77 | ...02-205,260-261 
 src/followup      |    79.9 |    78.92 |    90.9 |    79.9 |                   
  followupState.ts |   98.44 |    95.74 |     100 |   98.44 | 236-237           
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   96.29 |    88.88 |     100 |   96.29 | 78,108,122        
  speculation.ts   |   71.76 |    64.76 |   71.42 |   71.76 | ...53-654,661-662 
  ...onToolGate.ts |   97.97 |     87.5 |     100 |   97.97 | 105,110           
  ...nGenerator.ts |   72.03 |    81.15 |   83.33 |   72.03 | ...68-219,331-333 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |    93.3 |    89.05 |    94.6 |    93.3 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  ...t-verifier.ts |   96.27 |     90.9 |     100 |   96.27 | ...20,143-146,163 
  ...checkpoint.ts |   81.48 |    76.19 |     100 |   81.48 | ...02-105,115-118 
  goal-evidence.ts |   88.79 |     88.5 |   96.42 |   88.79 | ...04-805,828-831 
  ...projection.ts |   66.66 |    72.97 |   33.33 |   66.66 | ...83,186,190-192 
  ...ersistence.ts |   87.73 |    84.84 |      80 |   87.73 | ...-94,97,101-106 
  goal-protocol.ts |   95.74 |    93.33 |     100 |   95.74 | 154-155           
  goal-reducer.ts  |    93.4 |    90.65 |   96.96 |    93.4 | ...27,501,519-520 
  goal-runtime.ts  |   97.62 |     89.9 |     100 |   97.62 | ...1049,1169-1170 
  goal-tools.ts    |   98.22 |    93.02 |      95 |   98.22 | ...46-147,248-249 
  ...rn-context.ts |     100 |      100 |     100 |     100 |                   
  goal-verifier.ts |   92.46 |    92.85 |     100 |   92.46 | ...69-172,185-187 
  goal-wire.ts     |       0 |        0 |       0 |       0 | 1-28              
  goalHook.ts      |   96.91 |    92.42 |     100 |   96.91 | 115-120,221-222   
  goalJudge.ts     |   95.84 |    87.09 |     100 |   95.84 | ...55-356,448-449 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   88.07 |    86.24 |   88.54 |   88.07 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  context-usage.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.57 |    91.48 |     100 |   96.57 | ...20-321,402,404 
  ...entHandler.ts |   95.57 |    84.76 |   94.73 |   95.57 | ...1040-1041,1051 
  hookPlanner.ts   |   87.55 |    85.54 |   86.66 |   87.55 | ...22-226,233-244 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.65 |    72.34 |   66.66 |   62.65 | ...70-771,780-781 
  hookSystem.ts    |   87.64 |     98.5 |   70.83 |   87.64 | ...58-759,765-766 
  ...HookRunner.ts |   79.06 |    66.66 |      80 |   79.06 | ...33-434,452-456 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   94.19 |    84.37 |   81.81 |   94.19 | ...76-384,458-459 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   94.87 |    88.88 |     100 |   94.87 | ...84,325,327-329 
  ssrfGuard.ts     |   86.45 |    87.91 |     100 |   86.45 | ...85,289-295,301 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.25 |    96.12 |   88.88 |   94.25 | ...46-547,632-636 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
  ...it-context.ts |     100 |      100 |     100 |     100 |                   
 src/ide           |   76.98 |    85.03 |   79.03 |   76.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   69.16 |    84.65 |   68.29 |   69.16 | ...1068,1097-1105 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   58.96 |    70.57 |   66.14 |   58.96 |                   
  ...nfigLoader.ts |   80.55 |       72 |   95.45 |   80.55 | ...02-504,508-514 
  ...ionFactory.ts |   42.81 |    73.07 |      50 |   42.81 | ...76-427,433-450 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   75.73 |     80.1 |   79.66 |   75.73 | ...1346,1352-1382 
  ...eLspClient.ts |   32.78 |       80 |   16.66 |   32.78 | ...89-293,299-300 
  ...LspService.ts |      60 |    73.36 |   78.26 |      60 | ...1575,1635-1645 
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |    82.3 |    77.81 |   78.33 |    82.3 |                   
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   79.31 |    58.06 |     100 |   79.31 | ...26-933,940-942 
  ...en-storage.ts |   98.78 |    97.95 |     100 |   98.78 | 106-107           
  oauth-utils.ts   |   73.61 |    85.48 |    92.3 |   73.61 | ...46-366,392-421 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   82.12 |    88.19 |   89.28 |   82.12 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   87.08 |    87.03 |   95.23 |   87.08 | ...00-201,214-215 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   87.83 |    83.94 |   90.47 |   87.83 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.36 |    96.63 |   96.42 |   97.36 | ...91-293,367-368 
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    83.33 |     100 |     100 | 136,146           
  entries.ts       |   75.59 |    84.84 |   83.33 |   75.59 | ...56-157,172-180 
  extract.ts       |   92.41 |    79.41 |     100 |   92.41 | 56-61,100,119-122 
  ...entPlanner.ts |   91.59 |    76.74 |     100 |   91.59 | ...05,114-117,293 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |   81.83 |       75 |   83.33 |   81.83 | ...51,474,478-507 
  indexer.ts       |   94.14 |       84 |     100 |   94.14 | ...32-233,334,337 
  ...kill-agent.ts |   97.94 |    89.36 |     100 |   97.94 | 82-83,179-180     
  manager.ts       |    78.4 |    82.29 |   77.77 |    78.4 | ...1482,1495-1497 
  ...ent-config.ts |   86.99 |    82.69 |   86.36 |   86.99 | ...69,389,396-402 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |     100 |      100 |     100 |     100 |                   
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    87.03 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  refresh.ts       |   93.58 |    89.58 |     100 |   93.58 | ...75-176,183-184 
  ...ceSelector.ts |    93.1 |    81.81 |     100 |    93.1 | ...25,127-128,136 
  remember.ts      |   98.89 |    90.19 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    77.41 |     100 |   93.12 | ...08-109,154,157 
  scopes.ts        |     100 |      100 |     100 |     100 |                   
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   77.24 |    74.07 |   72.22 |   77.24 | ...52-456,459,465 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |     82.6 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |    81.53 |   81.81 |   81.21 | ...63-277,291-296 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.55 |    88.97 |   91.13 |   92.55 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   97.77 |    91.83 |     100 |   97.77 | 155,161,171       
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.11 |     100 |     100 | 177,261           
  modelsConfig.ts  |   89.36 |    86.93 |   88.09 |   89.36 | ...1404,1433-1434 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/output        |     100 |      100 |     100 |     100 |                   
  ...-formatter.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/permissions   |   83.79 |    91.16 |   71.07 |   83.79 |                   
  autoMode.ts      |   97.66 |    93.13 |     100 |   97.66 | ...82-589,635,712 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  ...e-commands.ts |   86.77 |     73.8 |     100 |   86.77 | 131-141,210-214   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   86.63 |    89.01 |      80 |   86.63 | ...1111,1217-1221 
  rule-parser.ts   |   94.49 |     92.7 |     100 |   94.49 | ...1447,1481-1483 
  ...-semantics.ts |   70.44 |    91.07 |   46.66 |   70.44 | ...2237,2311-2314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   99.04 |    95.23 |     100 |   99.04 |                   
  system-prompt.ts |   99.04 |    95.23 |     100 |   99.04 | 220               
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/providers     |   83.71 |     78.5 |   81.25 |   83.71 |                   
  all-providers.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   93.11 |     84.5 |     100 |   93.11 | ...56-257,330-331 
  ...der-config.ts |   75.85 |    73.84 |   78.26 |   75.85 | ...73-474,502-503 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.82 |    91.66 |   63.63 |   97.82 |                   
  ...oding-plan.ts |   87.34 |      100 |       0 |   87.34 | 82-84,87-89,91-94 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.05 |    81.25 |      75 |   97.05 | 118-119           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  grok.ts          |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  requesty.ts      |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |   85.41 |    78.52 |   95.89 |   85.41 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.79 |    73.29 |   90.62 |   82.79 | ...1205-1221,1251 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   89.66 |    84.56 |   96.91 |   89.66 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |    98.5 |     87.5 |     100 |    98.5 | 81-82,105,476-477 
  ...ionService.ts |   97.51 |    96.15 |     100 |   97.51 | ...,929,1072-1080 
  ...ingService.ts |   91.41 |    85.15 |   95.65 |   91.41 | ...2116,2143-2144 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    93.93 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.17 |    90.45 |      98 |   94.17 | ...1333,1736-1737 
  cronTasksFile.ts |   95.49 |    90.82 |     100 |   95.49 | ...37,346-347,483 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |    97.5 |    96.07 |     100 |    97.5 | 349-350,363-364   
  ...temService.ts |    92.8 |    84.68 |   94.11 |    92.8 | ...41,467-474,519 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    73.7 |    68.49 |   95.83 |    73.7 | ...2196,2225-2226 
  ...on-service.ts |   87.38 |       72 |     100 |   87.38 | ...01-305,343-344 
  ...references.ts |   98.39 |    88.76 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.26 |    97.35 |     100 |   98.26 | ...13-714,761-762 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.52 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |    97.3 |    91.22 |     100 |    97.3 | ...53-454,611-612 
  ...ttachments.ts |   97.74 |    90.85 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   90.95 |    78.75 |     100 |   90.95 | ...78,963-964,992 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |    98.5 |    94.11 |    90.9 |    98.5 | 64-65             
  ...ipt-reader.ts |   94.55 |    89.78 |   96.66 |   94.55 | ...1353-1354,1422 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   82.45 |    74.11 |   97.61 |   82.45 | ...2433,2445-2448 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.79 |    83.72 |   97.18 |   88.79 | ...2477,2553-2573 
  sessionTitle.ts  |   94.19 |    73.21 |     100 |   94.19 | ...43-246,277-278 
  ...ionService.ts |    84.4 |    78.45 |   97.18 |    84.4 | ...2493,2499-2504 
  ...pInhibitor.ts |   97.42 |    92.77 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    88.23 |     100 |     100 | 118-119           
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...rd-service.ts |     100 |    88.37 |     100 |     100 | ...29,145-146,241 
  ...oryService.ts |   90.72 |    84.07 |     100 |   90.72 | ...06-509,561-562 
  ...reeCleanup.ts |   14.42 |      100 |   33.33 |   14.42 | 58-186            
  ...ionService.ts |   87.98 |    86.84 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |    98.9 |    95.08 |     100 |    98.9 |                   
  microcompact.ts  |    98.9 |    95.08 |     100 |    98.9 | ...40,749,758-759 
 ...s/visionBridge |   98.81 |    92.12 |     100 |   98.81 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   89.29 |    85.89 |   93.61 |   89.29 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-curator.ts |   89.71 |    81.54 |     100 |   89.71 | ...01-902,904-907 
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   84.82 |    85.29 |   83.33 |   84.82 | ...1243,1250-1254 
  skill-paths.ts   |   90.42 |     87.5 |     100 |   90.42 | ...19-120,125-126 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |    98.03 |     100 |   97.91 | 277-278           
 ...ataviz/scripts |   80.06 |    95.23 |   88.23 |   80.06 |                   
  ...te_palette.js |   80.06 |    95.23 |   88.23 |   80.06 | 261-296,306-328   
 ...s/bundled/loop |   97.48 |    95.77 |     100 |   97.48 |                   
  ...omous-loop.ts |     100 |      100 |     100 |     100 |                   
  ...-task-file.ts |   94.85 |     92.4 |     100 |   94.85 | ...56,367,375-376 
  ...k-resolver.ts |     100 |      100 |     100 |     100 |                   
 src/subagents     |   87.72 |    89.01 |   96.55 |   87.72 |                   
  ...ter-schema.ts |     100 |    98.07 |     100 |     100 | 99                
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   84.48 |    85.91 |   94.87 |   84.48 | ...1582,1659-1660 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   81.73 |    83.97 |   84.83 |   81.73 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.08 |    80.95 |     100 |   99.08 | 185,199           
  ...on-tracing.ts |   76.31 |    74.62 |   73.68 |   76.31 | ...80,387-389,405 
  ...attributes.ts |   95.15 |    87.27 |     100 |   95.15 | ...97-198,216-217 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |   96.85 |    85.71 |     100 |   96.85 | 170-173           
  ...-exporters.ts |   65.78 |    83.33 |   55.55 |   65.78 | ...04-105,108-109 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |       99 |     100 |     100 | 99                
  ...ai-request.ts |   87.52 |    92.79 |   83.78 |   87.52 | ...55-561,564-570 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |    99.1 |    95.72 |      95 |    99.1 | 145,369-370       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   60.03 |    76.51 |   66.07 |   60.03 | ...1484,1501-1521 
  metrics.ts       |   80.37 |    82.35 |   80.95 |   80.37 | ...1150,1153-1164 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   91.06 |    87.15 |   68.75 |   91.06 | ...32,482-483,499 
  sdk.ts           |   82.12 |    90.47 |   66.66 |   82.12 | ...90-194,232-254 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |    91.1 |    88.68 |   96.77 |    91.1 | ...1737,1768-1771 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  trace-context.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.56 |    88.63 |     100 |   98.56 | 52,101            
  types.ts         |      83 |    94.32 |   86.36 |      83 | ...1467,1471-1478 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.23 |    80.35 |      70 |   74.23 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.23 |    80.18 |   69.49 |   74.23 | ...1122,1160-1161 
 src/test-utils    |   96.02 |    98.41 |   82.92 |   96.02 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...mised-lock.ts |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   94.85 |      100 |   78.78 |   94.85 | ...53,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   86.24 |    84.99 |   88.72 |   86.24 |                   
  ...erQuestion.ts |   89.71 |    80.76 |   91.66 |   89.71 | ...66-367,374-375 
  ...-registrar.ts |    77.7 |    66.66 |   66.66 |    77.7 | ...72-277,292-294 
  ...ub-session.ts |   89.67 |     91.3 |   81.81 |   89.67 | ...03-304,315-322 
  cron-create.ts   |   90.64 |    92.85 |   72.72 |   90.64 | ...,73-74,223-231 
  cron-delete.ts   |   97.56 |      100 |   83.33 |   97.56 | 31-32             
  cron-list.ts     |   98.23 |    95.34 |    87.5 |   98.23 | 57-58             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  display-image.ts |   87.42 |    84.84 |   88.88 |   87.42 | ...29-134,194-195 
  edit.ts          |    82.7 |    86.77 |   81.25 |    82.7 | ...43-744,863-913 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |      85 |     82.6 |    87.5 |      85 | ...28-133,161-175 
  exit-worktree.ts |   83.29 |    83.65 |   94.44 |   83.29 | ...14-515,537-538 
  exitPlanMode.ts  |      95 |    85.29 |     100 |      95 | ...21-325,344,378 
  ...permission.ts |     100 |      100 |     100 |     100 |                   
  glob.ts          |   96.33 |     88.5 |     100 |   96.33 | ...24-225,373,376 
  grep.ts          |   90.73 |    86.61 |   85.71 |   90.73 | ...76-677,727-728 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  image-gen.ts     |   91.66 |    77.41 |    90.9 |   91.66 | ...13-214,221-222 
  list-agents.ts   |   94.02 |    82.35 |   83.33 |   94.02 | 31-32,47-48       
  loop-wakeup.ts   |   99.27 |    92.85 |     100 |   99.27 | 45                
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.71 |     59.5 |   90.32 |   72.71 | ...1212,1214-1215 
  ...nt-manager.ts |   82.13 |    80.47 |   85.71 |   82.13 | ...3234,3236-3237 
  mcp-client.ts    |   79.87 |    85.58 |   89.47 |   79.87 | ...2259,2263-2266 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   79.21 |    85.71 |   81.57 |   79.21 | ...1341,1349-1350 
  ...ool-events.ts |       8 |        0 |       0 |       8 | 132-158           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 176-177           
  ...ce-content.ts |   96.55 |    91.17 |     100 |   96.55 | 80-82             
  mcp-retry.ts     |   97.67 |    95.65 |     100 |   97.67 | 131-132           
  ...ion-config.ts |     100 |      100 |     100 |     100 |                   
  mcp-status.ts    |     100 |      100 |     100 |     100 |                   
  mcp-tool.ts      |   98.35 |    93.71 |     100 |   98.35 | ...-990,1045-1046 
  ...sport-pool.ts |   83.98 |     80.3 |   88.46 |   83.98 | ...1409,1416-1420 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |     100 |      100 |     100 |     100 |                   
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 101,108           
  monitor.ts       |   91.82 |    83.09 |   88.46 |   91.82 | ...99,612,810-815 
  notebook-edit.ts |   85.69 |    77.08 |   81.25 |   85.69 | ...95-911,957-958 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   83.21 |    90.69 |     100 |   83.21 | 147-158,207-220   
  read-file.ts     |   95.49 |    88.52 |   86.66 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |   91.18 |    86.71 |    87.5 |   91.18 | ...26-427,441-453 
  ripGrep.ts       |    94.6 |    87.26 |   95.23 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   81.13 |    89.74 |    62.5 |   81.13 | ...80-286,363-371 
  ...n-mcp-view.ts |   94.07 |    91.89 |    90.9 |   94.07 | 131-139           
  shell.ts         |   78.81 |    84.22 |   91.91 |   78.81 | ...5035,5098-5099 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   91.39 |    92.55 |      90 |   91.39 | ...84,488,534-556 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |    94.4 |    93.33 |   81.81 |    94.4 | 45-49,63-64,95    
  task-list.ts     |   73.38 |    77.77 |   83.33 |   73.38 | ...02,105,109-116 
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  task-update.ts   |   82.89 |    83.92 |    92.3 |   82.89 | ...14-422,454-465 
  team-create.ts   |   97.22 |    85.71 |   83.33 |   97.22 | 48-49,129-130     
  team-delete.ts   |   86.74 |    83.33 |   83.33 |   86.74 | 37-38,42-48,72-73 
  ...n-approval.ts |   92.14 |    96.77 |   77.77 |   92.14 | 38-39,42-43,93-99 
  todoWrite.ts     |   95.13 |    87.85 |   93.33 |   95.13 | ...23-527,540-545 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.57 |    79.59 |    82.6 |   78.57 | ...89-990,998-999 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   93.11 |    92.53 |   91.66 |   93.11 | ...69-570,586-592 
  ...reapproved.ts |   99.27 |    94.11 |     100 |   99.27 | 170               
  web-fetch.ts     |   96.05 |    90.54 |   96.77 |   96.05 | ...85-786,800-801 
  web-search.ts    |   90.58 |    83.57 |      80 |   90.58 | ...1025,1083-1086 
  write-file.ts    |    86.7 |    84.92 |   88.88 |    86.7 | ...24-827,864-899 
  zoom-image.ts    |   95.76 |    93.75 |      90 |   95.76 | 54-59,203-204     
 src/tools/agent   |   87.22 |    87.68 |   88.69 |   87.22 |                   
  agent.ts         |   85.84 |    86.59 |   86.31 |   85.84 | ...4315,4337-4347 
  fork-profile.ts  |   93.65 |       90 |     100 |   93.65 | ...33-134,171-174 
  fork-subagent.ts |   98.73 |       95 |     100 |   98.73 | 101-102,173       
 ...tools/artifact |   95.78 |    92.51 |   88.63 |   95.78 |                   
  artifact-tool.ts |   91.46 |    88.46 |   71.42 |   91.46 | ...13-314,322-325 
  ...-publisher.ts |     100 |    85.71 |     100 |     100 | 32                
  ...-publisher.ts |   96.74 |    97.72 |    87.5 |   96.74 | 29-30,156-157     
  html.ts          |     100 |    96.77 |     100 |     100 | 122               
  ...-publisher.ts |     100 |       80 |     100 |     100 | 30                
  oss-publisher.ts |    98.1 |    91.48 |     100 |    98.1 | 43-45             
  publisher.ts     |     100 |      100 |     100 |     100 |                   
 ...s/computer-use |   90.21 |    82.17 |   78.08 |   90.21 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   80.11 |       90 |   77.77 |   80.11 | ...97,242-243,274 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    96.3 |    85.71 |     100 |    96.3 | 75-76,184,252-258 
 ...tools/workflow |   86.51 |    84.81 |      75 |   86.51 |                   
  workflow.ts      |   86.51 |    84.81 |      75 |   86.51 | ...67,512,514-515 
 src/utils         |   92.89 |    89.62 |   96.88 |   92.89 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.94 |    92.47 |     100 |   94.94 | ...43-544,651-655 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.45 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.88 |    94.11 |      95 |   95.88 | ...98-499,511-524 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   83.01 |    95.03 |    61.9 |   83.01 | ...62-378,382-388 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  file-identity.ts |     100 |      100 |     100 |     100 |                   
  fileUtils.ts     |   94.87 |    92.95 |   96.15 |   94.87 | ...1907,1915-1916 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |     100 |      100 |     100 |     100 |                   
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.39 |    94.28 |     100 |   94.39 | ...29-132,343-348 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  git-branches.ts  |    91.6 |    84.21 |    92.3 |    91.6 | ...90,405-410,570 
  ...fig-safety.ts |   97.01 |       80 |     100 |   97.01 | 53-54             
  gitDiff.ts       |   95.19 |    81.36 |     100 |   95.19 | ...1073,1419-1420 
  gitDirect.ts     |   98.84 |    94.28 |     100 |   98.84 | 234,318           
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |   78.02 |    81.25 |   85.71 |   78.02 | ...22-123,147-198 
  github-prs.ts    |   95.74 |    82.27 |     100 |   95.74 | 216,314-322       
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  image-view.ts    |   95.12 |    93.33 |     100 |   95.12 | ...68-172,240-244 
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   95.27 |     93.1 |     100 |   95.27 | ...16-317,359-362 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   94.01 |       90 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.21 |     100 |   98.96 | 153               
  ...kerChecker.ts |    90.9 |    91.66 |     100 |    90.9 | 73-79             
  notebook.ts      |   94.57 |    89.91 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   91.66 |    89.74 |     100 |   91.66 | ...26-228,251-256 
  osc8.ts          |   54.26 |    64.86 |   83.33 |   54.26 | ...72-195,197-257 
  partUtils.ts     |     100 |    98.64 |     100 |     100 | 211               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.61 |    92.42 |     100 |   93.61 | ...62-563,565-567 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   71.15 |       86 |     100 |   71.15 | ...-90,96-101,147 
  ...noreParser.ts |   92.63 |    91.66 |     100 |   92.63 | ...77-178,197-198 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |   96.98 |    87.15 |     100 |   96.98 | ...87-688,763-764 
  readManyFiles.ts |   95.75 |    80.86 |     100 |   95.75 | ...05,558,568-572 
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...67,558-559,577 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.11 |     100 |   97.63 | ...17,251-252,278 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   90.04 |    93.43 |   95.45 |   90.04 | ...55-565,598-599 
  ...sDiscovery.ts |   97.46 |    93.05 |     100 |   97.46 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   84.87 |    86.71 |   96.29 |   84.87 | ...71,696,725-734 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |    97.5 |    89.74 |     100 |    97.5 | 162-163           
  safe-mode.ts     |     100 |      100 |     100 |     100 |                   
  safeJsonParse.ts |     100 |      100 |     100 |     100 |                   
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...-child-env.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   98.03 |    97.75 |     100 |   98.03 | 100,102-103       
  ...aValidator.ts |   92.09 |    83.65 |   90.47 |   92.09 | ...60,882-883,896 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  sedEditParser.ts |   91.78 |    92.18 |     100 |   91.78 | ...66-569,645-646 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   95.98 |    83.96 |     100 |   95.98 | ...70,386,466,485 
  ...-pager-env.ts |     100 |      100 |     100 |     100 |                   
  ...fety-rules.ts |     100 |     89.7 |     100 |     100 | ...01,304,309-311 
  shell-utils.ts   |   86.07 |    88.33 |     100 |   86.07 | ...2269,2276-2280 
  ...lAstParser.ts |   98.27 |    91.38 |     100 |   98.27 | ...1321-1323,1333 
  ...ContextEnv.ts |     100 |       92 |     100 |     100 | 50-52             
  ...nlyChecker.ts |   96.33 |    96.57 |     100 |   96.33 | ...83-284,292-293 
  sideQuery.ts     |   86.82 |    86.66 |     100 |   86.82 | ...79-185,187-193 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...e-encoding.ts |   85.96 |    76.47 |     100 |   85.96 | 58-61,64-65,78-79 
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  textUtils.ts     |      65 |      100 |      75 |      65 | 56-75             
  thoughtUtils.ts  |     100 |    95.65 |     100 |     100 | 99                
  ...-converter.ts |   95.23 |    85.71 |     100 |   95.23 | 36-37             
  ...name-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-finalizer.ts |   97.66 |     90.9 |     100 |   97.66 | 165-166,168-172   
  tool-utils.ts    |    95.2 |    93.61 |     100 |    95.2 | ...58-159,162-163 
  ...ultCleanup.ts |   54.62 |       64 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.13 |    96.42 |     100 |   96.13 | ...34-339,341-346 
  ...pt-records.ts |    87.5 |    86.02 |     100 |    87.5 | ...76-480,510-525 
  truncation.ts    |   90.56 |    90.43 |     100 |   90.56 | ...35-443,480-486 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   96.74 |    91.04 |     100 |   96.74 | ...69,196,299-301 
  xml.ts           |    97.8 |    87.69 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    77.27 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.94 |    80.72 |   94.73 |   83.94 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |    82.9 |    76.81 |   95.08 |    82.9 | ...1563,1597-1598 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  ignore.ts        |     100 |    97.36 |     100 |     100 | 187               
  result-cache.ts  |     100 |    93.75 |     100 |     100 | 49                
 ...uest-tokenizer |   69.76 |    75.47 |   85.29 |   69.76 |                   
  ...eTokenizer.ts |   65.72 |    74.02 |    92.3 |   65.72 | ...65-466,479-533 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |   76.92 |      100 |   33.33 |   76.92 | 46-49,56-57       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

For detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run.

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head b1b135b, drove a fixed endpoint set against each, and diffed the JSON responses. Only fields that changed are shown.

No response changes against the PR base across 4 scenario(s).

Qwen Code · serve A/B

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. 2 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally. Not explored to full depth (tool budget reached): This PR removes the daemon's /demo debug page, folds the ...: did not execute rate-limit.test.ts , routes/health.test.ts , server.test.ts — this review worktree has no node_modules installed ( vitest unresolvable); …. Test Plan (not a blocker): 4221 passed — this review observed 18659 passed.

中文说明

已审查。 建议见行内评论。 2 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。 未探索到全部深度(达到工具调用预算):This PR removes the daemon's /demo debug page, folds the ...:did not execute rate-limit.test.ts , routes/health.test.ts , server.test.ts — this review worktree has no node_modules installed ( vitest unresolvable); …。 Test Plan(非阻断):4221 passed — this review observed 18659 passed

— qwen3.8-max via Qwen Code /review (v0.21.8)

Comment on lines +73 to +75
// Exempt: OPTIONS, health, heartbeat, SSE events, ACP transport
if (method === 'OPTIONS') return null;
if (
(method === 'GET' || method === 'HEAD') &&
(p === '/health' || p === '/demo')
)
return null;
if ((method === 'GET' || method === 'HEAD') && p === '/health') return null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-3: The removal of /demo from the rate-limit exemption list ships with no test gating it — the test-efficacy probe (harnessValidated: true) showed reverting this hunk (restoring || p === '/demo') leaves every test in rate-limit.test.ts green. The old 'exempts GET /demo' test was deleted with the route, and nothing pins the new exemption shape. — Failure scenario: a future change re-adds a pre-auth route to the exemption condition or widens the predicate → the suite stays green and an unauthenticated endpoint escapes rate limiting with no signal.

Suggested fix: add one assertion pinning the new behavior — e.g. in rate-limit.test.ts, drive limiter.middleware repeatedly against a non-exempt GET path and expect a 429 instead of next().

中文说明

R1-3:从限流豁免名单中移除 /demo 的这一改动没有任何测试把关——测试有效性探测(harnessValidated: true)显示,还原这个 hunk(恢复 || p === '/demo')后 rate-limit.test.ts 的所有测试仍然全绿。旧的 'exempts GET /demo' 测试随路由一起删除了,现在没有任何测试钉住新豁免名单的形状。— 失败场景:未来的改动把某个 pre-auth 路由重新加进豁免条件、或放宽谓词 → 测试套件依然全绿,未认证端点将在没有任何信号的情况下绕过限流。建议修复:新增一条断言钉住新行为——例如在 rate-limit.test.ts 中对一个非豁免的 GET 路径多次驱动 limiter.middleware,期望收到 429 而不是 next()

— qwen3.8-max via Qwen Code /review (v0.21.8)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bf482c3. rate-limit.test.ts now has exempts no GET path other than /health, which drives a fresh limiter twice against /demo, /health/deep, /healthz, and / and expects the second call to be refused with 429 in the read tier. Harness-checked the way you checked it: restoring || p === '/demo' in the predicate turns the new test red, so the exemption shape is gated now instead of free-floating.

中文说明

已在 bf482c3 修复。rate-limit.test.ts 新增 exempts no GET path other than /health:对 /demo/health/deep/healthz/ 各用一个新建 limiter 连打两次,断言第二次以 read tier 被 429 拒绝。按你的方式做了变异验证:把 || p === '/demo' 恢复回谓词,新测试转红,豁免名单的形状现在有测试把关。

Comment on lines 2442 to 2443
'token gates API routes; /health remains pre-auth ' +
'on loopback unless --require-auth is set)'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-4: The --allow-origin '*' boot-warning rewording ("/health and /demo remain pre-auth" → "/health remains pre-auth") is ungated — the test-efficacy probe showed reverting this hunk leaves every affected test green, and no test in the tree asserts the warning text. — Failure scenario: this warning is the operator's only notice of which routes are reachable pre-auth when booting with a wildcard origin; if the pre-auth surface changes again → the message silently misstates it and no test catches the drift.

Suggested fix: if the boot path gains a test for the --allow-origin '*' warning, assert it names exactly the current pre-auth routes; otherwise accept the gap knowingly.

中文说明

R1-4:--allow-origin '*' 启动告警的这次改写("/health and /demo remain pre-auth" → "/health remains pre-auth")没有任何测试把关——测试有效性探测显示还原这个 hunk 后所有相关测试仍然全绿,且整个仓库没有任何测试断言该告警文案。— 失败场景:这条告警是运维人员了解通配 origin 启动时哪些路由可未认证访问的唯一提示;如果 pre-auth 面再次变化 → 该消息会悄无声息地描述错误,且没有测试能发现这种漂移。建议修复:如果启动路径将来有了针对 --allow-origin '*' 告警的测试,请断言它恰好列出当前的 pre-auth 路由;否则请明知存在此缺口而接受它。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Took the first branch rather than accepting the gap. runQwenServe startup observability now has names every pre-auth surface in the --allow-origin '*' warning, which boots with allowOrigins: ['*'] plus a token, picks the --allow-origin: stderr line, and asserts it names the Web Shell static assets, --no-web, /health, and --require-auth, and does not name /demo. Reverting the wording turns it red.

The wording itself also changed — see R1-6: the old sentence enumerated the wrong surface, not just a stale one.

中文说明

选了第一条路,没有"明知有缺口而接受"。runQwenServe startup observability 新增 names every pre-auth surface in the --allow-origin '*' warning:以 allowOrigins: ['*'] 加 token 启动,取出 --allow-origin: 那行 stderr,断言它点名 Web Shell 静态资源、--no-web/health--require-auth,且不含 /demo。还原文案会让它转红。

文案本身也改了——见 R1-6:旧句子枚举的暴露面本身就是错的,不只是过时。

Comment thread docs/developers/qwen-serve-protocol.md Outdated
**`--allow-origin <pattern>` (T2.4 [#4514](https://github.com/QwenLM/qwen-code/issues/4514)).** Browser webuis hitting the daemon cross-origin are blocked by default — any request carrying an `Origin` header returns `403 {"error":"Request denied by CORS policy"}` because CLI/SDK clients never send `Origin` and the daemon treats its presence as a sign the request came from a browser context the operator has not opted into. Pass `--allow-origin <pattern>` (repeatable) at boot to install an allowlist instead of the wall. Each pattern is either:

- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` and `/demo` are also gated by the bearer — they're registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach `/health` without a token), and a `*` allowlist makes them reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot, so the `*` exposure surface is just `/health` (status JSON) and `/demo` (a static page whose JS still calls token-gated routes) — the actual API surface is gated regardless.
- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` is also gated by the bearer — it's registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach it without a token), and a `*` allowlist makes it reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot, so the `*` exposure surface is just `/health` (status JSON) and the Web Shell static assets (whose JS still calls token-gated routes) — the actual API surface is gated regardless.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-5: The PR-rewritten --allow-origin * bullet still lists /health in the tokenless * exposure surface on non-loopback binds, but there /health is registered after bearerAuth (exposeHealthPreAuth = loopback && !opts.requireAuth) and returns 401 without the token. A supertest probe run on both the PR and base trees observed 401 in both — the sentence was already wrong pre-PR, but this PR rewrote this very sentence and shipped the still-wrong /health enumeration on a changed line. — Failure scenario: an operator hardening a LAN-exposed daemon reads this edited paragraph → concludes /health stays reachable tokenlessly under * → adds compensating firewall rules or rejects a deploy over a leak that does not exist.

Suggested change
- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` is also gated by the bearer — it's registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach it without a token), and a `*` allowlist makes it reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot, so the `*` exposure surface is just `/health` (status JSON) and the Web Shell static assets (whose JS still calls token-gated routes) — the actual API surface is gated regardless.
- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` is also gated by the bearer — it's registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach it without a token), and a `*` allowlist makes it reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot and `/health` is registered behind it, so the only pre-auth surface `*` exposes is the Web Shell static assets (whose JS still calls token-gated routes) — the actual API surface is gated regardless.
中文说明

R1-5:本 PR 改写的 --allow-origin * 条目仍然把 /health 列入非 loopback 绑定下 * 的免认证暴露面,但在那里 /health 是在 bearerAuth 之后注册的(exposeHealthPreAuth = loopback && !opts.requireAuth),不带 token 时返回 401。在 PR 树和基线树上分别运行的 supertest 探测均观察到 401——这句话在 PR 之前就是错的,但本 PR 改写了这个句子,在一行被修改的文字里保留了仍然错误的 /health 枚举。— 失败场景:正在加固 LAN 暴露 daemon 的运维读到这段被编辑的文字 → 以为在 */health 仍可免 token 访问 → 添加多余的防火墙规则,或因为一个并不存在的泄露而拒绝部署。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed and fixed in bf482c3. A probe across all three launch modes (loopback+token, loopback+--require-auth, non-loopback+token) reproduces exactly what you observed — /health is 401 on a non-loopback bind, since exposeHealthPreAuth = loopback && !opts.requireAuth registers it behind bearerAuth there.

I went slightly further than the suggestion: the same probe showed the Web Shell static assets answer 200 without a token in all three modes, so the bullet now says the assets are the only tokenless surface on a non-loopback bind and names --no-web as the way to remove it. Same correction applied to the user doc (R1-8) and to the boot warning (R1-6), so the three now agree.

中文说明

已确认并在 bf482c3 修复。对三种启动模式(loopback+token、loopback+--require-auth、非 loopback+token)的探测复现了你观察到的结果——非 loopback 绑定下 /health 返回 401,因为 exposeHealthPreAuth = loopback && !opts.requireAuth 会把它注册在 bearerAuth 之后。

比建议多改了一点:同一次探测显示 Web Shell 静态资源在三种模式下都免 token 返回 200,所以该条目现在写明:非 loopback 绑定下静态资源是唯一的免认证面,并点名 --no-web 是移除它的方式。同样的更正也应用到了用户文档(R1-8)和启动告警(R1-6),三处现在一致。

Comment on lines 2441 to 2443
? ' (WARNING: `*` admits any cross-origin browser — bearer ' +
'token gates API routes; /health and /demo remain pre-auth ' +
'token gates API routes; /health remains pre-auth ' +
'on loopback unless --require-auth is set)'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-6: The --allow-origin '*' boot warning this PR rewrote omits the Web Shell static assets from the pre-auth surface it enumerates — on non-loopback binds they are the only tokenless surface (mountWebShellAssets is unconditional before bearerAuth; serves /, /assets/*, /session/:id navigations). The omission pre-dates the PR, but the rewrite is what stripped the enumeration of its last browser-surface reference (/demo), on a changed line. — Failure scenario: an operator starts qwen serve --allow-origin '*' on a LAN bind (where the /health clause does not even apply) → the warning reads as if nothing but token-gated API routes is reachable, while the full Web Shell UI is delivered tokenless to any admitted cross-origin browser; after this PR the warning and the rewritten protocol doc disagree about that surface.

Suggested change
? ' (WARNING: `*` admits any cross-origin browser — bearer ' +
'token gates API routes; /health and /demo remain pre-auth ' +
'token gates API routes; /health remains pre-auth ' +
'on loopback unless --require-auth is set)'
? ' (WARNING: `*` admits any cross-origin browser — bearer ' +
'token gates API routes; the Web Shell static assets are ' +
'always served pre-auth, and /health remains pre-auth '
'on loopback unless --require-auth is set)'
中文说明

R1-6:本 PR 改写的 --allow-origin '*' 启动告警遗漏了 Web Shell 静态资源这一 pre-auth 面——在非 loopback 绑定下它们是唯一的免认证面(mountWebShellAssets 无条件地位于 bearerAuth 之前,提供 //assets/*/session/:id 导航)。该遗漏在本 PR 之前就存在,但这次改写把枚举中最后一个浏览器面引用(/demo)删掉了,且发生在一行被修改的文字上。— 失败场景:运维在 LAN 绑定上启动 qwen serve --allow-origin '*'(此时告警里 /health 那半句根本不适用)→ 告警读起来好像除 token 把关的 API 路由外别无可达面,而实际上完整的 Web Shell UI 正免 token 地送达任何被允许的跨源浏览器;本 PR 之后,该告警与改写后的协议文档对该暴露面的描述互相矛盾。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bf482c3 — the warning now reads:

* admits any cross-origin browser — bearer token gates API routes; the Web Shell static assets stay pre-auth in every mode unless --no-web, and /health stays pre-auth on loopback unless --require-auth is set

(the suggested snippet was missing a + between the last two string literals, so I wrote it out rather than applying it). A probe confirmed the premise: /, /assets/*, and /session/:id navigations all answer 200 without a token on loopback, loopback + --require-auth, and a non-loopback bind alike. The wording is now asserted by a test — see R1-4.

中文说明

已在 bf482c3 修复,告警现在是:

* admits any cross-origin browser — bearer token gates API routes; the Web Shell static assets stay pre-auth in every mode unless --no-web, and /health stays pre-auth on loopback unless --require-auth is set

(建议的代码片段最后两段字符串之间缺一个 +,所以我重写而不是直接套用)。探测确认了前提://assets/*/session/:id 导航在 loopback、loopback + --require-auth、非 loopback 三种模式下都免 token 返回 200。该文案现在有测试断言——见 R1-4。

Comment thread docs/users/qwen-serve.md Outdated
- **`LOOPBACK_BINDS` includes IPv6** — `::1` and `[::1]` count as loopback for the no-token rule.
- **Host header allowlist** — on **loopback** binds the daemon checks `Host:` matches `localhost:port` / `127.0.0.1:port` / `[::1]:port` / `host.docker.internal:port` (case-insensitive per RFC 7230 §5.4) to defend against DNS rebinding. **Non-loopback binds (`--hostname 0.0.0.0`) intentionally bypass the Host allowlist** — the operator has chosen the surface area, so the bearer-token gate is the sole authentication layer; reverse proxies / SNI / client cert pinning are the operator's responsibility, not the daemon's. If you need Host-based isolation on a non-loopback bind, terminate TLS + check Host at a front proxy.
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` and `/demo` remain pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the `/demo` page) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` remains pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the Web Shell UI) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-8: The PR-rewritten --allow-origin bullet enumerates only /health as remaining pre-auth on loopback by default; the Web Shell static assets (/, /assets/*, /session/:id navigations) are also pre-auth, and stay pre-auth even under --require-auth (the mount is unconditional before bearerAuth). The rewrite removed /demo — the enumeration's browser surface — and named no replacement, the same defect class as R1-6. — Failure scenario: an operator configuring --allow-origin '*' on loopback weighs --require-auth against the stated residual → declines it believing /health is the sole pre-auth leftover (while the full Web Shell UI is delivered tokenless to any local caller), or adds it for the promised "full hardening" while the static shell stays tokenless — the hardening decision is made against a misstated surface.

Suggested change
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` remains pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the Web Shell UI) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` remains pre-auth on loopback by default, and the Web Shell static assets are always served pre-auth — use `--no-web` to remove them) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the Web Shell UI) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
中文说明

R1-8:本 PR 改写的 --allow-origin 条目只把 /health 列为 loopback 上默认保持 pre-auth 的面;Web Shell 静态资源(//assets/*/session/:id 导航)同样 pre-auth,且即使在 --require-auth 下也保持 pre-auth(挂载无条件位于 bearerAuth 之前)。这次改写删掉了 /demo——枚举中的浏览器面——却没有指明替代者,与 R1-6 属同一缺陷类别。— 失败场景:在 loopback 上配置 --allow-origin '*' 的运维基于所陈述的残留面权衡 --require-auth → 以为 /health 是唯一的 pre-auth 残留而放弃它(而实际上完整的 Web Shell UI 正免 token 送达任何本地调用方),或为了承诺的"完全加固"加上它、但静态外壳仍然免 token——加固决策是基于一个被错误描述的暴露面做出的。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in bf482c3, with one deviation from the suggested text. The residual is not "always served pre-auth" in the abstract — the probe shows it is pre-auth on loopback, on loopback with --require-auth, and on a non-loopback bind, because the mount is unconditional before bearerAuth in every mode. So the bullet now states that explicitly (/, /assets/*, /session/:id document navigations), notes it survives --require-auth, and points at --no-web for operators who need that surface gone. The flags-table row above it got the same treatment.

中文说明

已在 bf482c3 修复,与建议文案有一处出入。残留面并不是抽象意义上的"总是 pre-auth"——探测显示它在 loopback、loopback + --require-auth、非 loopback 三种情况下都 pre-auth,因为挂载在每种模式下都无条件位于 bearerAuth 之前。所以该条目现在明确写出这一点(//assets/*/session/:id 文档导航),说明它在 --require-auth 下依然存在,并为需要移除该面的运维指向 --no-web。上方 flags 表格里的对应行也做了同样处理。

@wenshao

wenshao commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@qwen-code-dev-bot qwen-code-dev-bot added the autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+) label Aug 9, 2026
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

@qwen-code-dev-bot

qwen-code-dev-bot commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

AutoFix round 6 finishedview run. See this round's report below.

中文说明

AutoFix 第 6 轮已完成 —— 查看运行。本轮报告见下方。

@jifeng

jifeng commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Independent local validation report

Verdict: Functionally positive in the tested scope. I found no runtime blocker in the /demo removal itself. Do not merge the current head as-is, because it conflicts with current main; resolve/rebase the single documentation conflict and repeat the short daemon smoke test before merging.

Scope and environment

  • Tested PR commit: 07f467171be36019f22194ba49844d42f47f4468
  • Baseline (PR merge base): 3e731cda8b073d058d8970ae8ffbfdc58021faba
  • macOS 26.5.2, Apple Silicon (arm64), Node.js v24.18.0, npm 11.16.0
  • Detached temporary worktrees and isolated daemon config; the main checkout was not modified.

Build and automated checks

  • npm ci succeeded; its prepare hook completed the full repository build and bundle, including the built Web Shell assets.
  • npm run typecheck succeeded across all workspaces.
  • git diff --check <merge-base>..HEAD succeeded.
  • Focused CLI serve tests (health.test.ts, rate-limit.test.ts, server.test.ts): 922 passed, 2 failed on the first loaded run. The two failures were unrelated load-sensitive server cases (socket hang up and a 15-second archive-batch timeout). An exact rerun of those two tests produced 2 passed; health tests were 2/2 passed and rate-limit tests were 27/27 passed. I therefore classify the first-run failures as suite-load flakes, not PR regressions.

Real daemon validation

Baseline daemon (built from the merge base, --no-web):

  • /health returned 200 with {"status":"ok"}; deep health returned 200 with aggregate counters.
  • /demo returned the legacy HTML debug page with its CSP and X-Frame-Options: DENY.

Bundled PR daemon with the real built Web Shell:

Check Result
GET / 200, Web Shell HTML, expected CSP/XFO and Cache-Control: no-cache
GET /health 200, {"status":"ok"}
GET /health?deep=1 200 with normal aggregate fields (1 workspace, 0 sessions/prompts/permissions in the isolated environment)
Plain GET /demo (Accept: application/json) 404, Cannot GET /demo
Document navigation to /demo (Accept: text/html) 200, the same Web Shell HTML/security headers as /
Independent in-app browser navigation to /demo Full localized Web Shell rendered; URL remained /demo; title was Qwen Code Web chat

Auth behavior also matched the intended route placement:

  • Loopback with --require-auth --token ...: /health was 401 without the token and 200 with it; deep health was 200 with the token. /demo document navigation was 401 without the token, 200 Web Shell with it, while a plain authenticated /demo request remained 404.
  • Non-loopback bind (0.0.0.0) with a token: /health was 401 without the token and 200 with it.

Rate limiting was proven active with --rate-limit-read 1: 25/25 concurrent /health requests returned 200, while ordinary /capabilities reads returned 200 then 429. This confirms that /health remains exempt while normal reads are limited.

Mergeability and limitations

  • GitHub currently reports the PR as CONFLICTING. A local merge-tree check against current main found one content conflict: docs/users/qwen-serve.md. Source files merged automatically in that check.
  • Tested locally on macOS arm64 only; Windows and Linux were not exercised here.
  • No live model prompt/session workload was run because the PR removes an HTTP debug surface and does not change the ACP/event protocol.
  • The exact PR head was tested, not a manually conflict-resolved merge with current main.

Recommendation

The observed behavior matches the PR description: the legacy /demo handler is removed, while shallow/deep health, authentication, health rate-limit exemption, root Web Shell serving, and document-navigation fallback are preserved. Resolve/rebase docs/users/qwen-serve.md, inspect the resolution, and rerun the short daemon smoke matrix. Subject to that, this PR is suitable to merge.

中文验证报告

独立本地验证结论

结论: 在本次覆盖范围内,功能验证通过,未发现删除 /demo 本身造成的运行时阻断问题。但当前 head 不应直接合并,因为它与最新 main 存在冲突;应先 rebase/解决唯一的文档冲突,再重复一次简短的 daemon 冒烟验证。

范围与环境

  • 测试的 PR commit:07f467171be36019f22194ba49844d42f47f4468
  • 对照基线(PR merge base):3e731cda8b073d058d8970ae8ffbfdc58021faba
  • macOS 26.5.2、Apple Silicon (arm64)、Node.js v24.18.0、npm 11.16.0
  • 使用隔离的临时 worktree 和 daemon 配置;未修改主工作区。

构建与自动化检查

  • npm ci 成功,其 prepare hook 完成了全仓构建与 bundle,包括真实 Web Shell 构建产物。
  • 全 workspace npm run typecheck 成功。
  • git diff --check <merge-base>..HEAD 成功。
  • 聚焦 CLI serve 测试(health.test.tsrate-limit.test.tsserver.test.ts)首次在负载下为 922 通过、2 失败。两项失败是与本 PR 无关的负载敏感用例(一次 socket hang up 和一次 15 秒 archive batch 超时);对这两项精确重跑后 2 项均通过。health 测试 2/2 通过,rate-limit 测试 27/27 通过。因此首次失败判定为套件负载抖动,而非 PR 回归。

真实 daemon 验证

对照基线 daemon(从 merge base 构建,使用 --no-web):

  • /health 返回 200 和 {"status":"ok"};深度 health 返回 200 和聚合计数。
  • /demo 返回旧版 HTML 调试页,并带原有 CSP 与 X-Frame-Options: DENY

使用真实 Web Shell 构建产物启动 PR bundle:

检查 结果
GET / 200,Web Shell HTML,CSP/XFO 及 Cache-Control: no-cache 符合预期
GET /health 200,{"status":"ok"}
GET /health?deep=1 200,聚合字段正常(隔离环境中 1 个 workspace,session/prompt/permission 均为 0)
普通 GET /demoAccept: application/json 404,Cannot GET /demo
文档导航 /demoAccept: text/html 200,返回与 / 相同的 Web Shell HTML 和安全响应头
应用内真实浏览器访问 /demo 完整的本地化 Web Shell 正常渲染;URL 保持 /demo;标题为 Qwen Code Web chat

认证行为也符合预期:

  • loopback 配置 --require-auth --token .../health 无 token 为 401、有 token 为 200;深度 health 带 token 为 200。/demo 文档导航无 token 为 401、带 token 返回 200 Web Shell;普通的已认证 /demo 请求仍为 404。
  • 非 loopback 绑定(0.0.0.0)并配置 token:/health 无 token 为 401、有 token 为 200。

限流使用 --rate-limit-read 1 做了真实验证:并发请求 /health 25/25 均为 200,而普通 /capabilities 连续请求依次为 200、429。这证明 /health 仍被豁免,同时普通读请求确实受到限流。

可合并性与限制

  • GitHub 当前将 PR 标记为 CONFLICTING。本地对最新 main 执行 merge-tree 检查,只发现一个内容冲突:docs/users/qwen-serve.md;源码文件在该检查中均可自动合并。
  • 本地只验证了 macOS arm64,未覆盖 Windows/Linux。
  • 未执行真实模型 prompt/session 工作负载,因为该 PR 删除的是 HTTP 调试页面,并未修改 ACP/event 协议。
  • 测试对象是 PR 的精确 head,而不是手工解决冲突后的合并结果。

合并建议

实测行为与 PR 描述一致:旧 /demo handler 被移除,同时浅/深 health、认证门控、health 限流豁免、根路径 Web Shell 以及文档导航 fallback 均保持正常。建议先 rebase/解决 docs/users/qwen-serve.md,检查冲突解决内容,然后重跑简短 daemon 冒烟矩阵;完成后可以合并。

@jifeng jifeng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Independent local validation found one focused test gap; details are attached inline.

});
});

describe('GET /demo', () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] Pin the removed /demo contract with replacement tests. This deletes every /demo assertion, while the remaining Web Shell tests only exercise a generic /deep/link. Reintroducing the old handler would therefore leave those tests green even though plain /demo requests no longer return 404. In the real bundled-daemon check, GET /demo with Accept: application/json returned 404, while a document navigation with Accept: text/html returned the Web Shell. Please retain that distinction in this suite with a focused pair of assertions (and, ideally, the --require-auth case, where an unauthenticated document navigation must remain 401).

中文说明

[建议] 请用替代测试固定 /demo 已删除后的行为契约。 此处删除了全部 /demo 断言,而现有 Web Shell 测试只覆盖通用的 /deep/link。因此即使未来误把旧 handler 加回,现有测试仍可能全绿,但普通 /demo 请求已不再是预期的 404。真实 bundle 验证中,带 Accept: application/jsonGET /demo 返回 404,而带 Accept: text/html 的文档导航返回 Web Shell。建议在该套件中保留一对针对 /demo 的明确断言;最好同时覆盖 --require-auth,确保未认证的文档导航仍返回 401。

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in bf482c3 — two focused tests in the Web Shell suite, both covering the distinction you measured on the real bundle:

  • no longer serves a demo page: /demo is an ordinary unknown pathAccept: application/json must 404 and must not contain the shell root; Accept: text/html must be 200 with the shell.
  • gates a /demo navigation behind the bearer once a token is configured — with token set and again with token + --require-auth, an unauthenticated document navigation is 401, not the shell. Your instinct was right: the SPA fallback is mounted after bearerAuth, so unlike / and /session/:id a leftover /demo bookmark is refused rather than answered.

Harness-checked: re-adding a /demo handler to the health route turns both tests red.

That last point also corrects something in my PR description — I wrote that the old URL "degrades to the Web Shell instead of erroring", which only holds for a tokenless loopback daemon. With a token configured it is a 401. I will fix the description.

中文说明

已在 bf482c3 完成——在 Web Shell 套件里加了两个针对性测试,都覆盖你在真实 bundle 上量到的区分:

  • no longer serves a demo page: /demo is an ordinary unknown path——Accept: application/json 必须 404 且不含 shell 根节点;Accept: text/html 必须 200 且是 shell。
  • gates a /demo navigation behind the bearer once a token is configured——设了 token、以及 token + --require-auth 两种情况下,未认证的文档导航都是 401 而非 shell。你的判断是对的:SPA 兜底挂在 bearerAuth 之后,所以与 //session/:id 不同,残留的 /demo 书签会被拒绝而不是被响应。

变异验证:把 /demo handler 加回 health 路由,两个测试都转红。

最后这点也纠正了我 PR 描述里的一句话——我写的"旧 URL 会降级到 Web Shell 而不是报错"只在无 token 的 loopback daemon 上成立;配置了 token 就是 401。我会去修正描述。

The daemon has shipped a real browser UI for a while: `resolveWebShellDir()`
finds the bundled Web Shell assets and `mountWebShellAssets()` serves them at
`/`, so `qwen serve` already opens onto a full client. `/demo` stayed behind as
a 663-line inline-HTML console covering the same ground with none of the
reach — nobody drives the daemon through it, and `npm run dev:daemon` starts
the Web Shell dev server rather than the demo page.

Keeping it around costs more than the dead code. It is the only file in the
tree that pairs an event log with daemon HTTP, so work that starts as a Web
Shell observation lands there instead: #8762 was found while running `/review`
through the Web Shell and was fixed entirely inside the demo page's rendering,
with "no Web Shell changes" in its own risk note. Deleting the page removes
that decoy.

Nothing is lost for protocol-level debugging: `GET /session/:id/events`
streams the same raw frames the Events tab printed.

`/health` shared `routes/health-demo.ts` with the demo handler, so the module
is now `routes/health.ts` / `createHealthRoutes()` and drops its `getPort`
dependency. The rate-limit exemption, the boot breadcrumb, and the daemon docs
lose their `/demo` arms; the loopback self-origin shim regression test already
asserted through `/health` and only needed its title corrected.
Review follow-up. Three of the removal hunks shipped ungated, and two doc
sentences the removal rewrote were describing the pre-auth surface wrong —
both before and after the edit.

Deleting the `/demo` route took its assertions with it, so nothing failed if
the handler came back: the Web Shell suite only exercised a generic deep link,
and the rate-limit exemption could be widened again with the suite still green.
`/demo` is now pinned as what it became — an ordinary unknown path: a
non-navigation request 404s, a browser navigation is answered by the SPA
fallback like any other deep link, and once a token is configured (with or
without `--require-auth`) that navigation is refused with 401, because the
fallback sits behind the bearer. The rate-limit test pins that `/health` is the
only exempt GET, so re-adding a second pre-auth page to the predicate fails
instead of silently escaping the limiter. Each new assertion was checked by
reverting the hunk it guards and confirming it goes red.

The `--allow-origin '*'` warning and both `--allow-origin` doc paragraphs
enumerated `/health` as the residual tokenless surface and said nothing about
the Web Shell static assets, which are mounted before the bearer in every
launch mode and stay reachable even under `--require-auth` — the enumeration
also claimed `/health` stays pre-auth on non-loopback binds, where it is
registered behind the bearer and 401s. A probe across all three launch modes
established the actual matrix; the warning and the docs now match it and name
`--no-web` as the way to remove the residual browser surface. The warning text
is asserted by a test for the first time.
@wenshao
wenshao force-pushed the chore/remove-daemon-demo-page branch from 07f4671 to bf482c3 Compare August 9, 2026 17:17
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration.

中文

请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. 4 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally. Not explored to full depth (tool budget reached): chunk 7: could not execute server.test.ts in this worktree — vite suite collection fails resolving @qwen-code/web-templates via src/ui/utils/export/formatters/html.ts (i….

中文说明

已审查。 建议见行内评论。 4 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。 未探索到全部深度(达到工具调用预算):chunk 7:could not execute server.test.ts in this worktree — vite suite collection fails resolving @qwen-code/web-templates via src/ui/utils/export/formatters/html.ts (i…

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

```

Open `http://127.0.0.1:4170/demo` in a browser to see the debug console: chat UI, event stream, and workspace inspection. In the default loopback dev mode, `createServeApp()` mounts the `/demo` route from `packages/cli/src/serve/routes/health-demo.ts` **before** `bearerAuth`, so no token is required.
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured. `--no-web` opts out and leaves the daemon API-only.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The rewritten §1 claims the shell's API calls "carry the bearer when one is configured", but the doc never explains how the token reaches the browser — the only usage instruction is Open http://127.0.0.1:4170/, which yields a 401-ing shell when auth is on.

Failure scenario: an operator follows the doc's intro ("Set QWEN_SERVER_TOKEN to enable") and §1's instruction, opens http://127.0.0.1:4170/ in a browser, and the shell renders but every API call returns 401 — with no in-UI way to supply the token and no doc hint that --open or a #token= fragment is required. The Web Shell has no in-UI token entry; the token reaches the browser only via qwen serve --open (which appends #token=), a manual #token=/?token= fragment, or an extension-parent postMessage.

Suggested change
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured. `--no-web` opts out and leaves the daemon API-only.
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured — start the daemon with `--open` (which puts the token in the URL fragment, never sent to the server) or append `#token=…` manually when auth is enabled. `--no-web` opts out and leaves the daemon API-only.
中文说明

改写的 §1 声称 Web Shell 的 API 调用"配置了 token 时会自动携带 bearer",但文档从未说明 token 如何到达浏览器——唯一的用法说明是 打开 http://127.0.0.1:4170/,开启认证后这会让外壳渲染成功但所有 API 调用返回 401。Web Shell 没有 UI 内输入 token 的入口;token 只能通过 qwen serve --open(把 token 放进 URL fragment)、手动在 URL 加 #token=/?token=、或扩展宿主 postMessage 传递。建议在 §1 说明开启认证后需用 --open 或手动附加 #token=… 打开外壳。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

| Loopback without `--require-auth` | `routes/health-demo.ts`, mounted by `createServeApp()` **before** `bearerAuth` | Works without token |
| Loopback with `--require-auth` | `routes/health-demo.ts`, mounted by `createServeApp()` **after** `bearerAuth` | Difficult to use from a plain browser; use curl or SDK |
| Non-loopback bind | `routes/health-demo.ts`, mounted by `createServeApp()` **after** `bearerAuth` | Same as above |
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] §8's "mounted before bearerAuth in every launch mode" assurance omits that on a non-loopback bind without --allow-origin the Web Shell is effectively read-only: same-origin POSTs carry an Origin header the CORS wall rejects with 403.

Failure scenario: an operator exposes the daemon on a non-loopback bind, opens the shell per §8, sees it render and reads "Every API route it calls stays token-gated, and the front end attaches the bearer itself" — then every mutation fails with 403 {"error":"Request denied by CORS policy"}, which looks like an auth bug and is not explained anywhere in the rewritten quickstart. The daemon's own boot diagnostic states the UI is "effectively read-only" in this mode (run-qwen-serve.ts), so the doc contradicts the runtime's own notice.

Suggested change
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself.
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself. On a non-loopback bind the shell is read-only unless `--allow-origin <origin>` is passed — same-origin POSTs carry an `Origin` header that the CORS wall rejects (403) — so pass `--allow-origin` for any bind beyond loopback.
中文说明

§8 声称外壳"在每个启动模式下都挂在 bearerAuth 之前",但没有说明在非 loopback 绑定且未配置 --allow-origin 时 Web Shell 实际是只读的:同源 POST 携带的 Origin 头会被 CORS 墙以 403 拒绝。daemon 自己的启动诊断就写明此模式下 UI"实际上是只读的",文档与运行时的提示相矛盾。建议在 §8 补充非 loopback 绑定下需传 --allow-origin <origin> 才能写操作。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Could not produce a passing fix for this feedback (round 1/100). This item now needs a human; the loop stays engaged and still picks up new feedback and base conflicts, but will not retry this item on its own.

What I found before stopping:

Address-review summary — PR #8805 (remove the daemon /demo debug page)

No new code changes were needed this round. All six inline findings were already
implemented in bf482c36bb (test pins, warning-text fix, and doc corrections),
and the branch has since merged current main (d5526e2825), which is why the
workflow reports no base conflict. This round re-verified every claimed fix
against the live head and re-ran the full required gate set; everything is green.

Feedback dispositions

All six are Suggestion-level findings; each was verified against the exact code
at HEAD and is resolved in the code.

  • R1-3 — rate-limit exemption removal is ungated (rate-limit.ts:75): Resolved. rate-limit.test.ts now has exempts no GET path other than /health, which drives a fresh limiter twice against /demo, /health/deep, /healthz, and / and expects the second call to be refused with a read-tier 429. Restoring || p === '/demo' in the predicate makes both /demo calls pass through next(), which flips the assertion — the exemption shape is gated.
  • R1-4 — --allow-origin '*' warning rewording is ungated (run-qwen-serve.ts): Resolved. run-qwen-serve.test.ts has names every pre-auth surface in the --allow-origin '*' warning, which boots with allowOrigins: ['*'] plus a token and asserts the --allow-origin: stderr line names the Web Shell static assets, --no-web, /health, and --require-auth, and does not name /demo.
  • **R1-5 — pro

Run log: https://github.com/QwenLM/qwen-code/actions/runs/31329158923


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Could not produce a passing fix for this feedback (round 2/100). This item now needs a human; the loop stays engaged and still picks up new feedback and base conflicts, but will not retry this item on its own.

What I found before stopping:
Qwen failed during address-review: status 125.

See the Qwen Autofix agent step logs for model/tool output.

Run log: https://github.com/QwenLM/qwen-code/actions/runs/31331437274


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ This run could not certify that any of this diff was reviewed. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally. Not reviewed: coverage — no plan was given, so this run cannot show that any of the diff was read.

— qwen3.8-max via Qwen Code /review (v0.21.8)

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Autofix review round: no action taken (PR #8805)

Feedback triage

The only new feedback since the last evaluation is a COMMENTED review from the
automated reviewer (qwen-code-ci-bot):

  • The run reported that it "could not certify that any of this diff was
    reviewed", that 1 Suggestion-level finding could not be anchored to a changed
    line and was dropped, and it explicitly concluded "nothing further to act on
    here".
  • The remaining notes (Integration Tests (CLI, No Sandbox) skipped in CI and
    not run locally; no coverage plan given) describe the review run's own
    coverage limits. They contain no finding and request no code change.

Conclusion

  • No inline comments, issue-level comments, failed checks, or still-red checks
    were reported for this round.
  • No REQUEST_CHANGES item, named defect, or actionable suggestion remains.

No code changes were made this round; the PR head is left as-is.

中文说明

Autofix 审查轮次:未做任何操作(PR #8805

反馈分类

自上次评估以来唯一的新反馈是自动审查机器人(qwen-code-ci-bot)的一条
COMMENTED 审查:

  • 该轮运行报告"无法确认此 diff 的任何部分已被审查",1 条 Suggestion
    级别的发现因无法锚定到已变更的行而被丢弃,并明确得出结论"此处无需进一步
    操作"。
  • 其余说明(Integration Tests (CLI, No Sandbox) 在 CI 中被跳过且未在本地
    运行;未提供覆盖计划)描述的是该审查运行自身的覆盖局限,不包含任何发现,
    也未请求任何代码变更。

结论

  • 本轮没有报告任何内联评论、issue 级评论、失败的检查或持续失败的检查。
  • 没有 REQUEST_CHANGES 项、指出的缺陷或可操作的建议需要处理。

本轮未做任何代码更改;PR 的 head 保持不变。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@wenshao

wenshao commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 120 passed · 0 failed · 120 total

中文 — 判定:✅ 通过 · 可合入(agent 判定)

沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查

脚本断言:120 通过 · 0 失败 · 120 总计

Verification report

PR #8805 deep verification — chore(serve): remove the /demo debug page

Verdict: merge-ready — 120 scripted assertions executed, 120 pass / 0 fail.
Verified head OID: d5526e2825fa99e735e68ea6d991d1dc1449d0b1 (merge ref 09bf314433, base 55e20db3).

中文摘要
  • 结论:可合并(merge-ready)。中心主张“/demo 已被彻底移除”通过真实 daemon 的 A/B 得到证明:base 侧 /demo 在各启动模式下照常返回调试页(200 + HTML + 防点击劫持头),head 侧同一路径要么 404(非导航请求)、要么落入 SPA 兜底返回 Web Shell(浏览器导航)、要么在配置 token 后 401。/health 与限流豁免行为在两臂间完全一致(未回归)。
  • A/B 结论:base 49/49、head 57/57(见 01-ab-base-matrix.png / 02-ab-head-matrix.png)。/health 在 loopback/非 loopback、有无 --require-auth 下行为逐格不变;限流豁免名单收窄后,/demo 不再豁免(由 200×5 变为 404,404,429,429,429),/health 仍豁免。
  • 新增测试非空:3 个对照绿 + 3 个变异全部被对应的新断言杀死(见 03-mutation-matrix.png),证明这些测试确实钉住了被删除的契约,而非恒绿。
  • findings:无阻塞项;无新发现的缺陷。
  • 未覆盖:见正文 “Not covered”。

Central claim + A/B

Central claim: /demo is fully removed — a non-navigation request 404s, a browser
navigation falls through to the SPA fallback (Web Shell) on a tokenless loopback daemon,
and is refused with 401 once a token is configured (fallback sits behind the bearer).
/health and its rate-limit exemption are unchanged.

I booted a real qwen serve daemon per arm (from TS source via the repo's own tsx
dev runner, so the only difference between arms is the PR diff) across 7 launch modes and
probed it over real HTTP. Every cell is a scripted assertion against an arm-specific
expectation table. Base-arm PASS means "base behaves as the PR describes base"; the flips
between arms are the A/B result.

Witnesses: evidence/01-ab-base-matrix.png (base, 49/49) and
evidence/02-ab-head-matrix.png (head, 57/57).

Cell Scenario BASE HEAD flip?
A1 tokenless loopback, GET /demo (JSON Accept) 200 demo HTML 404 ✅ load-bearing
A2 tokenless loopback, GET /demo (browser nav) 200 demo HTML + X-Frame-Options: DENY 200 SPA shell (<div id="root">) ✅ shape change
A3/A4 GET /health, GET /health?deep=1 200 ok / counters 200 ok / counters unchanged
A5/A6 GET /, unknown path 200 shell / 404 200 shell / 404 unchanged
B1/B2 loopback + token, GET /demo no auth (nav / json) 200 demo (pre-auth) 401 ✅ load-bearing
B6 loopback + token, GET /demo with bearer 200 demo 404
C1 loopback + token + --require-auth, /demo nav no auth 401 401 unchanged (both gated)
C2/C3 /health no-bearer / bearer under --require-auth 401 / 200 401 / 200 unchanged
C4 GET / no token under --require-auth 200 shell 200 shell unchanged (static pre-auth)
C5 /demo nav with bearer under --require-auth 200 demo 200 SPA shell
D1/D2 non-loopback (0.0.0.0) + token, /health no/bearer 401 / 200 401 / 200 unchanged
D3 non-loopback, GET / no token 200 shell 200 shell unchanged (static pre-auth)
D4/D5 non-loopback, /demo nav no-auth / bearer 401 / 200 demo 401 / 200 SPA shell
E1 --allow-origin '*' boot warning text enumerates /demo names Web Shell static assets, --no-web, /health, --require-auth; no /demo
RL1/RL4 /health ×5 (tokenless; and bearer under --require-auth after bucket exhausted) 200×5 200×5 unchanged (still exempt)
RL2/RL3 /demo ×5, --rate-limit-read 2 200×5 (exempt) 404,404,429,429,429 ✅ exemption narrowed

Key flips all reproduce: the demo handler is gone (A1/B1/B6), its loopback pre-auth
exposure is gone in every token mode (B1/C1/D4), and the rate-limit exemption list no
longer contains /demo (RL2) while /health stays exempt even with an exhausted read
bucket (RL4). The Web Shell static surface (/, /assets, /session/:id nav) remains
pre-auth in every mode on both arms (B4/C4/D3), exactly as the rewritten warning and docs
state.

Secondary claim — --no-web removes the residual browser surface: verified live on
head (03-no-web-probe.mjs, 4/4): GET / and a deep-link navigation both 404 (no shell,
no SPA fallback), /health still 200, boot log does not claim the UI is served.

Corrections

None. (No earlier review round or bot comment misdescribed the code in a way that needs
correcting.)

Findings

None blocking; no defects found. Two informational notes, neither a finding against
this PR:

  1. The description's local tsc --noEmit note says it reports pre-existing errors
    (missing qrcode-terminal types, a stale session-service declaration). In this
    container npx tsc --noEmit in packages/cli is clean (0 errors) on both arms, so
    those errors did not reproduce here — likely an environment/dependency-state difference.
    The load-bearing fact for this PR (no new type errors) holds: both arms are equally
    clean.
  2. The description cites 4221 passed for npx vitest run src/serve; the merge ref I
    verified carries 4242 passed / 1 skipped. File count (147) and skip count (1)
    match; the +21 is consistent with the branch carrying a merge of main (which added
    serve tests) — in any case the suite is fully green.

Not covered

  • Per-commit attribution. Checkout is depth-2 (git rev-parse --is-shallow-repository
    = true); only the merge head is reachable, so the two logical commits
    (4c755375 removal, bf482c36 test-pinning) could not be exercised individually. I
    verified the aggregate HEAD^1..HEAD diff instead. The mutation matrix nonetheless
    separates the two concerns (removal vs. the tests that pin it).
  • Repo-wide gates the PR's own CI already runs (full npm run build, full test suite,
    ESLint/Prettier, integration suites) were not re-run; I ran the affected workspace's
    serve suite and typecheck instead.
  • Windows / Linux-specific paths — the author marked these untested locally; the
    loopback/0.0.0.0 behavior exercised here is the POSIX path.
  • Release-bundling claim (Web Shell shipped next to the CLI bundle) — not exercised; I
    used the in-checkout packages/web-shell/dist.
  • ?deep=1 content equality across arms — I asserted both return 200 + aggregate
    counter keys (workspaceCount, etc.), not a byte-for-byte diff of the counters.

Methodology

Environment: Linux node v22.23.2 container, repo at the merge ref. The A/B harness
(01-daemon-matrix.mjs) spawns a genuine daemon per arm via node node_modules/tsx/dist/cli.mjs &lt;arm>/packages/cli/index.ts serve … with an isolated $HOME and scratch workspace, waits
for the qwen serve listening on … line, then probes over real loopback / 0.0.0.0 HTTP
with fetch, asserting status codes, body markers (Qwen Serve demo string vs
&lt;div id="root"> shell marker), and headers against per-arm expectation tables. The base
arm runs from a scratch git worktree of HEAD^1; only the PR diff differs between arms.
The mutation matrix (02-mutation-matrix.mjs) applies three single-purpose mutants in a
scratch HEAD worktree — restore the /demo route, widen the rate-limit exemption back to
'/health' || '/demo', revert the --allow-origin '*' warning text — and confirms each
turns its guarding test red while the unmutated controls stay green; it then restores the
tree (git status clean). Targeted gates: npx vitest run src/serve (head) and
npx tsc --noEmit (both arms). Raw per-arm stdout/stderr and build/typecheck logs are in
logs/; harness scripts are in this directory for rerun.

Evidence images

01-ab-base-matrix

02-ab-head-matrix

03-mutation-matrix

Harness scripts and raw logs are in the workflow run artifacts (7-day retention).

Qwen Code · sandboxed verification

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Gate check — passing (re-run on the current head).

  • Template: complete ✓ — all required sections, including the Chinese translation.
  • Problem — observed, not theoretical: the demo page demonstrably misroutes work. The fix(serve): stop usage_update frames from flooding the demo event log #8762 event-stream flooding was observed while driving /review through the Web Shell, yet the fix landed entirely inside this 663-line debug page — that PR's own risk note said "no Web Shell changes". Neither the shipped path (releases bundle the Web Shell next to the CLI) nor the dev path (the daemon dev script starts the Web Shell dev server) passes through /demo.
  • Direction: aligned. The daemon has shipped a real browser UI for a while; the demo page covers the same ground — chat, event log, workspace inspection — with none of the reach. Retiring it also shrinks the loopback pre-auth surface as a side benefit.
  • Size: no core paths touched — everything is inside packages/cli/src/serve/** and docs/**. Of 1566 changed lines: 754 production code (dominated by the pure deletion of the 663-line page), 471 test, 341 docs. No core-module gate applies, no large-PR advisory.
  • Approach: scope feels exactly right — delete the page and its tests, fold the shared route module back to health-only (dropping the port accessor it needed solely to render the page), drop /demo from the rate-limit exemption and the --allow-origin '*' warning, and rework the docs to point at the Web Shell and the session event stream. The two follow-up commits since the last reviewed head only tightened this: doc wording now scopes the self-origin strip claims to loopback (matching self-origin.ts), and two more tests re-pin the pre-auth CORS wall on / and the shell's non-loopback pre-auth behavior. The large user-facing doc diffs read bigger than they are because Prettier reflows Markdown table column widths. No drive-by changes spotted.
  • Risk: no elevated risk signals — none of the changed files match the revert-correlated high-risk paths.

Moving on to code review. 🔍

中文说明

入口检查 —— 通过(针对当前 head 的 re-run)。

  • 模板:完整 ✓ —— 全部必备章节齐全,含中文翻译。
  • 问题 —— 已观测而非理论:demo 页面确实会把工作引偏。fix(serve): stop usage_update frames from flooding the demo event log #8762 的事件流刷屏是在通过 Web Shell 驱动 /review 时观察到的,但修复却全部落在这个 663 行的调试页面里——该 PR 的风险说明还写着"不涉及 Web Shell 改动"。无论是发布路径(release 将 Web Shell 与 CLI 一起打包)还是开发路径(daemon dev 脚本启动的是 Web Shell dev server)都不经过 /demo
  • 方向:对齐。daemon 早已自带真正的浏览器 UI;demo 页面覆盖同样的功能(聊天、事件日志、workspace 查看)却无人使用。移除它顺带缩小了 loopback 预认证暴露面。
  • 规模:未触及核心路径——改动全部在 packages/cli/src/serve/**docs/**。共 1566 行改动:754 行生产代码(大头是纯删除 663 行页面)、471 行测试、341 行文档。不触发核心模块门禁,也不触发大 PR 提醒。
  • 方案:范围恰好——删除页面及其测试,把共享路由模块收敛为纯 health(去掉仅为渲染页面而存在的端口访问器),从限流豁免和 --allow-origin '*' 警告中移除 /demo,并把文档改指向 Web Shell 和会话事件流。上次审查 head 之后的两个提交只是进一步收紧:文档措辞把同源 Origin 剥离的适用范围限定到 loopback(与 self-origin.ts 一致),并新增两个测试重新钉住 / 上的预认证 CORS 墙和 shell 在非 loopback 下的预认证行为。用户文档 diff 偏大只是因为 Prettier 重排了 Markdown 表格列宽。未发现顺手改动。
  • 风险:无升级风险信号——改动文件均未命中与 revert 相关的高风险路径。

进入代码审查。🔍

Qwen Code · qwen3.8-max

Reviewed at b1b135b9dc075101bba4bbf5a485501a6ecbf850 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Code review

I proposed my own cut before reading the diff: delete demo.ts and its test, split the shared route module back to health-only, drop the /demo rate-limit exemption and the warning's /demo arm, reword the docs, and assert /demo is now an unknown path. This PR matches that one-to-one and goes a step further — the replacement tests pin the removal, so reintroducing the handler fails CI instead of silently shipping.

What I verified beyond the diff:

  • No dangling references. Grepping the tree across packages/**, docs/**, integration-tests/, scripts/, and .github/ finds no remaining health-demo, createHealthDemoRoutes, getDemoHtml, or /demo route registration. The only surviving matches are the new negative assertions that pin the removal, the historical CHANGELOG entry (correctly untouched), and unrelated fixtures (test extensions named "demo", feat/demo branch names).
  • getPort removal is exactly scoped. It left the health module's deps (only the demo handler consumed it there), but server.ts still passes it to the self-origin strip middleware and the host allowlist, which genuinely need it.
  • Rate-limit shape is pinned. The new test drives a fresh limiter against /demo, /health/deep, /healthz, and / and expects 429 on the second read — this also rules out an accidental prefix match on /health.
  • The old URL degrades sanely. New server tests pin the promised behavior: non-navigation GET /demo → 404, browser navigation on a tokenless loopback daemon → the SPA fallback serves the Web Shell, and once a token is configured that same navigation is 401 because the fallback sits behind bearerAuth. I checked this against the route-ordering code in server.ts (static mount before bearerAuth at line ~1647, SPA fallback after all API routes at line ~2751) — it matches.
  • The deleted handler's security posture lives on. Its anti-clickjacking headers (frame-ancestors 'none' + X-Frame-Options: DENY) are the Web Shell mount's defaults, and the deleted CORS-wall test is re-pinned against /. Nothing was orphaned.
  • The two commits since the last reviewed head are accuracy work, not new scope: doc claims about the self-origin strip are now scoped to loopback (matching the code, which only matches loopback origins), and the pre-auth CORS wall plus non-loopback shell behavior each gained a pinning test.

No critical blockers, no convention violations.

Files changed (22 of 22 shown)
File What changed
packages/cli/src/serve/demo.ts Deleted — the 663-line self-contained debug page
packages/cli/src/serve/demo.test.ts Deleted with the page
packages/cli/src/serve/routes/health.ts Renamed from health-demo.ts; demo handler and port dep removed, health-only
packages/cli/src/serve/routes/health.test.ts Renamed with the module, factory call updated
packages/cli/src/serve/server.ts Wires createHealthRoutes; comments updated
packages/cli/src/serve/server.test.ts Deletes the old /demo suite; adds tests pinning the removal, the CORS wall on /, and non-loopback shell pre-auth
packages/cli/src/serve/rate-limit.ts GET/HEAD exemption narrowed to /health only
packages/cli/src/serve/rate-limit.test.ts New shape-pinning test: nothing but /health escapes the limiter
packages/cli/src/serve/run-qwen-serve.ts Wildcard allow-origin warning names the real pre-auth surface
packages/cli/src/serve/run-qwen-serve.test.ts New test gates the warning's enumeration
packages/cli/src/serve/server/self-origin.ts Comment-only: demo page to Web Shell
packages/cli/src/serve/web-shell-static.ts Comment-only rewording
docs/users/qwen-serve.md Flag-table prose reworded; most of the diff is Prettier table reflow
docs/developers/qwen-serve-protocol.md Allow-origin exposure prose updated to the real pre-auth surface
docs/developers/daemon/00-index.md Implementation anchors repoint to health.ts and web-shell-static.ts
docs/developers/daemon/02-serve-runtime.md Subsystem table swaps the demo row for the Web Shell mount row; self-origin caveat scoped to loopback
docs/developers/daemon/12-auth-security.md CORS flowchart and caveats switch demo to Web Shell, loopback-scoped
docs/developers/daemon/17-configuration.md ServeOptions table reworded demo arms to Web Shell terms
docs/developers/daemon/19-observability.md Surface table swaps the /demo row for the Web Shell UI row
docs/developers/daemon/20-quickstart-operations.md Quickstart opens the Web Shell at root; section 8 rewritten around the shell and the SSE stream
docs/design/serve-server-split.md Assembly-order contract drops /demo from steps 3 and 9; reorders 8-9 to match the code
docs/design/serve-server-final-split.md Same assembly-order update

Test evidence — this PR's own CI on the reviewed commit

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
Serve A/B (ubuntu-latest, Node 22.x) ✅ success
Real daemon E2E / Java 11 ✅ success
ubuntu-latest / Java 11, 17, 21 ✅ success
macos-latest / Java 21 ✅ success
windows-latest / Java 21 ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Test (macos-latest / windows-latest, Node 22.x) ⏭️ skipped — merge-queue-only by workflow design
Integration Tests (CLI, No Sandbox) ⏭️ skipped — merge-queue-only by workflow design

Everything that ran on the reviewed commit landed green — there were no failures to triage. Two signals carry the behavioral claim specifically: the Serve A/B job built the PR base and this head, drove a fixed endpoint set against each, and diffed the responses — no unexpected deltas — and the real daemon E2E matrix exercises an actual qwen serve process end to end. The skipped jobs are gated on merge_group in ci.yml; they are skipped on every PR by design and run in the merge queue instead. The sandboxed /verify run on the previous head passed 120/120 scripted assertions (its report is in this thread); the two commits since then are doc wording and two additional pinning tests, and a fresh verify run for this head reports in its own comment. Since the A/B diff plus the pinned removal tests already substantiate the one claim this PR makes (nothing changes except /demo going away), no further sandboxed-lane trigger is needed here.

中文说明

代码审查:我在看 diff 之前先给出了自己的方案(删除 demo.ts 及其测试、把共享路由模块收敛为纯 health、去掉 /demo 的限流豁免和警告中的 /demo 分支、改写文档、断言 /demo 已是未知路径)。本 PR 与我的方案一一对应,并且更进一步——替换测试把"删除"本身钉住了:若有人重新引入旧 handler,CI 会直接失败。

diff 之外我核实了:树中(packages、docs、integration-tests、scripts、.github)不再存在任何 health-demo、createHealthDemoRoutes、getDemoHtml 或 /demo 路由注册的残留,仅剩的匹配是钉住删除的负向断言、历史 CHANGELOG 条目(正确地未改动)和无关测试夹具;getPort 只是从 health 模块依赖中移除,server.ts 中同源 Origin 剥离和 host 白名单仍在正常使用它;新的限流测试逐一验证 /demo、/health/deep、/healthz、/ 都会被限流,排除了 /health 前缀误匹配;旧 URL 的降级行为(非导航 404、无 token 时导航走 SPA fallback、配置 token 后导航 401)与 server.ts 的路由注册顺序一致(静态挂载在 bearerAuth 之前、SPA fallback 在所有 API 路由之后);被删 handler 的安全姿态(frame-ancestors 'none' + X-Frame-Options: DENY)在 Web Shell 挂载处本就是默认值,被删的 CORS 墙测试也在 / 上重新钉住。上次审查 head 之后的两个提交是准确性修正而非新范围:文档把同源 Origin 剥离限定到 loopback(与代码一致),并为预认证 CORS 墙和非 loopback shell 行为各加了一个钉住测试。

未发现阻断问题或规范违规。

测试证据:审查提交上的 CI 全部结束且全绿,没有需要归因的失败。Serve A/B 用 PR base 与本 head 分别构建、以固定端点集对比响应,无意外差异;真实 daemon E2E 矩阵实际启动了 qwen serve 进程。被跳过的检查在 ci.yml 中仅限 merge_group 事件,属于所有 PR 的共同设计,会在合并队列中运行。上一个 head 的沙箱 /verify 以 120/120 断言通过(报告在本帖中);之后的两个提交只是文档措辞和两个钉住测试,针对当前 head 的新一轮 verify 会在其自己的评论中汇报。A/B 对比加上钉住删除的测试已经证实了本 PR 唯一的行为主张(除 /demo 消失外一切不变),因此无需额外的沙箱验证触发。

Qwen Code · qwen3.8-max

Reviewed at b1b135b9dc075101bba4bbf5a485501a6ecbf850 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — a reductive change with an observed motivation, a pinned removal, green A/B and daemon-E2E evidence, and nothing left unverified.

Stepping back: this PR makes the codebase smaller and harder to misroute, which is the rare combination where the motivation, the diff, and the evidence all point the same way. The demo page demonstrably attracted work that belonged to the Web Shell (#8762 being the concrete case), and nothing on the shipped or development path used it.

Against my independent proposal, the implementation matches one-to-one and then exceeds it — the replacement tests don't just delete the old coverage, they pin the new contract (/demo 404s as an unknown path, navigation degrades to the SPA fallback, and the fallback's bearer gating applies once a token exists), so the removal cannot silently regress. Every edit serves the stated goal; the only "extra" is Prettier reflowing Markdown table widths in two docs, which the PR body calls out honestly.

This re-run re-reviewed everything after the two follow-up commits and the base merges that landed since the last pass. They changed no behavior — doc wording scoped to loopback, two more pinning tests — and I confirmed the head tree still has zero dangling /demo references and a correctly scoped getPort removal. CI settled fully green on the reviewed commit: unit suite, Serve A/B, the real daemon E2E matrix, the Web Shell E2E smoke, and the Desktop Shell builds. No PR workflow runs remain pending for this head, and the sandboxed verify that passed 120/120 on the previous head has a fresh run in flight for this one.

Approving, pinned to the reviewed commit.

中文说明

总体评价:这是一个让代码库变得更小、也更不容易把工作引偏的 PR —— 动机、diff 和证据三者方向一致,这并不多见。demo 页面确实吸引了本应属于 Web Shell 的工作(#8762 是具体案例),而发布路径和开发路径都没有使用它。

与我的独立方案相比,实现一一对应并且更进一步——替换测试不只是删掉旧覆盖,而是钉住了新契约(/demo 作为未知路径返回 404、导航降级到 SPA fallback、配置 token 后该 fallback 受 bearer 门控),删除不会被悄悄回退。每一处改动都服务于既定目标;唯一的"额外"是两个文档中 Prettier 重排表格列宽,PR 正文已如实说明。

本次 re-run 在上次审查之后新增的两个修复提交和 base 合并之上重新审查了全部内容。它们没有改变行为——只是把文档措辞限定到 loopback、并新增两个钉住测试——我确认当前 head 树中依然没有任何 /demo 残留引用,getPort 的移除范围也依然正确。审查提交上的 CI 已全部结束且全绿:单元套件、Serve A/B、真实 daemon E2E 矩阵、Web Shell E2E 冒烟、Desktop Shell 构建。该 head 上没有任何仍在运行的 PR 工作流;上一个 head 上以 120/120 通过的沙箱验证也已有针对当前 head 的新一轮在运行中。

批准合并,批准锚定在本次审查的提交上。

Qwen Code · qwen3.8-max

Reviewed at b1b135b9dc075101bba4bbf5a485501a6ecbf850 · re-run with @qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@jifeng

jifeng commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

LGTM, looks ready to ship. ✅

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind main, so it merged current main in via update-branch and will retry on the next scan. A stale base (a dependency or symbol main already changed) can fail the build without being the fix's fault; if it still fails once current, it hands off to a human.

What I found before stopping:
Qwen failed during address-review: status 125.

See the Qwen Autofix agent step logs for model/tool output.

Run log: https://github.com/QwenLM/qwen-code/actions/runs/31349170722


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

jifeng
jifeng previously approved these changes Aug 10, 2026

@jifeng jifeng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally. Not explored to full depth (tool budget reached): This PR removes the daemon's /demo debug page, folds the ...: I did not deep-verify the Web Shell client's actual UI features ("workspace inspector", "permission UX") inside packages/web-shell ; I checked only intra-PR co….

中文说明

已审查。 建议见行内评论。 1 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。 未探索到全部深度(达到工具调用预算):This PR removes the daemon's /demo debug page, folds the ...:I did not deep-verify the Web Shell client's actual UI features ("workspace inspector", "permission UX") inside packages/web-shell ; I checked only intra-PR co…

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

```

Open `http://127.0.0.1:4170/demo` in a browser to see the debug console: chat UI, event stream, and workspace inspection. In the default loopback dev mode, `createServeApp()` mounts the `/demo` route from `packages/cli/src/serve/routes/health-demo.ts` **before** `bearerAuth`, so no token is required.
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured. `--no-web` opts out and leaves the daemon API-only.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-1: The rewritten §1 claims the shell's API calls "carry the bearer when one is configured", but the doc never explains how the token reaches the browser — the only usage instruction is Open http://127.0.0.1:4170/, which yields a 401-ing shell when auth is on — Failure scenario: an operator follows §1 with auth configured and every API call returns 401; the Web Shell has no in-UI token entry, and the token reaches the browser only via qwen serve --open (which appends #token=) or a manual #token=/?token= fragment.

Suggested change
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured. `--no-web` opts out and leaves the daemon API-only.
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured — start the daemon with `--open` (which puts the token in the URL fragment, never sent to the server) or append `#token=…` manually when auth is enabled. `--no-web` opts out and leaves the daemon API-only.
中文说明

改写的 §1 声称 Web Shell 的 API 调用"配置了 token 时会自动携带 bearer",但文档从未说明 token 如何到达浏览器——唯一的用法说明是 打开 http://127.0.0.1:4170/,开启认证后这会让外壳渲染成功但所有 API 调用返回 401。Web Shell 没有 UI 内输入 token 的入口;token 只能通过 qwen serve --open(把 token 放进 URL fragment)、手动在 URL 加 #token=/?token=、或扩展宿主 postMessage 传递。建议在 §1 说明开启认证后需用 --open 或手动附加 #token=… 打开外壳。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

| Loopback without `--require-auth` | `routes/health-demo.ts`, mounted by `createServeApp()` **before** `bearerAuth` | Works without token |
| Loopback with `--require-auth` | `routes/health-demo.ts`, mounted by `createServeApp()` **after** `bearerAuth` | Difficult to use from a plain browser; use curl or SDK |
| Non-loopback bind | `routes/health-demo.ts`, mounted by `createServeApp()` **after** `bearerAuth` | Same as above |
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R1-2: §8's "mounted before bearerAuth in every launch mode" assurance omits that on a non-loopback bind without --allow-origin the Web Shell is effectively read-only: same-origin POSTs carry an Origin header the CORS wall rejects with 403 — Failure scenario: an operator exposes the daemon on a non-loopback bind, opens the shell per §8, reads "Every API route it calls stays token-gated", then every mutation fails with 403 Request denied by CORS policy, which looks like an auth bug and contradicts the daemon's own boot diagnostic ("the Web Shell is read-only on a non-loopback bind").

Suggested change
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself.
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself. On a non-loopback bind the shell is read-only unless `--allow-origin <origin>` is passed — same-origin POSTs carry an `Origin` header that the CORS wall rejects (403) — so pass `--allow-origin` for any bind beyond loopback.
中文说明

§8 声称外壳"在每个启动模式下都挂在 bearerAuth 之前",但没有说明在非 loopback 绑定且未配置 --allow-origin 时 Web Shell 实际是只读的:同源 POST 携带的 Origin 头会被 CORS 墙以 403 拒绝。daemon 自己的启动诊断就写明此模式下 UI"实际上是只读的"。建议在 §8 补充非 loopback 绑定下需传 --allow-origin <origin> 才能进行写操作。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

| Routes | File | Mounting entry |
| -------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `/health`, `/demo` | `packages/cli/src/serve/routes/health-demo.ts` | `healthDemoRoutes.register()` |
| `/health` | `packages/cli/src/serve/routes/health.ts` | `healthRoutes.register()` |

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R2-1: The section 9 call-chain diagram (line 256) still lists /demo as a mounted route — route mounting (health / demo / capabilities / …) — in the same document this PR rewrote to remove /demo, directly contradicting the corrected section 10 route table below — Failure scenario: a developer reading the call-chain diagram sees /demo as a mounted route pointing at demo.ts, which this PR deletes; the diagram contradicts the rest of the same document and misdirects readers to a page that no longer exists.

Suggested change
| `/health` | `packages/cli/src/serve/routes/health.ts` | `healthRoutes.register()` |
| |- route mounting (health / web-shell static / capabilities / workspace / session / SSE / ACP HTTP)
中文说明

第 9 节的调用链图示(第 256 行)仍把 /demo 列为挂载路由——route mounting (health / demo / capabilities / …)——与本 PR 刚改掉 /demo 的同一份文档矛盾,也直接与下方已修正的第 10 节路由表冲突。建议把图示中的 /demo 移除,改为 health / web-shell static / capabilities / workspace / session / SSE / ACP HTTP。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

| `serve/daemon-logger.ts` | `DaemonLogger` structured file logs. See [`19-observability.md`](./19-observability.md). |
| `serve/debug-mode.ts` | Shared `isServeDebugMode()` predicate controlling verbose error context in HTTP responses. |
| `serve/acp-http/` | ACP Streamable HTTP transport (RFD #721), mounted at `/acp`. Seven files implement JSON-RPC POST, SSE GET, DELETE teardown, and shared bridge usage in parallel with the REST surface. |
| `serve/web-shell-static.ts`, `serve/web-shell-resolver.ts` | Locate and mount the built Web Shell assets (the daemon's browser UI) at `/`, `/assets`, and `/session/:id`, plus the SPA deep-link fallback registered after all API routes. Mounted **before** `bearerAuth` in every launch mode — a browser cannot attach `Authorization` to a navigation or subresource — while every API route it calls stays token-gated. Degrades to API-only when the assets are absent; `--no-web` opts out. |

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R2-5: This PR promotes --no-web to first-class daemon-docs guidance, but 02-serve-runtime.md's Configuration "Flags" table has no --no-web entry, and the page's own cross-reference "See 17-configuration.md for the merged reference" leads to a page that has zero --web/--no-web rows — despite 00-index.md billing that page as where "Full qwen serve flags … are collected in one page" — Failure scenario: a developer reads the new row and wants the flag's type/default/interactions; they follow the merged-reference link, and the reference page contains no --web/--no-web row, so the flag's semantics are discoverable only by grepping prose across three docs.

中文说明

本 PR 把 --no-web 提升为一等公民的操作指引,但 02-serve-runtime.md 的 Configuration "Flags" 表没有 --no-web 条目,而本页指向的"合并参考"17-configuration.md 中也没有任何 --web/--no-web 行——尽管 00-index.md 声称该页是"完整的 qwen serve 标志集合"。建议在两份文档的标志表中补上 --web / --no-web 行(boolean,默认 true,镜像 docs/users/qwen-serve.md 中已有的语义)。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

## 8. Is there a browser UI?

**Yes.** It is implemented by `getDemoHtml(port)` in `packages/cli/src/serve/demo.ts` as self-contained HTML with no external dependency.
**Yes — the Web Shell.** `resolveWebShellDir()` finds the built assets (bundled next to the CLI bundle in a release, `packages/web-shell/dist` in a checkout) and `mountWebShellAssets()` serves them at `/`, `/assets`, and `/session/:id`. When the assets are missing the daemon degrades to API-only instead of crashing; `--no-web` opts out explicitly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R2-8: The rewritten §8 claims mountWebShellAssets() serves the shell at /session/:id with no qualifier, but the route answers only document navigations (isDocumentNavigation) — the sibling doc rewritten in this same PR (qwen-serve-protocol.md) correctly qualifies the identical claim as "/session/:id document navigations" — Failure scenario: §8 sits immediately below §7's curl checklist, so an operator verifying the claim runs curl http://127.0.0.1:4170/session/<sid> with curl's default Accept: */*; isDocumentNavigation() returns false and there is no GET /session/:id API route, so the request ends as a 401 or JSON 404 — never the shell HTML the sentence implies.

Suggested change
**Yes — the Web Shell.** `resolveWebShellDir()` finds the built assets (bundled next to the CLI bundle in a release, `packages/web-shell/dist` in a checkout) and `mountWebShellAssets()` serves them at `/`, `/assets`, and `/session/:id`. When the assets are missing the daemon degrades to API-only instead of crashing; `--no-web` opts out explicitly.
**Yes — the Web Shell.** `resolveWebShellDir()` finds the built assets (bundled next to the CLI bundle in a release, `packages/web-shell/dist` in a checkout) and `mountWebShellAssets()` serves them at `/`, `/assets`, and `/session/:id` document navigations (browser deep links — a plain `curl /session/<id>` gets the API's 401/404, not the shell). When the assets are missing the daemon degrades to API-only instead of crashing; `--no-web` opts out explicitly.
中文说明

改写的 §8 声称 mountWebShellAssets()/session/:id 提供外壳服务,但没有说明该路由只应答文档导航isDocumentNavigation);同一 PR 改写的 qwen-serve-protocol.md 已用"/session/:id document navigations"正确限定。由于 §8 紧跟在 §7 的 curl 清单之下,用 curl 的默认 Accept: */* 访问会因 isDocumentNavigation() 为 false 而落到 401/JSON 404,而非外壳 HTML。建议补充"document navigations"限定。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

Comment on lines 25165 to 25166
describe('same-origin Origin-stripping middleware', () => {
it('strips loopback Origin header matching daemon port', async () => {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-3: The deleted /demo CORS test (GET /demo + Origin: https://evil.example.com → 403) was the only assertion that a pre-auth page — not an API route — sits behind the denyBrowserOriginCors wall. Nothing in this PR's replacement tests re-pins that contract for the shell: every surviving Origin-header test targets API paths, and none hits the Web Shell page paths /, /session/:id, or /assets/* — Failure scenario: a future change moves mountWebShellAssets above denyBrowserOriginCors (the exact class of regression the new rate-limit pin guards for the limiter), and nothing fails because no Origin-bearing request ever reaches the pre-auth page paths; the daemon's only pre-auth HTML surface then answers cross-origin requests without the 403 the middleware is supposed to produce.

Suggested change
describe('same-origin Origin-stripping middleware', () => {
it('strips loopback Origin header matching daemon port', async () => {
it('rejects cross-origin requests for the pre-auth shell page (CORS wall runs first)', async () => {
const res = await app.get('/').set('Origin', 'https://evil.example.com');
expect(res.status).toBe(403);
});
中文说明

被删除的 /demo CORS 测试(GET /demo + Origin: https://evil.example.com → 403)是唯一断言预认证页面(而非 API 路由)位于 denyBrowserOriginCors 墙之后的用例。本 PR 的替代测试没有为外壳重新固定这一契约:现有带 Origin 的测试都指向 API 路径,没有覆盖 Web Shell 页面路径 //session/:id/assets/*。建议在 Web Shell 静态服务 describe 中补一个断言 GET / 带恶意 Origin 返回 403 的测试。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

Comment thread docs/design/serve-server-final-split.md Outdated
Comment on lines +18 to +19
8. JSON body parser and JSON parser error mapper
9. post-auth `/health` and `/demo` when required
9. post-auth `/health` when required

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R5-1: Both design docs list "JSON body parser and JSON parser error mapper" (item 8) before "post-auth /health when required" (item 9), but createServeApp() registers post-auth /health (server.ts:1705) before installJsonBodyParser (server.ts:1708). This PR re-emits item 9 (dropping /demo) while its own server.ts hunk edits the exact code region — Failure scenario: a maintainer audits createServeApp() against the design doc's order list (the doc's stated purpose) and reasons about the middleware stack against a false order; the JSON-parser error mapper never wraps post-auth /health requests, contrary to what the list implies.

Suggested change
8. JSON body parser and JSON parser error mapper
9. post-auth `/health` and `/demo` when required
9. post-auth `/health` when required
8. post-auth `/health` when required
9. JSON body parser and JSON parser error mapper
中文说明

两份设计文档把"JSON body parser and JSON parser error mapper"(第 8 项)列在"post-auth /health when required"(第 9 项)之前,但 createServeApp() 实际先注册 post-auth /health(server.ts:1705)再 installJsonBodyParser(server.ts:1708)。本 PR 重写了第 9 项(去掉 /demo)且其 server.ts hunk 恰好编辑该区域。建议交换第 8、9 项以匹配实际装配顺序。

— DeepSeek/deepseek-v4-flash via Qwen Code /review (v0.21.8)

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Autofix review round: no action taken (PR #8805)

Feedback triage

Every feedback item newer than the last evaluation was read and classified. None is actionable — all are approvals or informational bot passes:

Source Item Classification Action
@jifeng (maintainer) Issue comment + review: "LGTM, looks ready to ship. ✅" Approval None
@qwen-code-ci-bot (automated reviewer) Review: "LGTM, looks ready to ship. ✅" Approval None
@qwen-code-ci-bot Sandboxed verification: ✅ passed — merge-ready (120/120 scripted assertions) Informational pass None
@qwen-code-ci-bot Triage stages 1–3: gate check passing, code review found no blockers or convention violations, confidence 5/5, approved at the reviewed commit; notes all earlier bot findings were already addressed in the follow-up commit Informational pass None
@wenshao "@qwen-code /triage" Bot trigger command, not feedback for this flow None
@qwen-code-dev-bot Status note that the stale base was updated by merging current main Informational; the merge commit is already at HEAD None

Checks

  • Failed checks: none.
  • Still-red checks persisting from before the last evaluation: none.
  • Review and inline-comment sections of the triaged feedback: empty.
  • No verification-gate rejection, budget warning, or same-run repair context was present.

Decision

No code change this round. The PR head already carries the full removal of the /demo debug page, tests pinning that removal, and the follow-up commit that addressed every earlier automated finding; maintainer, automated reviewer, triage, and sandboxed verification all approve the current head.

中文说明

Autofix 评审轮次:未做改动(PR #8805

反馈分类

已阅读并分类上次评估之后的每一条反馈,均无需处理——全部为批准或信息性的机器人通过记录:

来源 内容 分类 操作
@jifeng(维护者) Issue 评论 + Review:“LGTM, looks ready to ship. ✅” 批准
@qwen-code-ci-bot(自动评审) Review:“LGTM, looks ready to ship. ✅” 批准
@qwen-code-ci-bot 沙箱验证:✅ 通过——可合并(脚本断言 120/120) 信息性通过
@qwen-code-ci-bot Triage 阶段 1–3:门禁检查通过,代码评审未发现阻断项或规范违规,置信度 5/5,批准锚定在被审查提交上;并确认此前机器人提出的所有建议已在后续提交中修复 信息性通过
@wenshao @qwen-code /triage” 机器人触发命令,不属于本流程的反馈
@qwen-code-dev-bot 状态说明:落后的 base 已通过合并当前 main 更新 信息性;合并提交已在 HEAD

检查

  • 失败的检查: 无。
  • 上次评估之前遗留的仍失败检查: 无。
  • 分类后的反馈中,Review 与行内评论部分均为空。
  • 不存在验证门禁拒绝、预算告警或同轮修复上下文。

结论

本轮不做任何代码改动。当前 PR head 已包含 /demo 调试页的完整移除、钉住该移除的测试,以及修复了此前所有自动评审建议的后续提交;维护者、自动评审、triage 与沙箱验证均批准当前 head。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

… wall

Review follow-up. The removal rewrote the daemon docs around the Web
Shell, and three of the rewritten claims did not match what the runtime
actually does: §1 never said how the bearer reaches the browser (with
auth on, the plain URL loads a shell whose every API call 401s), §8
called the shell writable on any bind (on a non-loopback bind without
`--allow-origin` its POSTs hit the CORS wall and 403), and §8 served
`/session/:id` without the document-navigation qualifier its own code
enforces. The §9 call-chain diagram also still listed the deleted
`/demo` route, the developer flag references had no `--web`/`--no-web`
row despite the new guidance pointing at the flag, and both design docs
listed the JSON body parser ahead of post-auth `/health` while
`createServeApp()` registers them the other way round.

The deleted `/demo` CORS test was also the only assertion that a
pre-auth page sits behind the Origin wall — every surviving Origin test
targets an API path. Re-pin it for the shell root so a mount-order
regression fails instead of exposing the pre-auth HTML surface
cross-origin.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 4/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 4/100 轮)。改动内容与我反驳保留之处如下:

Review response summary — PR #8805

All seven findings are Suggestion-level from the automated reviewer. Each was verified against the current code before editing, and all seven are addressed in one commit (fix(serve): correct Web Shell doc claims and re-pin the pre-auth CORS wall). No conflicts: --conflict false, and origin/main was not merged.

Feedback points and dispositions

  1. rc:3746344200 (R1-1) — quickstart §1 claims the shell's API calls "carry the bearer when one is configured" but never explains how the token reaches the browser. — Addressed. Verified: the Web Shell reads the token only from the #token= URL fragment (?token= fallback) in packages/web-shell/client/config/daemon.ts, qwen serve --open appends it (maybeOpenWebShellBrowser in commands/serve.ts), and there is no in-UI token entry. With auth on, opening the plain URL yields a shell whose every API call 401s. §1 now tells operators to start with --open or append #token=… manually when auth is enabled.

  2. rc:3746344216 (R1-2) — §8 omits that on a non-loopback bind without --allow-origin the Web Shell is effectively read-only. — Addressed. Verified: installSelfOriginStripMiddleware (serve/server/self-origin.ts) strips only loopback origins, so on a non-loopback bind the shell's same-origin POSTs keep their Origin header and denyBrowserOriginCors rejects them with 403 — exactly what the boot diagnostic in run-qwen-serve.ts warns. §8 now states the shell is read-only beyond loopback unless --allow-origin <origin> is passed.

  3. rc:3746344224 (R2-1) — the §9 call-chain diagram still lists /demo as a mounted route. — Addressed. The diagram line now reads route mounting (health / web-shell static / capabilities / workspace / session / SSE / ACP HTTP), matching the §10 route table this PR already corrected.

  4. rc:3746344227 (R2-5) — this PR promotes --no-web to first-class guidance, but neither the 02-serve-runtime.md Configuration table nor the "merged reference" 17-configuration.md has a --web/--no-web row. — Addressed. Added a --web / --no-web row to both tables (boolean, default true), mirroring the semantics already documented in docs/users/qwen-serve.md.

  5. rc:3746344229 (R2-8) — §8 claims mountWebShellAssets() serves the shell at /session/:id without the document-navigation qualifier. — Addressed. Verified: the route answers only when isDocumentNavigation(req) is true (web-shell-static.ts), and the sibling qwen-serve-protocol.md rewritten in this same PR already qualifies the identical claim. §8 now says "document navigations" and notes that a plain curl /session/<id> gets the API's 401/404, not the shell.

  6. rc:3746344233 (R3-3) — the deleted /demo CORS test was the only assertion that a pre-auth page sits behind the denyBrowserOriginCors wall; every surviving Origin test targets API paths. — Addressed. Added rejects cross-origin requests for the pre-auth shell page (CORS wall runs first) to the Web Shell static serving suite: GET / with Origin: https://evil.example.com must return 403 with the wall's JSON envelope. Verified against createServeApp() ordering (CORS wall registered before mountWebShellAssets); the test passes.

  7. rc:3746344240 (R5-1) — both design docs list the JSON body parser before post-auth /health, but createServeApp() registers them the other way round. — Addressed. Verified in server.ts: the post-auth healthRoutes.register(app) branch runs before installJsonBodyParser(app). Items 8 and 9 are swapped in both docs/design/serve-server-final-split.md and docs/design/serve-server-split.md.

Changed files

  • docs/developers/daemon/20-quickstart-operations.md (R1-1, R1-2, R2-1, R2-8)
  • docs/developers/daemon/02-serve-runtime.md (R2-5)
  • docs/developers/daemon/17-configuration.md (R2-5)
  • docs/design/serve-server-final-split.md (R5-1)
  • docs/design/serve-server-split.md (R5-1)
  • packages/cli/src/serve/server.test.ts (R3-3)

Conflict notes

None — --conflict false; no merge performed.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx vitest run src/serve/server.test.ts (inside packages/cli, the touched file) — 902 passed, 0 failed (includes the new CORS-wall test)
  • npx vitest run src/serve/server.test.ts -t "Web Shell static serving" — 26 passed (focused run; new test confirmed green individually)
  • npx prettier --check on all six changed files — clean
  • Integration tests after npm run bundle — not run: the change is documentation text plus one unit-level test, fully exercised by the focused Vitest runs above; nothing here is only exercised through the bundled CLI or integration harness.
中文说明

审查回应摘要 — PR #8805

七条发现均来自自动审查器的 Suggestion 级别。每一条都在编辑前对照当前代码核实,全部七条已在一次提交中处理(fix(serve): correct Web Shell doc claims and re-pin the pre-auth CORS wall)。无冲突:--conflict false,未合并 origin/main

反馈点与处理

  1. rc:3746344200 (R1-1) — 快速上手 §1 声称外壳的 API 调用"配置了 bearer 时会自动携带",但从未说明 token 如何到达浏览器。 — 已处理。 已核实:Web Shell 只从 #token= URL fragment(?token= 兜底)读取 token(packages/web-shell/client/config/daemon.ts),qwen serve --open 会追加该 fragment(commands/serve.tsmaybeOpenWebShellBrowser),且 UI 内没有 token 输入入口。开启认证后直接打开纯 URL 会得到一个所有 API 调用全部 401 的外壳。§1 现在告知操作者在启用认证时使用 --open 启动或手动追加 #token=…

  2. rc:3746344216 (R1-2) — §8 没有说明在非 loopback 绑定且未配置 --allow-origin 时 Web Shell 实际是只读的。 — 已处理。 已核实:installSelfOriginStripMiddlewareserve/server/self-origin.ts)只剥离 loopback 来源的 Origin,因此在非 loopback 绑定下外壳的同源 POST 仍携带 Origin 头,被 denyBrowserOriginCors 以 403 拒绝——这正是 run-qwen-serve.ts 启动诊断所警告的行为。§8 现在说明:超出 loopback 的绑定若不传 --allow-origin <origin>,外壳是只读的。

  3. rc:3746344224 (R2-1) — §9 调用链图示仍把 /demo 列为挂载路由。 — 已处理。 图示行已改为 route mounting (health / web-shell static / capabilities / workspace / session / SSE / ACP HTTP),与本 PR 已修正的 §10 路由表一致。

  4. rc:3746344227 (R2-5) — 本 PR 把 --no-web 提升为一等指引,但 02-serve-runtime.md 的 Configuration 表和"合并参考"17-configuration.md 都没有 --web/--no-web 行。 — 已处理。 在两份表中各补一行 --web / --no-web(boolean,默认 true),语义镜像 docs/users/qwen-serve.md 中已有的描述。

  5. rc:3746344229 (R2-8) — §8 声称 mountWebShellAssets()/session/:id 提供外壳,却没有 document-navigation 限定。 — 已处理。 已核实:该路由仅在 isDocumentNavigation(req) 为 true 时应答(web-shell-static.ts),同一 PR 改写的 qwen-serve-protocol.md 已对相同说法加了限定。§8 现在写明 "document navigations",并注明纯 curl /session/<id> 得到的是 API 的 401/404 而非外壳。

  6. rc:3746344233 (R3-3) — 被删除的 /demo CORS 测试是唯一断言预认证页面位于 denyBrowserOriginCors 墙之后的用例;现存所有带 Origin 的测试都指向 API 路径。 — 已处理。 在 Web Shell 静态服务测试组中新增 rejects cross-origin requests for the pre-auth shell page (CORS wall runs first):带 Origin: https://evil.example.comGET / 必须返回 403 及墙的标准 JSON 响应体。已对照 createServeApp() 的装配顺序核实(CORS 墙在 mountWebShellAssets 之前注册),测试通过。

  7. rc:3746344240 (R5-1) — 两份设计文档把 JSON body parser 列在 post-auth /health 之前,但 createServeApp() 的实际注册顺序相反。 — 已处理。 已在 server.ts 中核实:post-auth 的 healthRoutes.register(app) 分支先于 installJsonBodyParser(app) 执行。docs/design/serve-server-final-split.mddocs/design/serve-server-split.md 中的第 8、9 项已交换。

变更文件

  • docs/developers/daemon/20-quickstart-operations.md(R1-1、R1-2、R2-1、R2-8)
  • docs/developers/daemon/02-serve-runtime.md(R2-5)
  • docs/developers/daemon/17-configuration.md(R2-5)
  • docs/design/serve-server-final-split.md(R5-1)
  • docs/design/serve-server-split.md(R5-1)
  • packages/cli/src/serve/server.test.ts(R3-3)

冲突说明

无 — --conflict false,未执行合并。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx vitest run src/serve/server.test.ts(在 packages/cli 内,即被改动的文件)— 902 个测试全部通过,0 失败(包含新增的 CORS 墙测试)
  • npx vitest run src/serve/server.test.ts -t "Web Shell static serving" — 26 个通过(聚焦运行;已单独确认新测试为绿)
  • 对全部六个变更文件执行 npx prettier --check — 干净
  • npm run bundle 之后的集成测试 — 未运行:本次变更为文档文本加一个单元级测试,上面的聚焦 Vitest 运行已完整覆盖;此处没有任何只能通过打包 CLI 或集成测试框架验证的行为。

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

中文说明

已审查。 建议见行内评论。 1 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

— qwen3.8-max via Qwen Code /review (v0.21.8)

* Content-Security-Policy for the Web Shell HTML shell.
*
* Deliberately looser than the `/demo` page's `default-src 'none'`: the real
* Deliberately looser than a `default-src 'none'` static page: the real

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The demo→Web Shell rename sweep missed a sibling: packages/cli/src/serve/server/self-origin.ts:10 — the module header of installSelfOriginStripMiddleware still reads "Allow same-origin requests from the demo page.", a page this PR deletes, while the in-function comment in the same file already says "loopback web shell". Every other reference was updated (docs, the --allow-origin '*' boot warning, the comments in this file, the test rename to "loopback self-origin shim"). — Failure scenario: a maintainer later removing dead demo scaffolding greps for demo-page references, reads that header, concludes the Origin-strip middleware exists only for the deleted /demo page, and deletes or relocates it. Every same-origin Web Shell POST/fetch then carries an Origin header that denyBrowserOriginCors rejects with 403 — the Web Shell UI stops working in default loopback mode. The PR's own 12-auth-security.md warns: "If a future change moves the strip elsewhere, the Web Shell breaks." — Suggested fix: change the header to "Allow same-origin requests from the Web Shell."

中文说明

[建议] demo→Web Shell 的重命名清理遗漏了一处同类引用:packages/cli/src/serve/server/self-origin.ts:10 —— installSelfOriginStripMiddleware 的模块头注释仍写着 "Allow same-origin requests from the demo page.",而这个页面已被本 PR 删除,同文件内的函数内注释却已经写着 "loopback web shell"。其他所有引用都已更新(文档、--allow-origin '*' 启动告警、本文件中的注释、以及重命名为 "loopback self-origin shim" 的测试)。— 失败场景:之后有位维护者清理 demo 遗留代码,搜索 demo 相关引用时读到该头注释,以为这个 Origin 剥离中间件只为已删除的 /demo 页面而存在,于是删除或移动它。此后 Web Shell 的每个同源 POST/fetch 都会携带 Origin 头并被 denyBrowserOriginCors 以 403 拒绝 —— Web Shell UI 在默认 loopback 模式下将无法使用。本 PR 自己更新的 12-auth-security.md 也警告过:"If a future change moves the strip elsewhere, the Web Shell breaks."。— 建议修复:将该头注释改为 "Allow same-origin requests from the Web Shell."。

— qwen3.8-max via Qwen Code /review (v0.21.8)

| `--external-tool-guard-timeout-ms <n>` | integer `100..30000` | `3000` | Per-handshake and per-prepare deadline. A timeout fails startup during the handshake or fails the invocation closed during a turn. |
| `--allow-origin <pattern>` | repeatable string | unset | Cross-origin allowlist that replaces the default CORS denial. `*` allows any origin but requires a token. |
| `--allow-private-auth-base-url` | boolean | `false` | Allows `/workspace/auth/provider` to install localhost / private-network auth provider `baseUrl`; use only in trusted local development. |
| `--web` / `--no-web` | boolean | `true` | Serve the built Web Shell SPA at the daemon root (`GET /`, `/assets/*`, and `/session/:id` document navigations). These entry points are mounted before `bearerAuth`; every API route stays token-gated. `--no-web` leaves the daemon API-only. |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] This diff adds the --web/--no-web row to the CLI-flag table, but the same page's ## ServeOptions (programmatic embedding) table — introduced as "It mirrors the CLI flags above and adds:" — gains no serveWebShell row, even though serveWebShell?: boolean (types.ts) is the real field mapped from this flag (serve.ts:805, fast-path.ts:83) and honored by createServeApp/runQwenServe. Before this diff both tables were consistently silent about the switch; the added row makes the page contradict its own mirror claim. — Failure scenario: an embedder wiring runQwenServe/createServeApp programmatically — the named audience of that section — wants the API-only mode the new row describes, looks up the corresponding option in the ServeOptions table, finds nothing, and concludes the programmatic API has no opt-out. — Suggested fix: add a serveWebShell row to the ServeOptions table, e.g. "Serve the built Web Shell SPA at the daemon root (default true); false (the CLI's --no-web) leaves the daemon API-only. No effect when the build omits the Web Shell assets."

中文说明

[建议] 本 diff 在 CLI 参数表中新增了 --web/--no-web 行,但同一页的 ## ServeOptions (programmatic embedding) 表 —— 其引导语写着 "It mirrors the CLI flags above and adds:" —— 却没有新增 serveWebShell 行,尽管 serveWebShell?: boolean(types.ts)正是该参数映射的真实字段(serve.ts:805fast-path.ts:83),且被 createServeApp/runQwenServe 实际消费。改动前两张表对这个开关都一致地未记录;新增行使该页与自身的 "镜像 CLI 参数" 声明相矛盾。— 失败场景:一位按该节目受众(编程嵌入方)接入 runQwenServe/createServeApp 的开发者,想要新行所描述的 API-only 模式,于是在 ServeOptions 表中查找对应选项,什么也找不到,从而以为编程接口没有该开关。— 建议修复:在 ServeOptions 表中补一行 serveWebShell,例如 "Serve the built Web Shell SPA at the daemon root (default true); false (the CLI's --no-web) leaves the daemon API-only. No effect when the build omits the Web Shell assets."。

— qwen3.8-max via Qwen Code /review (v0.21.8)

});

it('demo self-origin shim still works when `--allow-origin` is set (loopback strip runs first)', async () => {
it('loopback self-origin shim still works when `--allow-origin` is set (loopback strip runs first)', async () => {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The deleted /demo suite pinned the browser-UI surface on a non-loopback bind (hostname: '0.0.0.0' tests in this diff's - lines); the successor contract — "the shell is pre-auth in every launch mode", documented by this PR at 20-quickstart-operations.md:211 — has no non-loopback test pin. Every other deleted guard got an explicit re-pin (the CORS test even says "Re-pins the contract the deleted /demo CORS test carried"); the only non-loopback Web Shell test is the negative /health non-shadowing case (~line 3406). — Failure scenario: a future change reintroduces bind-conditional gating of mountWebShellAssets — the exact pattern this PR deletes (the old /demo registered after bearerAuth on non-loopback, so the precedent is in-repo and plausible to copy). Browser navigations to any --hostname 0.0.0.0 deployment then 401 and white-screen with no failing test. — Suggested fix: add one test in the Web Shell static serving describe: createServeApp({ ...baseOpts, hostname: '0.0.0.0', token: 'secret' }, undefined, { webShellDir }), then GET / with Accept: text/html → expect 200 and the shell body.

中文说明

[建议] 被删除的 /demo 测试套件曾对非 loopback 绑定下的浏览器 UI 面做过固定(本 diff - 行中 hostname: '0.0.0.0' 的测试);其继承契约 —— 本 PR 记录在 20-quickstart-operations.md:211 的 "shell 在所有启动模式下都是 pre-auth" —— 却没有非 loopback 的测试固定。其他每个被删的守卫都有显式重新固定(CORS 测试甚至注明 "Re-pins the contract the deleted /demo CORS test carried");唯一的非 loopback Web Shell 测试是反向的 /health 不遮蔽用例(约 3406 行)。— 失败场景:未来某个改动重新引入对 mountWebShellAssets 的按绑定条件鉴权 —— 正是本 PR 删除的模式(旧 /demo 在非 loopback 下注册在 bearerAuth 之后,该先例就在仓库里,很容易被照抄)。届时对任何 --hostname 0.0.0.0 部署的浏览器导航将 401 并白屏,且没有任何测试失败。— 建议修复:在 Web Shell static serving describe 中加一个测试:createServeApp({ ...baseOpts, hostname: '0.0.0.0', token: 'secret' }, undefined, { webShellDir }),然后以 Accept: text/html 请求 GET / → 断言 200 且返回 shell 主体。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Reject any request with an `Origin` header. CLI/SDK never set Origin; only browsers do. Returns deterministic `403 { error: 'Request denied by CORS policy' }` rather than the 500 HTML the `cors` package's error-callback would produce.

Exception: the demo page's same-origin XHRs are handled by a separate middleware (in `server.ts`) that strips `Origin` when it matches the daemon's own address.
Exception: the Web Shell's same-origin XHRs are handled by a separate middleware (in `server.ts`) that strips `Origin` when it matches the daemon's own address.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The demo→Web Shell rename keeps the claim that the strip middleware fires "when it matches the daemon's own address", but server/self-origin.ts matches a hard-coded loopback-host set only (127.0.0.1, localhost, [::1], host.docker.internal), independent of the bind address. The base sentence described the demo page, pre-auth only on loopback where the claim held; retargeting it to the Web Shell — pre-auth in every mode — makes it over-broad for non-loopback binds, and contradicts three sibling passages this same PR edits (qwen-serve.md:559 "Loopback self-origin hits", qwen-serve-protocol.md:45, 20-quickstart-operations.md §8's read-only caveat). — Failure scenario: operator binds non-loopback without --allow-origin; the shell HTML loads (pre-auth GET, no Origin), but every same-origin POST carries Origin: http://<lan-ip>:4170, unmatched by the strip set, so denyBrowserOriginCors 403s it and the UI cannot create sessions or send prompts. The operator reads this note — the LAN IP is "the daemon's own address" — concludes the shim malfunctioned instead of discovering the real --allow-origin requirement, and files a wrong-direction bug report.

Suggested change
Exception: the Web Shell's same-origin XHRs are handled by a separate middleware (in `server.ts`) that strips `Origin` when it matches the daemon's own address.
Exception: the Web Shell's same-origin XHRs on a **loopback** bind are handled by a separate middleware (in `server.ts`) that strips `Origin` when it matches one of the loopback self-origins (`127.0.0.1`, `localhost`, `[::1]`, `host.docker.internal`). On non-loopback binds the shell's XHRs carry an unmatched `Origin` and need `--allow-origin` for the daemon origin.
中文说明

[建议] demo→Web Shell 的重命名保留了 "当 Origin 与 daemon 自身地址匹配时由剥离中间件处理" 的说法,但 server/self-origin.ts 只匹配一组硬编码的 loopback 主机(127.0.0.1localhost[::1]host.docker.internal),与实际绑定地址无关。原句描述的是 demo 页面 —— 仅在 loopback 下 pre-auth,该说法在那里成立;将其改指 Web Shell(在所有模式下 pre-auth)后,对非 loopback 绑定就变得过宽,并与本 PR 同时修改的三处兄弟段落矛盾(qwen-serve.md:559 的 "Loopback self-origin hits"、qwen-serve-protocol.md:4520-quickstart-operations.md §8 的只读说明)。— 失败场景:运维者在非 loopback 绑定且未加 --allow-origin;shell HTML 可以加载(pre-auth GET,不带 Origin),但每个同源 POST 都携带 Origin: http://<lan-ip>:4170,不在剥离集合内,被 denyBrowserOriginCors 以 403 拒绝,UI 无法创建会话或发送 prompt。运维者读到本句 —— 局域网 IP 正是 "daemon 自身地址" —— 会以为是剥离中间件出了故障,而不是发现真正需要的 --allow-origin 配置,从而提交方向错误的 bug 报告。

— qwen3.8-max via Qwen Code /review (v0.21.8)


- Direct `createServeApp` without `deps.fsFactory` or `deps.bridge` defaults to `trusted: false`; agent-side ACP `writeTextFile` rejects as `untrusted_workspace`. The warning is printed once.
- `denyBrowserOriginCors` rejects **all** requests carrying `Origin`; the demo page works because another middleware strips matching same-origin values first.
- `denyBrowserOriginCors` rejects **all** requests carrying `Origin`; the Web Shell works because another middleware strips matching same-origin values first.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The demo→Web Shell rename retargets this caveat from a surface pre-auth only on loopback (the base demo page) to one pre-auth in every mode, while the strip middleware it credits matches only hard-coded loopback origins — so "the Web Shell works" is over-broad for non-loopback binds (sibling of the 12-auth-security.md Exception note). — Failure scenario: operator runs qwen serve --hostname 0.0.0.0 without --allow-origin; the shell HTML loads pre-auth (document GET carries no Origin), but every same-origin XHR/POST carries Origin: http://<bind-addr>:4170, unmatched by the loopback-only strip set, and denyBrowserOriginCors 403s it — the shell renders but is completely non-functional, contradicting this caveat's explanation of why the deny-all-Origin wall never breaks the Web Shell.

Suggested change
- `denyBrowserOriginCors` rejects **all** requests carrying `Origin`; the Web Shell works because another middleware strips matching same-origin values first.
- `denyBrowserOriginCors` rejects **all** requests carrying `Origin`; the **loopback** Web Shell works because another middleware strips matching loopback same-origin values first — non-loopback binds require `--allow-origin` for the shell's XHRs.
中文说明

[建议] demo→Web Shell 的重命名把这条注意事项从 "仅 loopback 下 pre-auth 的界面"(原 demo 页)改指到 "所有模式下都 pre-auth" 的界面,而它所依赖的剥离中间件只匹配硬编码的 loopback origin —— 因此 "the Web Shell works" 对非 loopback 绑定过宽(与 12-auth-security.md 中 Exception 一句属同类问题)。— 失败场景:运维者执行 qwen serve --hostname 0.0.0.0 且未加 --allow-origin;shell HTML 以 pre-auth 加载(文档 GET 不带 Origin),但每个同源 XHR/POST 都携带 Origin: http://<bind-addr>:4170,不在仅含 loopback 的剥离集合内,被 denyBrowserOriginCors 以 403 拒绝 —— shell 能渲染出来,却完全不可用,与本注意事项 "为何 deny-all-Origin 墙不会弄坏 Web Shell" 的解释相矛盾。

— qwen3.8-max via Qwen Code /review (v0.21.8)

```

With the hardened loopback recipe (3), `/demo` is registered after `bearerAuth`. A normal browser navigation needs an auth header, so use curl or an SDK script instead.
With the hardened loopback recipe (3), `/health` is registered after `bearerAuth`, so probes must carry the token like every other route.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] "like every other route" is false in recipe 3 — the Web Shell entry points (GET /, /assets/*, /session/:id document navigations) remain pre-auth in every launch mode, including --require-auth (mountWebShellAssets is gated only by serveWebShell !== false, never by requireAuth/bind). §1 of this same page — also rewritten by this diff — says the shell loads without a token, and the --web row this PR adds uses the careful qualifier "every API route stays token-gated", which this sentence drops. The base sentence made no universal claim. — Failure scenario: an operator hardening a daemon with recipe 3 reads this note while enumerating the unauthenticated surface and concludes every route on the port is token-gated, missing that GET / still serves the full Web Shell SPA pre-auth on the same port.

Suggested change
With the hardened loopback recipe (3), `/health` is registered after `bearerAuth`, so probes must carry the token like every other route.
With the hardened loopback recipe (3), `/health` is registered after `bearerAuth`, so probes must carry the token like every other API route (the Web Shell static surface stays pre-auth by design; pass `--no-web` for an API-only daemon).
中文说明

[建议] "like every other route" 在配方 3 下不成立 —— Web Shell 入口(GET //assets/*/session/:id 文档导航)在所有启动模式下(包括 --require-auth)仍然 pre-auth(mountWebShellAssets 只受 serveWebShell !== false 约束,与 requireAuth/绑定方式无关)。本页 §1 —— 同样由本 diff 重写 —— 写明 shell 无需 token 即可加载;本 PR 新增的 --web 行也使用了 "every API route stays token-gated" 这一谨慎限定,而本句丢掉了该限定。原句(base)并未做这种全称断言。— 失败场景:运维者用配方 3 加固 daemon,在枚举未鉴权面时读到本句,以为该端口上所有路由都已 token 鉴权,从而忽略 GET / 仍在同一端口以 pre-auth 提供完整 Web Shell SPA。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Comment thread docs/developers/qwen-serve-protocol.md Outdated
**`--allow-origin <pattern>` (T2.4 [#4514](https://github.com/QwenLM/qwen-code/issues/4514)).** Browser webuis hitting the daemon cross-origin are blocked by default — any request carrying an `Origin` header returns `403 {"error":"Request denied by CORS policy"}` because CLI/SDK clients never send `Origin` and the daemon treats its presence as a sign the request came from a browser context the operator has not opted into. Pass `--allow-origin <pattern>` (repeatable) at boot to install an allowlist instead of the wall. Each pattern is either:

- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` and `/demo` are also gated by the bearer — they're registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach `/health` without a token), and a `*` allowlist makes them reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot, so the `*` exposure surface is just `/health` (status JSON) and `/demo` (a static page whose JS still calls token-gated routes) the actual API surface is gated regardless.
- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` is also gated by the bearer — it's registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach it without a token), and a `*` allowlist makes it reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot and `/health` is registered behind it, so the only surface `*` exposes without a token is the Web Shell static assets (`/`, `/assets/*`, and `/session/:id` document navigations — their JS still calls token-gated routes). `--no-web` removes even that; the actual API surface is gated regardless.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] The rewritten * bullet enumerates the token-less loopback exposure as only /health, but the Web Shell static assets stay pre-auth even under loopback + --require-auth (mountWebShellAssets is unconditional), so under a * allowlist they remain readable from any cross-origin browser. At base the sentence named both pre-auth surfaces (/health and /demo), and --require-auth gated both; the rewrite drops the second surface without acknowledging it can no longer be gated. The bullet's own non-loopback sentence, the sibling user-doc bullet (qwen-serve.md), and the boot warning all enumerate the Web Shell residual — this loopback sentence is the one location that agreement was not applied. — Failure scenario: an operator hardening a loopback daemon that uses --allow-origin '*' follows the recommendation, adds --require-auth, and concludes no token-less * surface remains — whereas any web page open in the user's browser can still read http://127.0.0.1:4170/ and /assets/* cross-origin. Harm is bounded (static shell assets only — the API stays token-gated), but this paragraph is the reference for *'s exposure and its loopback enumeration is incomplete. — Suggested fix: add a note mirroring the non-loopback one: even with --require-auth, the Web Shell static assets stay pre-auth on loopback by design and remain exposed to any cross-origin browser under *; --no-web removes that surface.

中文说明

[建议] 重写后的 * 条目把 loopback 下的无 token 暴露面只列为 /health,但 Web Shell 静态资源即使在 loopback + --require-auth 下仍然 pre-auth(mountWebShellAssets 无条件挂载),因此在 * 允许列表下它们依然可被任意跨源浏览器读取。base 版本同时列出两个 pre-auth 面(/health/demo),且 --require-auth 当时能将两者都置于鉴权之后;重写丢掉了第二个面,且未说明它已无法再被鉴权。该条目自己的非 loopback 句、兄弟用户文档(qwen-serve.md)的条目、以及启动告警都列出了 Web Shell 残留面 —— 唯独这句 loopback 说明没有同步。— 失败场景:运维者为使用 --allow-origin '*' 的 loopback daemon 加固,按建议加上 --require-auth,便以为不再存在无 token 的 * 暴露面 —— 但用户浏览器里打开的任何网页仍可跨源读取 http://127.0.0.1:4170//assets/*。危害有限(仅静态 shell 资源 —— API 仍受 token 鉴权),但本段是 * 暴露面的参考说明,其 loopback 枚举不完整。— 建议修复:补一条与非 loopback 句对应的说明:即使带 --require-auth,Web Shell 静态资源按设计在 loopback 下仍是 pre-auth,在 * 下仍暴露给任意跨源浏览器;--no-web 可移除该暴露面。

— qwen3.8-max via Qwen Code /review (v0.21.8)

…to loopback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 5/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 5/100 轮)。改动内容与我反驳保留之处如下:

Autofix review round summary — PR #8805

All 7 Suggestion-level findings from the automated reviewer were verified against the code and implemented in one commit (32378600e4). No finding was declined. --conflict was false; no merge was performed.

# Finding Disposition Change
R2-1 installSelfOriginStripMiddleware module header still says "Allow same-origin requests from the demo page." Implemented server/self-origin.ts header now reads "Allow same-origin requests from the Web Shell." — the last remaining demo-page reference in the serve source.
R2-2 17-configuration.md gained a --web/--no-web CLI-flag row but the ServeOptions table (introduced as mirroring the CLI flags) had no serveWebShell row. Implemented Added the serveWebShell row after allowPrivateAuthBaseUrl (mirroring the CLI table order), with default/opt-out semantics verified against types.ts, serve.ts, fast-path.ts, and run-qwen-serve.ts.
R2-3 The deleted /demo suite pinned the browser-UI surface on a non-loopback bind; the successor "pre-auth in every launch mode" contract had no non-loopback test pin. Implemented Added serves the shell pre-auth on a non-loopback bind (every launch mode) to the Web Shell static serving describe: createServeApp({ hostname: '0.0.0.0', token: 'secret' }) + GET / with Accept: text/html → 200 and the shell body.
R2-4 12-auth-security.md Exception note claimed the strip middleware fires "when it matches the daemon's own address", but it only matches a hard-coded loopback-host set — over-broad for non-loopback binds. Implemented Rewrote the note: loopback-scoped, enumerates the four loopback self-origins, points at server/self-origin.ts (the defining module), and states that non-loopback binds need --allow-origin for the shell's XHRs — consistent with the sibling passages in qwen-serve-protocol.md and 20-quickstart-operations.md §8.
R2-5 02-serve-runtime.md caveat "the Web Shell works because another middleware strips matching same-origin values first" over-broad for non-loopback binds. Implemented Scoped the caveat to the loopback Web Shell and added the --allow-origin requirement for non-loopback binds (suggested text applied).
R2-6 20-quickstart-operations.md recipe 3 said probes must carry the token "like every other route" — false, because the Web Shell entry points stay pre-auth even under --require-auth. Implemented Now reads "like every other API route" and notes the Web Shell static surface stays pre-auth by design, with --no-web for an API-only daemon (suggested text applied).
R2-7 qwen-serve-protocol.md * bullet enumerated the token-less loopback exposure as only /health, omitting the Web Shell static assets that stay pre-auth even under --require-auth. Implemented Added the loopback mirror of the non-loopback sentence: even with --require-auth the Web Shell static assets remain pre-auth by design and readable from any cross-origin browser under *; --no-web removes that surface.

Verification notes: the middleware behavior claims (R2-4/R2-5/R2-7) were checked against server/self-origin.ts (hard-coded loopback origin set, independent of bind address) and the server.ts mount order (mountWebShellAssets before bearerAuth, gated only by serveWebShell !== false). The two "like every other route" occurrences in qwen-serve-protocol.md:15, 12-auth-security.md:153, and users/qwen-serve.md:328 are pre-existing (blame: May/June commits, not this PR) and about /health gating specifically, so they were left untouched as out of scope.

Verification

Commands actually run, in order:

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • cd packages/cli && npx vitest run src/serve/server.test.ts — 903 tests passed (1 file), including the new non-loopback pre-auth test and the existing loopback self-origin shim test
  • cd packages/cli && npx vitest run src/serve/server.test.ts -t "pre-auth on a non-loopback" — 1 passed, 902 skipped (new test in isolation)
  • npm run generate:settings-schema — not required: no settings source was changed (only docs, one test file, and one source comment)
  • Integration tests after npm run bundle — not required: no behavior exercised only through the bundled CLI was touched; the new test runs against createServeApp in the same harness as its siblings
中文说明

Autofix 审查轮次总结 — PR #8805

自动审查者提出的全部 7 条建议级发现均已对照代码核实,并在一次提交(32378600e4)中实现。没有拒绝任何发现。--conflictfalse,未执行合并。

# 发现 处理 改动
R2-1 installSelfOriginStripMiddleware 的模块头注释仍写着 "Allow same-origin requests from the demo page."。 已实现 server/self-origin.ts 头注释改为 "Allow same-origin requests from the Web Shell." —— serve 源码中最后一处 demo 页面残留引用。
R2-2 17-configuration.md 新增了 --web/--no-web CLI 参数行,但(声明与 CLI 参数镜像的)ServeOptions 表缺少 serveWebShell 行。 已实现 allowPrivateAuthBaseUrl 之后(与 CLI 表顺序一致)补上 serveWebShell 行,默认值/关闭语义已对照 types.tsserve.tsfast-path.tsrun-qwen-serve.ts 核实。
R2-3 被删除的 /demo 测试套件曾固定非 loopback 绑定下的浏览器 UI 面;继承契约 "所有启动模式下 pre-auth" 缺少非 loopback 测试固定。 已实现 Web Shell static serving describe 中新增 serves the shell pre-auth on a non-loopback bind (every launch mode):createServeApp({ hostname: '0.0.0.0', token: 'secret' }) + 以 Accept: text/html 请求 GET / → 断言 200 且返回 shell 主体。
R2-4 12-auth-security.md 的 Exception 注释声称剥离中间件在 "与 daemon 自身地址匹配时" 生效,但它实际只匹配硬编码的 loopback 主机集合 —— 对非 loopback 绑定过宽。 已实现 重写该注释:限定为 loopback 场景,列出四个 loopback self-origin,指向 server/self-origin.ts(定义模块),并说明非 loopback 绑定下 shell 的 XHR 需要 --allow-origin —— 与 qwen-serve-protocol.md20-quickstart-operations.md §8 的兄弟段落保持一致。
R2-5 02-serve-runtime.md 中 "the Web Shell works because another middleware strips matching same-origin values first" 对非 loopback 绑定过宽。 已实现 将该注意事项限定为 loopback Web Shell,并补充非 loopback 绑定需要 --allow-origin(采用建议文本)。
R2-6 20-quickstart-operations.md 配方 3 称探针须 "like every other route" 携带 token —— 不成立,因为即使在 --require-auth 下 Web Shell 入口仍然 pre-auth。 已实现 改为 "like every other API route",并注明 Web Shell 静态面按设计保持 pre-auth、--no-web 可得到纯 API daemon(采用建议文本)。
R2-7 qwen-serve-protocol.md* 条目把 loopback 下的无 token 暴露面只列为 /health,遗漏了即使带 --require-auth 仍然 pre-auth 的 Web Shell 静态资源。 已实现 补上与非 loopback 句对应的说明:即使带 --require-auth,Web Shell 静态资源按设计仍是 pre-auth,在 * 下仍可被任意跨源浏览器读取;--no-web 可移除该暴露面。

核实说明:中间件行为相关的论断(R2-4/R2-5/R2-7)已对照 server/self-origin.ts(硬编码 loopback origin 集合,与绑定地址无关)和 server.ts 的挂载顺序(mountWebShellAssets 位于 bearerAuth 之前,仅受 serveWebShell !== false 约束)核实。qwen-serve-protocol.md:1512-auth-security.md:153users/qwen-serve.md:328 中另外几处 "like every other route" 属于既有内容(blame:五/六月的提交,非本 PR),且专门描述 /health 的鉴权,故保持不动,不在本次范围内。

验证

实际执行的命令,按顺序:

  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0)
  • cd packages/cli && npx vitest run src/serve/server.test.ts — 903 个测试全部通过(1 个文件),包括新增的非 loopback pre-auth 测试和既有的 loopback self-origin shim 测试
  • cd packages/cli && npx vitest run src/serve/server.test.ts -t "pre-auth on a non-loopback" — 1 通过,902 跳过(单独运行新测试)
  • npm run generate:settings-schema — 无需执行:未改动任何 settings 源(仅文档、一个测试文件、一处源码注释)
  • npm run bundle 后的集成测试 — 无需执行:未触及只能经 bundled CLI 验证的行为;新测试与同组测试一样直接基于 createServeApp 运行

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally. Test Plan (not a blocker): 4221 passed — this review observed 18735 passed.

中文说明

已审查。 建议见行内评论。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。 Test Plan(非阻断):4221 passed — this review observed 18735 passed

— qwen3.8-max via Qwen Code /review (v0.21.8)

- **`--require-auth` shadows feature preflight.** Unauthenticated clients cannot discover the `require_auth` tag; their discovery surface is the 401 body itself.
- **Mutation gate body-parser ordering**: `mutationGate({strict: true})` 401 responses fire **after** `express.json()` parses the body. Worst case on a saturated loopback listener: `--max-connections × express.json({limit: '10mb'})` ≈ 2.5 GB transient. Loopback-only attack surface, intentionally accepted.
- **Same-origin Origin stripping** in `server.ts` happens _before_ `denyBrowserOriginCors`. If a future change moves the strip elsewhere, the demo page breaks.
- **Same-origin Origin stripping** in `server.ts` happens _before_ `denyBrowserOriginCors`. If a future change moves the strip elsewhere, the Web Shell breaks.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-1: Contradictory file attribution for the self-origin strip middleware, introduced by this diff. The exception paragraph this PR rewrites (line 103 of this file) now correctly attributes the middleware to server/self-origin.ts, but this caveat line — edited in the same commit (the demo page breaksthe Web Shell breaks) — still says the stripping happens "in server.ts". The entire middleware lives in packages/cli/src/serve/server/self-origin.ts; server.ts retains only the one-line install call installSelfOriginStripMiddleware(app, getPort) (line 1036). — Failure scenario: a maintainer heeding this caveat — whose whole purpose is to warn where the ordering must be guarded — goes to server.ts to inspect or relocate the strip and no longer finds the strip logic there; in the security doc that gates the browser-origin wall, the pointer to the guard now points at the wrong file.

Suggested change
- **Same-origin Origin stripping** in `server.ts` happens _before_ `denyBrowserOriginCors`. If a future change moves the strip elsewhere, the Web Shell breaks.
- **Same-origin Origin stripping** (implemented in `server/self-origin.ts`, installed from `server.ts`) happens _before_ `denyBrowserOriginCors`. If a future change moves the strip elsewhere, the Web Shell breaks.
中文说明

本次 diff 引入了 self-origin strip 中间件在文件归属上的自相矛盾。本 PR 重写的例外段落(本文件第 103 行)已正确地把该中间件归于 server/self-origin.ts,但这条注意事项——同一次提交里刚被编辑过(the demo page breaksthe Web Shell breaks)——仍然说 stripping 发生在 "in server.ts"。整个中间件都在 packages/cli/src/serve/server/self-origin.ts,server.ts 里只剩一行安装调用 installSelfOriginStripMiddleware(app, getPort)(第 1036 行)。 — 触发场景:维护者看到这条注意事项(它的全部作用就是警示这个顺序必须在哪里被守护)后去 server.ts 检查或移动 strip,却再也找不到 strip 逻辑——这份为浏览器同源墙把关的安全文档,把守护者指向了错误的文件。

— qwen3.8-max via Qwen Code /review (v0.21.8)

| `externalToolGuard` | Optional `{mode:'required', endpoint, token, timeoutMs?}`. Omission is fully off; required mode performs the provider handshake before listening. |
| `allowOrigins` | Cross-origin allowlist (`string[]`), corresponding to `--allow-origin`. |
| `allowPrivateAuthBaseUrl` | Allows private / localhost auth provider `baseUrl` installation. |
| `serveWebShell` | Serve the built Web Shell SPA at the daemon root (default `true`); `false` (the CLI's `--no-web`) leaves the daemon API-only. No effect when the build omits the shell assets. |

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-2: The new serveWebShell row's last sentence — "No effect when the build omits the shell assets." — is contradicted by runtime behavior: run-qwen-serve.ts:2919-2924 writes the missing-assets boot warning only inside if (opts.serveWebShell !== false), so serveWebShell=false (the CLI's --no-web) observably silences the per-boot warning — an effect in exactly the situation the row calls "No effect". — Failure scenario: in a build without Web Shell assets every boot prints "Web Shell assets not found; serving API only. … pass --no-web to silence this."; an operator trusting this doc line never tries the documented silencing path — the daemon's own warning tells them to use --no-web for a situation the doc says the flag cannot change. (The identical wording pre-exists in types.ts's JSDoc — fixing both keeps them consistent.)

Suggested change
| `serveWebShell` | Serve the built Web Shell SPA at the daemon root (default `true`); `false` (the CLI's `--no-web`) leaves the daemon API-only. No effect when the build omits the shell assets. |
| `serveWebShell` | Serve the built Web Shell SPA at the daemon root (default `true`); `false` (the CLI's `--no-web`) leaves the daemon API-only. No effect on what is served when the build omits the shell assets; `false` additionally silences the missing-assets boot warning. |
中文说明

新增的 serveWebShell 行最后一句 — "No effect when the build omits the shell assets." — 与运行时行为矛盾:run-qwen-serve.ts:2919-2924 只在 if (opts.serveWebShell !== false) 内部输出缺少资产的启动警告,所以 serveWebShell=false(即 CLI 的 --no-web)会实实在在地让每次启动的警告消失 — 正是在这行文字说 "No effect" 的场景里有效果。 — 触发场景:在没有 Web Shell 资产的构建里,每次启动都会打印 "Web Shell assets not found; serving API only. … pass --no-web to silence this.";信任这行文档的运维者永远不会去试文档所说的消声途径 — daemon 自己的警告都在告诉他们对这个场景用 --no-web,而文档却说这个 flag 改变不了任何东西。(同样的措辞也早已存在于 types.ts 的 JSDoc — 两处一起改才能保持一致。)

— qwen3.8-max via Qwen Code /review (v0.21.8)

## 8. Is there a browser UI?

**Yes.** It is implemented by `getDemoHtml(port)` in `packages/cli/src/serve/demo.ts` as self-contained HTML with no external dependency.
**Yes — the Web Shell.** `resolveWebShellDir()` finds the built assets (bundled next to the CLI bundle in a release, `packages/web-shell/dist` in a checkout) and `mountWebShellAssets()` serves them at `/`, `/assets`, and `/session/:id` document navigations (browser deep links — a plain `curl /session/<id>` gets the API's 401/404, not the shell). When the assets are missing the daemon degrades to API-only instead of crashing; `--no-web` opts out explicitly.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-4: This diff adds guidance referencing --open (§1) and --no-web (§1, §2, §8) to this file, but the file's own section 3 "Full startup flags" table has no --web/--no-web row and no --open row, while docs/users/qwen-serve.md documents both (both flags pre-date this PR at commands/serve.ts:328-334). The omission predates the diff, but the new references are what make the file internally inconsistent. — Failure scenario: a reader following the new §1 instruction "start the daemon with --open (which puts the token in the URL fragment…)" turns to §3 — the self-described complete flag reference — for the flag's default or its interaction with --require-auth, and finds nothing, while far less central flags are listed; the reader concludes the guidance references a flag that doesn't exist or must hunt in a different document for basic semantics. Suggested fix: add --web/--no-web and --open rows to the §3 table mirroring the entries in docs/users/qwen-serve.md (this PR is the demo→Web Shell doc sweep, so this is the natural time).

中文说明

这个 diff 在本文件里新增了引用 --open(§1)和 --no-web(§1、§2、§8)的指引,但本文件自己的第 3 节 "Full startup flags" 表格既没有 --web/--no-web 行,也没有 --open 行,而 docs/users/qwen-serve.md 对两者都有记载(两个 flag 都早于本 PR,见 commands/serve.ts:328-334)。遗漏本身早于本 diff,但正是这些新引用让文件内部自相矛盾。 — 触发场景:读者按照新的 §1 指引 "start the daemon with --open(which puts the token in the URL fragment…)" 操作,然后翻到 §3 — 自称完整的 flag 参考 — 查这个 flag 的默认值或它与 --require-auth 的相互作用,却什么都找不到,而远不如它核心的 flag 反而都在表里;读者要么以为指引引用了一个不存在的 flag,要么得去别的文档里找基本语义。建议修复:给 §3 表格补上 --web/--no-web--open 行,与 docs/users/qwen-serve.md 的条目保持一致(本 PR 正是 demo→Web Shell 的文档清扫,顺手补上正合适)。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Comment on lines +318 to +319
scoped.middleware(mockReq({ method: 'GET', path }), mockRes(), next);
scoped.middleware(mockReq({ method: 'GET', path }), res, vi.fn());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-5: The new pinning test's comment claims it "Pins the shape of the GET/HEAD exemption", but the loop only sends method: 'GET' — no HEAD request is exercised anywhere in this file (grep-verified; the only "HEAD" hits are the word "header"). The exemption it pins is (method === 'GET' || method === 'HEAD') && p === '/health' (rate-limit.ts:75). — Failure scenario: a future widening that applies to HEAD only — e.g. a new if (method === 'HEAD' && p === '/some-page') return null; branch, or splitting the predicate — lets an unauthenticated route escape the rate limiter (unlimited pre-auth HEAD traffic bypasses the DoS mitigation) while this test, which advertises itself as the guard against exactly that widening, stays green. Suggested fix (spans the loop declaration and these lines): run the same per-path loop over both methods, or narrow the comment to "GET exemption" if HEAD coverage is deliberately out of scope.

for (const method of ['GET', 'HEAD'] as const) {
  for (const path of ['/demo', '/health/deep', '/healthz', '/']) {
    // ... same fresh-limiter-per-call setup and 429 assertions,
    // with mockReq({ method, path })
  }
}
中文说明

新增的固定测试的注释声称它 "Pins the shape of the GET/HEAD exemption",但循环只发送 method: 'GET' — 整个文件里没有任何 HEAD 请求被演练过(grep 验证;仅有的 "HEAD" 命中是 "header" 这个单词)。它固定的豁免条件是 (method === 'GET' || method === 'HEAD') && p === '/health'(rate-limit.ts:75)。 — 触发场景:未来一次只对 HEAD 生效的放宽 — 比如新增 if (method === 'HEAD' && p === '/some-page') return null; 分支,或把谓词拆开 — 会让一个未认证路由逃过限流(无限量的 pre-auth HEAD 流量绕过 DoS 缓解),而这个自称正是守护这种放宽的测试却一路绿灯。建议修复(跨循环声明与这两行):对 ['GET', 'HEAD'] 两种方法各跑一遍同样的每路径循环;或者,如果 HEAD 覆盖有意不在范围内,就把注释收窄为 "GET exemption"。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Comment on lines +3406 to +3408
it('serves the shell pre-auth on a non-loopback bind (every launch mode)', async () => {
// Re-pins the non-loopback half of the deleted `/demo` suite: the
// shell is pre-auth in every launch mode. The old `/demo` registered

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-6: This test's comment claims to pin "the shell is pre-auth in every launch mode … this fails first", but it exercises only one mode (hostname: '0.0.0.0', token: 'secret'); the requireAuth: true mode is unpinned here and — exhaustively grep-verified across all packages/cli test files — nowhere else. The behavior is explicitly documented by this PR (qwen-serve-protocol.md:23: "--require-auth still leaves the Web Shell static assets … pre-auth … by design"). — Failure scenario (probe-proven): gating mountWebShellAssets on opts.requireAuth !== true makes the filtered Web Shell suite pass 31/31 with zero failures — a future change that 401s address-bar navigations (which cannot attach the Authorization header) on exactly the hardened --require-auth deployments ships green. A comparator arm (gate on !opts.token) failed 5 tests, so the harness catches gating regressions in covered modes only. Suggested fix: extend this test (or add a sibling) to cover { hostname: '0.0.0.0', token: 'secret', requireAuth: true } and the loopback requireAuth: true case, asserting GET / with Accept: text/html still returns 200 + shell; or narrow the comment to the mode actually tested.

中文说明

这个测试的注释声称固定了 "the shell is pre-auth in every launch mode … this fails first",但它只演练了一种模式(hostname: '0.0.0.0', token: 'secret');requireAuth: true 模式在这里没有被固定,而且经过对 packages/cli 全部测试文件的穷尽 grep 验证,别处也没有。该行为被本 PR 明确写入文档(qwen-serve-protocol.md:23:"--require-auth still leaves the Web Shell static assets … pre-auth … by design")。 — 触发场景(已用探针证实):把 mountWebShellAssetsopts.requireAuth !== true 门控起来,过滤后的 Web Shell 测试套件以 31/31 全绿通过 — 未来若有改动让地址栏导航(无法附带 Authorization 头)在恰好是加固过的 --require-auth 部署上返回 401,它会在一片绿灯中上线。对照臂(用 !opts.token 门控)失败了 5 个测试,说明这套测试能抓住被覆盖模式下的门控回归,只是没盯住 requireAuth 模式。建议修复:给这个测试(或新增一个兄弟测试)补上 { hostname: '0.0.0.0', token: 'secret', requireAuth: true } 和 loopback requireAuth: true 两种情况,断言带 Accept: text/htmlGET / 仍返回 200 + shell;或者把注释收窄到实际测试的模式。

— qwen3.8-max via Qwen Code /review (v0.21.8)

**`--allow-origin <pattern>` (T2.4 [#4514](https://github.com/QwenLM/qwen-code/issues/4514)).** Browser webuis hitting the daemon cross-origin are blocked by default — any request carrying an `Origin` header returns `403 {"error":"Request denied by CORS policy"}` because CLI/SDK clients never send `Origin` and the daemon treats its presence as a sign the request came from a browser context the operator has not opted into. Pass `--allow-origin <pattern>` (repeatable) at boot to install an allowlist instead of the wall. Each pattern is either:

- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` and `/demo` are also gated by the bearer — they're registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach `/health` without a token), and a `*` allowlist makes them reachable from any cross-origin browser. On non-loopback binds the bearer is already mandatory at boot, so the `*` exposure surface is just `/health` (status JSON) and `/demo` (a static page whose JS still calls token-gated routes) — the actual API surface is gated regardless.
- The literal `*` — admit any origin. **Risky**: boot refuses when `*` is configured but no bearer token is set (any source: `--token`, `QWEN_SERVER_TOKEN`, or `--require-auth` which mandates a token at boot). The boot breadcrumb emits a stderr warning when `*` is in the list. **Recommendation**: pair with `--require-auth` on loopback binds so `/health` is also gated by the bearer — it's registered before the bearer middleware on loopback by default (so k8s/Compose probes can reach it without a token), and a `*` allowlist makes it reachable from any cross-origin browser. `--require-auth` still leaves the Web Shell static assets (`/`, `/assets/*`, and `/session/:id` document navigations) pre-auth on loopback by design — they are mounted before the bearer middleware — so under a `*` allowlist they remain readable from any cross-origin browser; `--no-web` removes that surface. On non-loopback binds the bearer is already mandatory at boot and `/health` is registered behind it, so the only surface `*` exposes without a token is the Web Shell static assets (`/`, `/assets/*`, and `/session/:id` document navigations — their JS still calls token-gated routes). `--no-web` removes even that; the actual API surface is gated regardless.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-7: This rewrite documents that the Web Shell entry points stay pre-auth even under --require-auth, but leaves the same section's two auth-surface definitions stale — line 7 ("every route except /health on loopback binds" must carry the bearer) and line 19 ("When the flag is on, the global bearerAuth middleware gates every route — including /capabilities"). Probe-verified at the reviewed commit: under loopback --require-auth, GET /, /assets/*, and /session/:id document navigations answer 200 pre-auth while /health//capabilities answer 401 — so the absolute claims are false in exactly the modes they quantify over, and this section now contradicts itself four lines apart. Note: the factual staleness predates this PR (the unconditional pre-auth mount landed with the Web Shell), but this diff's rewrite introduces the explicit contradiction — pre-PR, no sentence in this section predicated pre-auth-ness of --require-auth mode. (Same pattern as the rewritten CORS bullet in docs/users/qwen-serve.md — see the sibling comment.) — Failure scenario: an SDK/integration author or security reviewer deriving the token-required surface of a hardened daemon from this reference trusts "every route", deploys --require-auth, and concludes no unauthenticated surface remains — never considering --no-web; meanwhile GET / answers 200 without a token in exactly that mode. Or a maintainer reconciling the contradiction "fixes" the server to match the absolute promise and breaks browser address-bar navigations on exactly the hardened deployments this bullet promises stay pre-auth. Suggested fix: scope the quantifiers on lines 7/19 to API routes and name the exception, e.g. line 7 "every API route except /health on loopback binds (the Web Shell static assets are the other pre-auth exception — see below)".

中文说明

这次重写把 Web Shell 入口点在 --require-auth 下仍然 pre-auth 写进了文档,却让同一节里两处认证面定义保持陈旧:第 7 行("every route except /health on loopback binds" 必须携带 bearer)和第 19 行("When the flag is on, the global bearerAuth middleware gates every route — including /capabilities")。已在被审提交上用探针验证:loopback --require-auth 下,GET //assets/*/session/:id 文档导航以 200 pre-auth 返回,而 /health//capabilities 返回 401 — 这些绝对化表述在它们所量化的模式里恰好是假的,本节如今在相隔四行之内自相矛盾。说明:事实层面的陈旧早于本 PR(无条件 pre-auth 挂载是随 Web Shell 一起引入的),但正是本 diff 的重写引入了显式矛盾 — PR 之前本节没有任何一句话声称过 --require-auth 模式下的 pre-auth 属性。(与 docs/users/qwen-serve.md 里重写的 CORS 条目是同一模式 — 见姊妹评论。) — 触发场景:SDK/集成作者或安全评审从这份参考推导加固 daemon 需要 token 的面,相信 "every route",部署 --require-auth,断定不再存在未认证面 — 从不考虑 --no-web;而 GET / 在该模式下恰好无需 token 就返回 200。或者维护者为消除矛盾把服务器 "修" 成符合绝对化表述,恰好在本条目承诺保持 pre-auth 的加固部署里弄坏了浏览器地址栏导航。建议修复:把第 7/19 行的量词收窄到 API 路由并点名例外,例如第 7 行改为 "every API route except /health on loopback binds (the Web Shell static assets are the other pre-auth exception — see below)"。

— qwen3.8-max via Qwen Code /review (v0.21.8)

Comment thread docs/users/qwen-serve.md
- **`LOOPBACK_BINDS` includes IPv6** — `::1` and `[::1]` count as loopback for the no-token rule.
- **Host header allowlist** — on **loopback** binds the daemon checks `Host:` matches `localhost:port` / `127.0.0.1:port` / `[::1]:port` / `host.docker.internal:port` (case-insensitive per RFC 7230 §5.4) to defend against DNS rebinding. **Non-loopback binds (`--hostname 0.0.0.0`) intentionally bypass the Host allowlist** — the operator has chosen the surface area, so the bearer-token gate is the sole authentication layer; reverse proxies / SNI / client cert pinning are the operator's responsibility, not the daemon's. If you need Host-based isolation on a non-loopback bind, terminate TLS + check Host at a front proxy.
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` and `/demo` remain pre-auth on loopback by default) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the `/demo` page) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.
- **CORS denies any browser Origin by default** — returns `403` JSON. Pass **`--allow-origin <pattern>`** (repeatable, T2.4 #4514) to opt specific browser origins through. Each value is either the literal `*` (any origin — boot refuses if no bearer token is configured; `--require-auth` on loopback is recommended for full hardening since `/health` remains pre-auth on loopback by default — note that the Web Shell static assets (`/`, `/assets/*`, `/session/:id` document navigations) are mounted before the bearer in every mode and stay pre-auth even under `--require-auth`, so use `--no-web` when the residual browser surface matters) or a canonical URL origin (`<scheme>://<host>[:<port>]`, no trailing slash / path / userinfo). Matched origins receive proper CORS response headers (`Access-Control-Allow-Origin: <echoed>`, `Vary: Origin`, plus standard methods / headers / max-age and exposed `Retry-After`); unmatched origins still get a 403 with the same envelope as the default wall. `caps.features.allow_origin` is advertised conditionally so SDK / webui clients can pre-flight whether the daemon honors cross-origin hits before issuing them. Example: `qwen serve --allow-origin http://localhost:3000 --allow-origin http://localhost:5173`. Loopback self-origin hits (e.g. the Web Shell UI) are unaffected — a separate Origin-strip shim handles them regardless of `--allow-origin`. **Browser webuis without `--allow-origin` configured** still fall back to the same Stage 1 options as before: package as a native shell (Electron/Tauri) so no `Origin` header is sent, or front the daemon with a same-origin reverse proxy.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-7: The rewritten bullet asserts the Web Shell stays pre-auth "even under --require-auth" — accurate — but that directly contradicts the same file's own Authentication section: line 330 ("Pass --require-auth to make the bearer token mandatory on every route") and line 328 (non-loopback /health "requires the token like every other route"). Probe-verified at the reviewed commit: under loopback --require-auth, GET /, /assets/*, /session/:id document navigations answer 200 pre-auth while /health//capabilities answer 401. Lines 328/330 were already false pre-PR (the Web Shell pre-auth mount predates this PR), but this diff's rewrite introduces the explicit intra-file contradiction — "stay pre-auth even under --require-auth" is text this PR adds, and it negates line 330's absolute promise in that flag's own mode. (Same pattern as qwen-serve-protocol.md lines 7/19 — see the sibling comment.) — Failure scenario: an operator hardening a daemon follows this file's Authentication section, deploys qwen serve --require-auth, trusts the absolute "mandatory on every route" promise and concludes no unauthenticated surface remains — never considering --no-web; meanwhile GET / answers 200 without a token in exactly that mode (as this bullet itself now states). Suggested fix: scope the absolutes to API routes and name the exception — e.g. line 330 "mandatory on every API route … (the Web Shell static surface stays pre-auth by design — pass --no-web to remove it)", line 328 "like every other API route".

中文说明

这条重写的条目断言 Web Shell "even under --require-auth" 仍然 pre-auth — 这没错 — 但它与本文件自己的 Authentication 一节直接矛盾:第 330 行("Pass --require-auth to make the bearer token mandatory on every route")和第 328 行(非 loopback 的 /health "requires the token like every other route")。已在被审提交上用探针验证:loopback --require-auth 下,GET //assets/*/session/:id 文档导航以 200 pre-auth 返回,而 /health//capabilities 返回 401。第 328/330 行在本 PR 之前就已经是假的(Web Shell 的 pre-auth 挂载早于本 PR),但正是本 diff 的重写引入了文件内的显式矛盾 — "stay pre-auth even under --require-auth" 是本 PR 新增的文字,它在这个 flag 自己的模式里否定了第 330 行的绝对化承诺。(与 qwen-serve-protocol.md 第 7/19 行是同一模式 — 见姊妹评论。) — 触发场景:运维者按本文件的 Authentication 一节加固 daemon,部署 qwen serve --require-auth,相信 "mandatory on every route" 的绝对化承诺,断定不再有未认证面 — 从不考虑 --no-web;而 GET / 在该模式下恰好无需 token 就返回 200(正如本条目自己所写)。建议修复:把绝对化表述收窄到 API 路由并点名例外 — 如第 330 行改为 "mandatory on every API route … (the Web Shell static surface stays pre-auth by design — pass --no-web to remove it)",第 328 行改为 "like every other API route"。

— qwen3.8-max via Qwen Code /review (v0.21.8)

…emo-page

# Conflicts:
#	docs/users/qwen-serve.md
@wenshao

wenshao commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /resolve

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 Addressed the latest review feedback (round 6/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 6/100 轮)。改动内容与我反驳保留之处如下:

Autofix address-review summary — PR #8805 (round 6)

Feedback triage

Critical-only mode is active after 5 change-producing rounds. All actionable sections this round were empty:

  • Reviews: none
  • Inline comments: none
  • Issue-level comments: none
  • Failed checks / still-red checks: none

The 7 deferred non-Critical items (1 review + 6 inline findings) were left untouched per the Critical-only rule: no code changes, no thread resolutions, no comment replies for them. They remain open for human follow-up.

Work done: base-conflict resolution (--conflict true)

Merged origin/main (15 commits ahead) into chore/remove-daemon-demo-page. Merge commit: b1b135b9dc.

Only two files were modified on both sides; everything else merged one-sided:

  1. docs/users/qwen-serve.md — manual resolution. The conflict was in the CLI-flags table. The PR side had rewritten the --allow-origin row (removing the deleted /demo page and re-scoping the pre-auth claim to the Web Shell static assets) and re-padded the widened table; main (fix(acp-bridge): bound live journal replay chunks #8801) had rewritten the --max-journal-events / --max-journal-bytes rows for the new chunk-bounded live-journal semantics. Resolution: kept the PR's table text and padding, and folded in main's two journal rows re-padded to the PR's wider column. Verified: differs from the PR head by exactly those two rows; contains main's journal wording verbatim; prettier-clean. The CORS bullet re-scope outside the table came through one-sided from the PR.
  2. docs/developers/qwen-serve-protocol.md — auto-merged. Verified both sides' changes are present (PR's demo-removal wording; main's journal-replay description), in disjoint regions.

A committer identity (qwen-code-dev-bot, matching this branch's earlier workflow commits) was configured repository-locally because the runner had none and git commit refused to run.

No code files were modified on both sides, so no behavioral interaction exists between the two branches; the merge only combines them.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check docs/users/qwen-serve.md — passed
  • npx vitest run in packages/acp-bridge — passed (exit 0)
  • npx vitest run in packages/sdk-typescript — passed (exit 0)
  • npx vitest run in packages/core (full) — first run in this runner's shell showed 84 failures; every cluster was proven to be runner-environment contamination, not merge breakage, via A/B runs: the workflow shell exports QWEN_HOME (breaking tests that assert os.homedir()-based default paths) and SANDBOX (breaking the "not in sandbox mode" editor tests), and the real home /home/github-runner is not writable by the node user (breaking tests that mkdir there when QWEN_HOME is unset). Re-run under a CI-equivalent environment (HOME set to a writable dir, QWEN_HOME/SANDBOX unset): 573 files / 19636 tests passed, 0 failed.
  • npx vitest run in packages/cli (full) — one failure in src/ui/auth/AuthDialog.test.tsx ("drives API key provider steps from endpoint options metadata"). Proven to be a runner artifact: the test is wrapped in itWhenTuiInputReliable, which skips whenever CI=true (always set in GitHub Actions) because piped-stdin escape sequences are unreliable; the test file and AuthDialog.tsx are byte-identical across the merge base, the PR head, and origin/main (same blob SHAs, no commits touching packages/cli/src/ui/auth/ on either side), so the merge cannot be implicated; the failure also reproduces under a fully stripped environment (env -i). With CI=true: 794 files / 18764 tests passed, 0 failed.
  • Integration tests after npm run bundle — not run: this round changed documentation only (conflict resolution), no code path was altered, and both sides' code merged without interaction; the merged tree is unit-verified above.

Conflict notes

  • Single content conflict (CLI-flags table in docs/users/qwen-serve.md), resolved by combining both sides' wording as described above; no side was taken blindly.
  • origin/main is now an ancestor of the branch head; working tree clean.
中文说明

Autofix address-review 摘要 — PR #8805(第 6 轮)

反馈分诊

在 5 个产生改动的轮次之后,当前处于仅处理 Critical 的模式。本轮所有可执行区域均为空:

  • Reviews(评审):无
  • Inline comments(行内评论):无
  • Issue-level comments(议题级评论):无
  • 失败检查 / 持续失败检查:无

7 个被延后的非 Critical 条目(1 个评审 + 6 条行内发现)按照 Critical-only 规则保持原样不动:不为它们修改代码、不解决话题、不写评论回复。它们保持开放,留待人工跟进。

已完成工作:基分支冲突解决(--conflict true

origin/main(领先 15 个提交)合并进 chore/remove-daemon-demo-page。合并提交:b1b135b9dc

只有两个文件在双方都被修改过;其余全部为单边合入:

  1. docs/users/qwen-serve.md — 手动解决。 冲突位于 CLI 参数表。PR 一侧重写了 --allow-origin 行(移除已删除的 /demo 页面,并将 pre-auth 表述重新限定到 Web Shell 静态资源),并重新加宽了表格填充;main(fix(acp-bridge): bound live journal replay chunks #8801)则为新的分块限制 live-journal 语义重写了 --max-journal-events / --max-journal-bytes 两行。解决方式:保留 PR 的表格文本与填充,并将 main 的这两行按 PR 更宽的列重新填充后并入。已验证:与 PR 头部相比恰好只差这两行;逐字包含 main 的 journal 表述;prettier 检查通过。表格外的 CORS 要点重新限定表述来自 PR 的单边改动,正常合入。
  2. docs/developers/qwen-serve-protocol.md — 自动合并。 已验证双方改动均在(PR 的 demo 移除措辞;main 的 journal 重放描述),且位于互不重叠的区域。

由于 runner 上没有配置提交者身份导致 git commit 拒绝执行,本仓库局部配置了提交者身份(qwen-code-dev-bot,与本分支早前的 workflow 提交一致)。

没有任何代码文件在双方同时被修改,因此两个分支之间不存在行为交互;本次合并只是将两者组合。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx prettier --check docs/users/qwen-serve.md — 通过
  • packages/acp-bridgenpx vitest run — 通过(exit 0)
  • packages/sdk-typescriptnpx vitest run — 通过(exit 0)
  • packages/corenpx vitest run(全量)— 首次在本 runner shell 中运行出现 84 个失败;通过 A/B 对照运行证明每个失败簇都是 runner 环境污染,而非合并破坏:workflow shell 导出了 QWEN_HOME(破坏断言基于 os.homedir() 默认路径的测试)和 SANDBOX(破坏 "not in sandbox mode" 的 editor 测试),且真实 home /home/github-runnernode 用户不可写(破坏在取消 QWEN_HOME 后需要在此 mkdir 的测试)。在 CI 等效环境(HOME 指向可写目录,取消 QWEN_HOME/SANDBOX)下重跑:573 个文件 / 19636 个测试通过,0 失败
  • packages/clinpx vitest run(全量)— src/ui/auth/AuthDialog.test.tsx 中 1 个失败("drives API key provider steps from endpoint options metadata")。证明为 runner 假象:该测试由 itWhenTuiInputReliable 包裹,凡 CI=true(GitHub Actions 恒为 true)即跳过,因为管道 stdin 的转义序列不可靠;测试文件与 AuthDialog.tsx 在合并基点、PR 头部与 origin/main 之间逐字节一致(blob SHA 相同,任一侧均无触及 packages/cli/src/ui/auth/ 的提交),因此与合并无关;在完全剥离环境(env -i)下同样复现。设置 CI=true 后:794 个文件 / 18764 个测试通过,0 失败
  • npm run bundle 之后的集成测试 — 未运行:本轮仅改动文档(冲突解决),未变更任何代码路径,双方代码无交互合入;合并后的树已通过上述单元级验证。

冲突说明

  • 唯一内容冲突(docs/users/qwen-serve.md 的 CLI 参数表),按上文所述合并双方措辞解决;未盲目取任何一侧。
  • origin/main 现为分支头部的祖先;工作树干净。

Deferred non-Critical feedback

Critical-only mode is active after 5 change-producing rounds. The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

完成 5 个产生改动的轮次后进入仅处理 Critical 的模式。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: conflicted with main — resolved in this push. · 与 main 有冲突——已在本次推送中解决。

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code did not run conflict resolution for this request.

PR #8805 does not currently have merge conflicts with main.

@jifeng jifeng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao

wenshao commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@wenshao
wenshao enabled auto-merge August 10, 2026 13:15
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 157 passed · 0 failed · 157 total

中文 — 判定:✅ 通过 · 可合入(agent 判定)

沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查

脚本断言:157 通过 · 0 失败 · 157 总计

Verification report

PR #8805 deep verification (round 2) — chore(serve): remove the /demo debug page

Verdict: merge-ready — 157 scripted assertions executed, 157 pass / 0 fail
(A/B matrix 143, mutation matrix 10, doc-claim probes 4).
Verified head OID: b1b135b9dc075101bba4bbf5a485501a6ecbf850 (merge ref 5017d71da3, base 77bd04bd61).

中文摘要
  • 结论:可合并(merge-ready)。这是第二轮验证(上一轮在 head d5526e28 判定 merge-ready)。此后分支新增 3 个提交:文档声明修正 + 重新钉住 pre-auth CORS 墙(5551616)、完成 demo 改名收尾并把 pre-auth shell 声明限定到 loopback(3237860)、以及一次带冲突(docs/users/qwen-serve.md)的 main 合并(b1b135b)。全部既有测量已在新 head 上重跑而非沿用旧报告。
  • A/B 结论:中心主张“/demo 已彻底移除”再次成立。真实 daemon 跨 7 种启动模式逐格对照(见 01-ab-base-matrix.png / 02-ab-head-matrix.png):base 侧 /demo 在各模式下仍返回调试页(含 loopback+token 的 warm 预鉴权暴露、限流豁免 200×5);head 侧同一路径非导航 404、浏览器导航落入 SPA 兜底(无 token 时 200 Web Shell,配置 token 后 401)、限流豁免收窄(404,404,429,429,429)。/health、限流豁免、CORS 墙、Web Shell 静态面预鉴权等所有不变量两臂一致。
  • 新增测试非空:5 个变异体(恢复 /demo 路由、放宽限流豁免、回退告警文案、把 shell 挂到 CORS 墙之前、以及一个既有行为的阳性对照)全部被对应测试杀死,5 个未变异对照全绿(见 03-mutation-matrix.png)。
  • 文档与运行时一致:重写后的文档声明(bearer 进入浏览器的方式、非 loopback 绑定下 shell 只读、/session/:id 仅限文档导航、自源 Origin 剥离仅限 loopback、中间件顺序)逐条用活体 daemon 或代码核对(见 04-doc-claim-probes.png)。main 对冲突文件的改动(--max-journal-events 新措辞)在合并结果中保留。
  • findings:无阻塞项、无新缺陷;3 条信息性说明见正文。
  • 未覆盖:见正文 “Not covered”。

Previous-round finding status

Round 1 (head d5526e28) returned merge-ready with no findings — two informational
notes only. Both re-measured at the new head:

# Previous item Severity Status at b1b135b9
1 tsc --noEmit clean on both arms in this container, although the description cites pre-existing errors (qrcode-terminal types, a stale session-service declaration) informational stands — re-ran on both arms at the new head: 0 errors on both (base arm needed the PR-untouched dist/ + per-package node_modules linked in, then compiled clean)
2 Suite count drift: description cites 4221 passed; round 1 measured 4242 / 1 skipped informational stands — re-measured 4244 passed / 2 skipped across 147 files; the delta keeps tracking merged-main additions, and the PR diff itself adds no .skip (grep = 0)

Round 1's "Not covered" items: per-commit attribution is still graph-limited (depth-2
graft), but the two delta commits are now reachable as objects and were individually
inspected (see Not covered); the rest carry over unchanged and are re-listed below.

Central claim + A/B (re-measured at the new head)

Central claim: /demo is fully removed — a non-navigation request 404s, a browser
navigation falls through to the SPA fallback (Web Shell) on a tokenless loopback daemon
and is refused with 401 once a token is configured; /health and its rate-limit
exemption are unchanged. Secondary claims: the rewritten --allow-origin '*' warning
enumerates the real pre-auth surface, and the CORS-wall contract the deleted demo test
carried is re-pinned on the shell root.

Booted a real qwen serve daemon per arm (TS source via the repo's own tsx runner,
so the only difference between arms is the PR diff) across 7 launch modes, probed over
real HTTP. Both arms assert against arm-specific expectation tables; a flip is an
expected difference, and every cell's expectation held. Witnesses:
evidence/01-ab-base-matrix.png (base arm, 73 assertions) and
evidence/02-ab-head-matrix.png (head arm, 70 assertions); raw log logs/01-matrix-full.out.

Cell Scenario BASE (77bd04bd) HEAD (b1b135b9) flip?
A1 tokenless loopback, GET /demo (JSON Accept) 200 demo HTML 404, no shell marker ✅ load-bearing
A2 tokenless loopback, GET /demo (browser nav) 200 demo + X-Frame-Options: DENY 200 SPA shell (<div id="root">) ✅ shape change
A3 tokenless loopback, GET /demo cross-origin 403 CORS wall 403 CORS wall unchanged (wall runs first on both)
A4 tokenless loopback, GET / cross-origin 403 wall 403 wall unchanged — the re-pinned CORS contract, live
A5–A8 /health, /health?deep=1 (workspaceCount), /, unknown path 200 ok / counters / shell / 404 identical unchanged
A9/A10 GET /session/<id> nav vs JSON 200 shell / 404 200 shell / 404 unchanged (doc-navigation qualifier)
B1/B2 loopback + token (warm runtime), /demo no auth (nav/json) 200 demo — pre-auth exposure 401 ✅ load-bearing
B3/B4 loopback + token, /demo with bearer (json/nav) 200 demo / demo 404 / 200 SPA shell
B5–B7 / no auth, /daemon/status no auth, /health no auth 200 shell / 401 / 200 identical unchanged
C1/C2 loopback + token + --require-auth, /health no/bearer 401 / 200 401 / 200 unchanged
C3/C4 /demo nav no auth / with bearer under --require-auth 401 / 200 demo 401 / 200 SPA shell
C5/C6 / and /assets/* no token under --require-auth 200 shell / 200 asset identical unchanged (static pre-auth even under --require-auth)
D1/D2 non-loopback (0.0.0.0) + token, /health no/bearer 401 / 200 401 / 200 unchanged
D3 non-loopback, GET / no token 200 shell 200 shell unchanged (static pre-auth on any bind)
D4/D5 non-loopback, /demo nav no auth / json with bearer 401 / 200 demo 401 / 404
D6 non-loopback, cross-origin POST /session/:id/prompt 403 CORS wall 403 CORS wall unchanged — doc §8 claim
D7 non-loopback, same POST without Origin, no auth 401 bearer 401 bearer unchanged (wall is Origin-keyed)
E1 --allow-origin '*' boot warning enumerates /health and /demo names Web Shell static assets, --no-web, /health, --require-auth; no /demo
E2 under *, cross-origin GET / 200 + ACAO echoes origin identical unchanged
RL1 --rate-limit --rate-limit-read 2 --require-auth, /health ×5 with bearer 200×5 200×5 unchanged (still exempt — here only the exemption list can save it, since --require-auth registers /health after bearerAuth)
RL2 same mode, /demo ×5 with bearer 200×5 (on the exemption list) 404,404,429,429,429 ✅ exemption narrowed
RL3 /health after the bucket burned 200 200 unchanged
F1–F3 --no-web: /, /demo nav, /health 404 / 200 demo / 200 404 / 404 / 200 ✅ demo gone even with the shell disabled

One base-side nuance worth naming (pre-existing, not caused by this PR): on
loopback+token the base's /demo pre-auth exposure is observable only on the warm
runtime app — a cold daemon's deferred gate 401s the unauthenticated request first
(because its exemption list covers only shell entry points). The matrix warms the
runtime with a bearer'd session lookup before the B1/B2 cells so the exposure the PR
removes is the one actually measured.

Delta-specific re-verification. The CORS re-pin test's contract was exercised live
(A4: cross-origin GET / → 403 {error: 'Request denied by CORS policy'} on both arms),
and the loopback-scoped self-origin claim of the rewritten security doc was probed live:
on a 0.0.0.0 bind a LAN origin's POST hits the wall (403) while a loopback origin is
stripped and passes to the bearer gate (401) — evidence/04-doc-claim-probes.png, 4/4.
A repo-wide /demo census at head (docs/ + packages/cli/src) found exactly one hit —
"source": "@scope/demo" in the protocol doc's channel-scope example, unrelated to the
page — so the rename sweep is complete. The conflict resolution in
docs/users/qwen-serve.md kept both sides: main's rewritten --max-journal-events
wording is present, the PR's pre-auth wording is present, the old journal wording and
every /demo reference are gone.

Corrections

None. No earlier round or bot comment misdescribed the code in a way that needs correcting.

Findings

None blocking; no defects found. Three informational notes:

  1. (Carried, re-measured) npx tsc --noEmit in packages/cli is clean on both
    arms
    in this container; the description's cited pre-existing errors did not
    reproduce here in round 1 and still do not. Both arms equally clean ⇒ the
    load-bearing fact (no new type errors) holds.
  2. (Carried, re-measured) The description's 4221 passed remains stale against
    4244 passed / 2 skipped measured here; the drift tracks merged main, and the PR
    diff adds no skips. Suite fully green.
  3. (New, context for the B cells) The cold/warm gating split on the base arm
    described above means the base's loopback pre-auth /demo exposure required a warm
    daemon; a cold one already 401d it via the deferred gate. This is pre-existing
    fast-path architecture on the base (the gate shipped via main, not this PR) and
    does not weaken the removal — head returns 401 in both states.

Not covered

  • Per-commit exercise remains graph-limited. The checkout is depth-2 and grafted
    (git rev-parse --is-shallow-repository = true); git merge-base --is-ancestor says
    none of the 7 commits in the snapshot is an ancestor of HEAD^2. The four commit
    objects are nonetheless present locally, so this round inspected the two delta commits'
    own diffs (git show 5551616, git show 32378600) and verified each of their claims
    against the merge head (test re-pins present, doc wording present, runtime behavior
    measured). The two older commits were verified in round 1 and their surface was
    re-measured in this round's aggregate A/B. Per-commit harness runs were not possible.
  • Repo-wide gates the PR's own CI already runs (full npm run build, repo-wide test
    suite, ESLint/Prettier, integration suites) — not re-run; targeted gates instead
    (vitest run src/serve on head: 147 files / 4244 pass / 2 skip / exit 0;
    tsc --noEmit both arms: clean).
  • Windows/Linux-specific paths — the loopback/0.0.0.0 behavior exercised here is the
    POSIX path; the author marked Windows/Linux untested locally.
  • Release-bundling claim (Web Shell shipped next to the CLI bundle) — not exercised;
    the A/B used each tree's packages/web-shell/dist (the PR-untouched head build,
    symlinked into the base tree, byte-identical by virtue of the PR's zero diff there).
  • ?deep=1 byte equality across arms — asserted 200 + workspaceCount key on both
    arms, not a counter-by-counter diff.
  • Real-browser rendering of the Web Shell — probes are HTTP-level; the shell's own JS
    behavior is out of this PR's diff (packages/web-shell untouched).

Methodology

Environment: Linux node v22.23.2 container, repo at the merge ref
(5017d71da3), npm ci + npm run build pre-run. A/B (01-daemon-matrix.mjs):
14 real daemons (7 launch modes × 2 arms) spawned via
node node_modules/tsx/dist/cli.mjs <tree>/packages/cli/index.ts serve … with isolated
$HOME and scratch workspaces; base arm from a git worktree of HEAD^1. Workspace-link
confound checked: import.meta.resolve('@qwen-code/qwen-code-core') from the base tree
resolves into the head tree (git diff HEAD^1..HEAD -- packages/core packages/web-shell
is empty, so identical content); the base tree additionally needed the PR-untouched
build artifacts it lacks (the git-ignored generated git-commit.ts copied; the
packages/web-shell/dist and remaining package dist/ + per-package node_modules
dirs symlinked from the head tree) — runtime startup fails without the generated file,
which surfaced as a 503 daemon_runtime_failed before being diagnosed. Harness
expectations were corrected three times during development (warm-vs-cold gate for the
base B cells, --rate-limit master switch + bearer for the RL cells, ACAO origin-echo
under *) — all three were harness-hypothesis errors proven against the code, not PR
behavior; the final tables encode the corrected expectations and passed 143/143. The
mutation matrix ran in a scratch HEAD worktree (02-mutation-matrix.mjs, restored
clean afterwards: git status empty for packages/cli/src). Doc claims were checked by
grep against the rewritten files and by the live probes above. Raw logs:
logs/01-matrix-full.out, logs/02-mutation-full.out,
logs/03-gate-vitest-src-serve-head.log, logs/04-doc-claim-probes.out.

Evidence images

01-ab-base-matrix

02-ab-head-matrix

03-mutation-matrix

04-doc-claim-probes

Harness scripts and raw logs are in the workflow run artifacts (7-day retention).

Qwen Code · sandboxed verification

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed. Suggestions are inline. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

中文说明

已审查。 建议见行内评论。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

— qwen3.8-max via Qwen Code /review (v0.21.8)

```

Open `http://127.0.0.1:4170/demo` in a browser to see the debug console: chat UI, event stream, and workspace inspection. In the default loopback dev mode, `createServeApp()` mounts the `/demo` route from `packages/cli/src/serve/routes/health-demo.ts` **before** `bearerAuth`, so no token is required.
Open `http://127.0.0.1:4170/` in a browser to get the Web Shell UI: chat, session list, and workspace inspection. `createServeApp()` mounts the bundled Web Shell assets (`packages/cli/src/serve/web-shell-static.ts`) **before** `bearerAuth`, so the shell itself loads without a token; its own API calls carry the bearer when one is configured — start the daemon with `--open` (which puts the token in the URL fragment, never sent to the server) or append `#token=…` manually when auth is enabled. `--no-web` opts out and leaves the daemon API-only.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-4: This diff adds guidance referencing --open (§1) and --no-web (§1, §2, §8) to this file, but the file's own section 3 "Full startup flags" table has no --web/--no-web row and no --open row. Before this PR the page never mentioned these flags, so every flag its prose referenced was covered by the table until this diff newly breaks that in-file correspondence; --open in particular is documented nowhere in the developer docs. — Failure scenario: an operator following the quickstart consults the same page's "Full startup flags" table to confirm --open semantics and finds no entry, having to read CLI source (packages/cli/src/commands/serve.ts:334) instead.

Suggested fix: add --open and --web/--no-web rows to the section 3 table using the CLI descriptions from commands/serve.ts:328-339 (02-serve-runtime.md already has a --web/--no-web row to mirror).

中文说明

本 diff 在这个文件中新增了引用 --open(§1)和 --no-web(§1、§2、§8)的指引,但本文件自己的第 3 节 "Full startup flags" 表格里既没有 --web/--no-web 行,也没有 --open 行。在本 PR 之前该页面从未提及这些 flag,所以正文引用的每个 flag 都能在表格里找到,直到本 diff 新打破了这一文件内对应关系;尤其是 --open 在开发者文档中完全没有记载。——触发场景:按 quickstart 操作的运维者到同一页的 "Full startup flags" 表格确认 --open 的语义,却找不到对应条目,只能去读 CLI 源码(packages/cli/src/commands/serve.ts:334)。

建议修复:用 commands/serve.ts:328-339 中的 CLI 描述,在第 3 节表格里补上 --open--web/--no-web 行(02-serve-runtime.md 里已有可参照的 --web/--no-web 行)。

— qwen3.8-max via Qwen Code /review (v0.21.8)

| Loopback without `--require-auth` | `routes/health-demo.ts`, mounted by `createServeApp()` **before** `bearerAuth` | Works without token |
| Loopback with `--require-auth` | `routes/health-demo.ts`, mounted by `createServeApp()` **after** `bearerAuth` | Difficult to use from a plain browser; use curl or SDK |
| Non-loopback bind | `routes/health-demo.ts`, mounted by `createServeApp()` **after** `bearerAuth` | Same as above |
The static shell is mounted **before** `bearerAuth` in every launch mode — a browser cannot attach an `Authorization` header to an address-bar navigation or a `<script src>` subresource, so gating it would just break the UI. Every API route it calls stays token-gated, and the front end attaches the bearer itself. On a non-loopback bind the shell is read-only unless `--allow-origin <origin>` is passed — same-origin POSTs carry an `Origin` header that the CORS wall rejects (403) — so pass `--allow-origin` for any bind beyond loopback.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R4-1: The §8 rewrite adds the absolute claim "Every API route it calls stays token-gated", but in the loopback developer default (no token, no --require-auth) bearerAuth (packages/cli/src/serve/auth.ts:272) returns a pass-through middleware, so there is no token gate at all in the most common launch mode. Even with a token configured, /health stays pre-auth on loopback unless --require-auth is set (exposeHealthPreAuth = loopback && !opts.requireAuth, routes/health.ts:160; deliberately pinned by server.test.ts "exempts /health from bearer auth so liveness probes work without credentials"). — Failure scenario: a reader auditing whether pre-auth shell mounting weakens API auth gets a blanket guarantee the code does not provide.

Suggested fix: qualify the clause — "every API route it calls still passes through bearerAuth (open only in the loopback developer default without --require-auth; /health additionally stays pre-auth on loopback unless --require-auth is set)". The same phrasing is added by this diff at 02-serve-runtime.md:52 (subsystems table) and 17-configuration.md:35 (--web flag row), and also appears at docs/users/qwen-serve.md:415 — worth fixing together.

中文说明

§8 的重写新增了绝对化表述 "Every API route it calls stays token-gated",但在 loopback 开发者默认模式(无 token、无 --require-auth)下,bearerAuth(packages/cli/src/serve/auth.ts:272)返回的是直通中间件,即最常见的启动模式下根本没有 token 门槛。即使配置了 token,只要未设置 --require-auth,/health 在 loopback 上仍是 pre-auth(exposeHealthPreAuth = loopback && !opts.requireAuth,routes/health.ts:160;server.test.ts 的 "exempts /health from bearer auth so liveness probes work without credentials" 专门钉住了该行为)。——触发场景:评审者评估 pre-auth 挂载 shell 是否削弱 API 认证时,会得到代码并未提供的绝对保证。

建议修复:收窄该句——"every API route it calls still passes through bearerAuth(open only in the loopback developer default without --require-auth;/health additionally stays pre-auth on loopback unless --require-auth is set)"。同样的措辞在本 diff 中还出现在 02-serve-runtime.md:52(subsystems 表)与 17-configuration.md:35(--web flag 行),另见 docs/users/qwen-serve.md:415——建议一并修改。

— qwen3.8-max via Qwen Code /review (v0.21.8)

next,
);
it('exempts no GET path other than /health', () => {
// Pins the shape of the GET/HEAD exemption after `/demo` was removed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Suggestion] R3-5: The new pinning test's comment claims it "Pins the shape of the GET/HEAD exemption" after /demo was removed from it, but the loop only sends method: 'GET' — no HEAD request is exercised anywhere in this file (grep-verified: the only "HEAD" hits are setHeader/Retry-After header). The implementation exempts GET and HEAD alike (resolveTier in rate-limit.ts), so the HEAD half of the claimed contract is unpinned. — Failure scenario: a future change dropping HEAD from the exemption predicate (or splitting its tier) leaves every test green while HEAD probes against /health start consuming read tokens and 429ing on hardened deploys — the exact regression the comment says this test exists to catch.

Suggested fix: either exercise each path with both GET and HEAD in the loop, or narrow the comment to the GET exemption it actually pins:

// Pins the shape of the GET exemption after `/demo` was removed
中文说明

新增钉住测试的注释声称它 "Pins the shape of the GET/HEAD exemption"(在 /demo 被移出豁免之后),但循环只发送 method: 'GET'——整个文件没有任何 HEAD 请求被执行(grep 验证:仅有的 "HEAD" 命中是 setHeader/Retry-After header)。实现对 GET 和 HEAD 一视同仁地豁免(rate-limit.tsresolveTier),因此所声称契约中 HEAD 的一半并没有被钉住。——触发场景:未来某个改动把 HEAD 从豁免谓词里去掉(或拆分它的 tier)时,所有测试仍是绿的,而针对 /health 的 HEAD 探测开始消耗 read 配额、在加固部署上返回 429——恰好就是注释声称本测试要拦截的那种回归。

建议修复:要么在循环里对每个路径同时执行 GETHEAD,要么把注释收窄为它实际钉住的 GET 豁免:

// Pins the shape of the GET exemption after `/demo` was removed

— qwen3.8-max via Qwen Code /review (v0.21.8)

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 95e1769 Aug 10, 2026
100 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.9.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants