Skip to content

feat(core,cli): Workflow tool token budget + per-run UI surfacing (P5)#5231

Merged
wenshao merged 4 commits into
mainfrom
lazzy/workflow-p5-budget
Jun 18, 2026
Merged

feat(core,cli): Workflow tool token budget + per-run UI surfacing (P5)#5231
wenshao merged 4 commits into
mainfrom
lazzy/workflow-p5-budget

Conversation

@LaZzyMan

@LaZzyMan LaZzyMan commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds a per-run output-token budget to the Workflow tool. The budget is plumbed through the orchestrator dispatch gate, the WorkflowRunRegistry, the BackgroundTasksDialog phase tree, and the /workflows slash command. A one-time usage banner is prepended to the first successful workflow result of a session, gated by a new skipWorkflowUsageWarning setting. Two new knobs: QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<int> (env, per-run cap) and skipWorkflowUsageWarning: true (setting, suppress banner). Implementation includes WorkflowBudgetImpl + env resolver with a 100M hard ceiling on the override, WorkflowBudgetExceededError carrying runId / budgetTotal / spent, a budgetUpdated orchestrator emitter event, registry fields tokensSpent / tokenBudgetTotal / perPhaseTokens with an onBudgetUpdated handler attributing token deltas to currentPhase at fire time, and a shouldShowUsageWarning() latch that survives reset() so /clear doesn't re-arm the banner.

Why it's needed

Phase P5 of the Dynamic Workflows port (issue #4721). Workflows can dispatch up to 1000 agents per run; without a per-run output-token cap, a runaway script can burn through significant token budget unchecked. The cap is a soft gate, not a pre-commit reservation — checked at dispatch entry, so concurrent fan-out (parallel() / pipeline()) inside the concurrency window can overshoot by up to (concurrency_window − 1) × per_dispatch_tokens before the first overshooting dispatch throws WorkflowBudgetExceededError. Matches upstream Claude Code 2.1.168 semantics. The UI surfacing (chip in dialog row + per-phase totals + tokens/cap detail block) lets operators see the budget at glance without needing to read dist logs; the banner teaches the env knob without spamming the model context (banner lives in returnDisplay only, never in llmContent).

Reviewer Test Plan

How to verify

Set QWEN_CODE_ENABLE_WORKFLOWS=1 and launch qwen. Ask the model to run a workflow script via the Workflow tool. Observe (a) the one-time banner in the tool result, (b) the run appearing in /workflows, (c) /workflows <runId> rendering the tokens / cap / per-phase block. Run a second workflow in the same session and confirm the banner is suppressed. Set QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=100 and run a workflow that dispatches multiple agents — confirm the second or third dispatch throws WorkflowBudgetExceededError once cumulative output tokens exceed 100. Set skipWorkflowUsageWarning: true in settings and confirm the banner never appears.

# Run the workflow suites locally
cd packages/core && npx vitest run --no-coverage \
  src/agents/runtime/workflow-budget.test.ts \
  src/agents/runtime/workflow-orchestrator.test.ts \
  src/agents/runtime/workflow-sandbox.test.ts \
  src/tools/workflow/workflow.test.ts \
  src/agents/workflow-run-registry.test.ts
# Expected: 272 passed

cd packages/cli && npx vitest run --no-coverage \
  src/ui/commands/workflowsCommand.test.ts \
  src/ui/components/background-view/BackgroundTasksDialog.test.tsx
# Expected: 42 passed

Evidence (Before & After)

See the dedicated E2E test report comment (posted separately) for the full real-LLM tmux session capture. Highlights:

Before P5/workflows <runId> detail dump had no tokens / cap / per-phase fields; first Workflow call had no usage banner; QWEN_CODE_MAX_TOKENS_PER_WORKFLOW had no effect.

After P5 (tmux + DashScope qwen3.7-plus):

  • First call: banner prepended verbatim: > Workflows have no per-run token cap. Set 'QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<n>' (env) for a soft cap. Suppress this notice with 'skipWorkflowUsageWarning: true' in settings.
  • /workflows: Workflow runs (1 total · 0 running) + Recent row.
  • /workflows wf_xxx: status: completed, runtime: 2ms, agents: 0/0, tokens: 0, cap: (no cap), Phases (1).
  • Second call: banner suppressed (/skipWorkflowUsageWarning/ regex count = 1 across full scrollback).

Tested on

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

Local tmux verification on macOS only; CI runs cover Linux + Windows test suites (typecheck + 272 + 42).

Environment (optional)

Local dev: node bundle/qwen.js from npm run bundle output, OAuth qwen-oauth and --auth-type openai --openai-base-url https://dashscope.aliyuncs.com/compatible-mode/v1 --model qwen3.7-plus both confirmed working with the new tool registration.

Risk & Scope

  • Main risk or tradeoff: Budget is a soft gate, not pre-commit reservation — concurrent fan-out can overshoot by (concurrency_window − 1) × per_dispatch_tokens before the first overshoot dispatch throws. Documented in module-level docstring + banner copy. Matches upstream semantics. Operators sizing the cap should subtract this margin.
  • Not validated / out of scope: hard pre-commit reservation (would require either over-conservative blocking via per-agent estimate × concurrency, or a signaling protocol — both significant impl deltas not in P5's scope); per-phase attribution race when an agent crosses a phase() boundary mid-flight (documented in WorkflowRunRegistry.onBudgetUpdated JSDoc).
  • Breaking changes / migration notes: None. WorkflowTaskRegistration.tokenBudgetTotal is optional and defaults to null; legacy registrations continue working unchanged. Existing WorkflowOrchestratorEmitter consumers continue working without setting budgetUpdated. skipWorkflowUsageWarning defaults to false, banner fires once per session by default.

Linked Issues

Refs #4721

中文说明

这个 PR 干了什么

Workflow 工具增加按 run 的 output token 预算。预算贯通 orchestrator 调度门、WorkflowRunRegistryBackgroundTasksDialog phase 树,以及 /workflows slash 命令。每个 session 首次成功运行 workflow 时,在结果前 prepend 一次性使用提示横幅,由新设置 skipWorkflowUsageWarning 控制。两个新旋钮:QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<int>(env,按 run 上限)和 skipWorkflowUsageWarning: true(设置,关闭横幅)。实现包含 WorkflowBudgetImpl + env 解析器(env override 上有 100M 硬上限)、WorkflowBudgetExceededError(携带 runId / budgetTotal / spent)、budgetUpdated orchestrator emitter 事件、registry 字段 tokensSpent / tokenBudgetTotal / perPhaseTokens + onBudgetUpdated handler(按 fire 时刻的 currentPhase 归属 token delta),以及 shouldShowUsageWarning() latch(reset() 不重置,避免 /clear 重新触发横幅)。

为什么需要

Dynamic Workflows port 的 P5 阶段(issue #4721)。workflow 单 run 可以派发最多 1000 个 agent;没有按 run 的 output token 上限,跑飞的脚本可以消耗大量 token 不受约束。这个上限是软门,不是预先预留 —— 在调度入口检查,所以并发 fan-out(parallel() / pipeline())在 concurrency 窗口内可以 overshoot,最多到 (concurrency_window − 1) × per_dispatch_tokens,第一次 overshoot 的调度抛 WorkflowBudgetExceededError。与上游 Claude Code 2.1.168 语义对齐。UI 暴露(dialog 行 chip + per-phase 总计 + tokens/cap 详情块)让运维不用读 dist 日志就能 glance 看到预算;横幅教用户 env 旋钮,但不污染 model context(横幅只在 returnDisplay,不进 llmContent)。

Reviewer 验证计划

如何验证

QWEN_CODE_ENABLE_WORKFLOWS=1 启动 qwen。让 model 通过 Workflow 工具跑 workflow 脚本。观察 (a) 工具结果里出现一次性横幅,(b) 这次运行出现在 /workflows 列表里,(c) /workflows <runId> 渲染 tokens / cap / per-phase 块。同 session 跑第二次 workflow,确认横幅被压制。设 QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=100 跑一个派发多个 agent 的 workflow —— 确认累计 output token 超过 100 时第二或第三次调度抛 WorkflowBudgetExceededError。设 skipWorkflowUsageWarning: true 后确认横幅完全不出现。

Before / After 证据

详见单独贴出的 E2E 测试报告 comment(含完整 tmux 真场景截屏)。要点:

P5 之前 —— /workflows <runId> 详情没有 tokens / cap / per-phase 字段;首次调用没有横幅;QWEN_CODE_MAX_TOKENS_PER_WORKFLOW 不生效。

P5 之后(tmux + DashScope qwen3.7-plus 实测):

  • 第一次调用:横幅原样 prepend:> Workflows have no per-run token cap. Set 'QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<n>' (env) for a soft cap. Suppress this notice with 'skipWorkflowUsageWarning: true' in settings.
  • /workflowsWorkflow runs (1 total · 0 running) + Recent 行
  • /workflows wf_xxxstatus: completedruntime: 2msagents: 0/0tokens: 0cap: (no cap)Phases (1)
  • 第二次调用:横幅压制(全 scrollback 中 /skipWorkflowUsageWarning/ 匹配数 = 1)

测试平台

OS 状态
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

macOS 本地 tmux 实测;Linux + Windows 测试套件由 CI 覆盖(typecheck + 272 + 42 个测试)。

环境(可选)

本地 dev:node bundle/qwen.jsnpm run bundle 产物),OAuth qwen-oauth--auth-type openai --openai-base-url https://dashscope.aliyuncs.com/compatible-mode/v1 --model qwen3.7-plus 都验证可以触发新工具注册。

风险与边界

  • 主要风险/权衡:预算是软门,不是预先预留 —— 并发 fan-out 在第一次 overshoot 调度抛出前可以 overshoot 到 (concurrency_window − 1) × per_dispatch_tokens。模块级 docstring + 横幅文案都已注明。与上游语义对齐。运维设置上限时应留出这个余量。
  • 未验证/超出范围:硬预留(要么按 per-agent 估算 × concurrency 过度保守阻塞,要么搞个 signaling 协议 —— 都是大改动,超出 P5 范围);agent 跨 phase() 边界时的归属竞争(WorkflowRunRegistry.onBudgetUpdated JSDoc 中已说明)。
  • 破坏性变更/迁移:无。WorkflowTaskRegistration.tokenBudgetTotal 是 optional,默认 null;旧的 registration 继续无改动工作。已有的 WorkflowOrchestratorEmitter consumer 不实现 budgetUpdated 也无影响。skipWorkflowUsageWarning 默认 false,默认每 session 横幅触发一次。

关联 issue

Refs #4721

@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.

Hi @LaZzyMan, thanks for the detailed PR — the description is thorough and clearly well thought out.

However, the PR body doesn't follow our PR template. The template requires these sections (which are missing):

  • ## What this PR does
  • ## Why it's needed
  • ## Reviewer Test Plan (with ### How to verify, ### Evidence (Before & After), ### Tested on)
  • ## Risk & Scope
  • ## Linked Issues
  • <details><summary>中文说明</summary> block

The content is all here — it's just organized under different headings (## Summary, ## What lands, ## Test coverage, ## Test plan, etc.) that don't match the template. Could you restructure the body to use the template headings? Most of the existing content maps directly:

  • "Summary" → "What this PR does" + "Why it's needed"
  • "Test plan" → "Reviewer Test Plan" (with the sub-sections)
  • Add a "Risk & Scope" section and the 中文说明 block

This helps maintainers scan PRs consistently and won't take long given how complete the description already is.

中文说明

感谢详细的 PR 描述!内容很充实,但 PR 正文未使用我们的PR 模板。请将现有内容重新组织到模板要求的标题下(What this PR does / Why it's needed / Reviewer Test Plan / Risk & Scope / Linked Issues / 中文说明)。大部分内容可以直接映射过去,不会花太多时间。

Qwen Code · qwen3.7-max

@github-actions

github-actions Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 76.74% 76.74% 80.49% 79.9%
Core 82.52% 82.52% 84.21% 84.1%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   76.74 |     79.9 |   80.49 |   76.74 |                   
 src               |    71.2 |     68.3 |   73.91 |    71.2 |                   
  gemini.tsx       |   63.74 |    65.83 |   71.42 |   63.74 | ...1170-1174,1213 
  ...ractiveCli.ts |   70.34 |    64.53 |   66.66 |   70.34 | ...1609-1611,1646 
  ...liCommands.ts |   84.88 |    77.92 |     100 |   84.88 | ...41,367,401,493 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   56.58 |    61.25 |   82.75 |   56.58 |                   
  acpAgent.ts      |   56.43 |    61.28 |   82.94 |   56.43 | ...7043,7068-7083 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   68.65 |    83.33 |   66.66 |   68.65 |                   
  filesystem.ts    |   68.65 |    83.33 |   66.66 |   68.65 | ...32,77-94,97-98 
 ...ration/session |   85.09 |    78.48 |   88.18 |   85.09 |                   
  ...ryReplayer.ts |   67.34 |     75.6 |   81.81 |   67.34 | ...54-269,282-283 
  Session.ts       |   85.72 |    78.04 |   89.36 |   85.72 | ...4424,4450-4454 
  ...entTracker.ts |   91.62 |    89.47 |   88.88 |   91.62 | ...32,196,272-281 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   84.21 |    82.14 |     100 |   84.21 | ...37-153,209-211 
  tasksSnapshot.ts |   94.06 |    86.66 |     100 |   94.06 | 60-66             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ssion/emitters |   96.25 |    94.11 |   96.96 |   96.25 |                   
  BaseEmitter.ts   |    92.3 |    81.81 |     100 |    92.3 | 23-24             
  ...ageEmitter.ts |   95.23 |    95.12 |     100 |   95.23 | 48-55             
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   98.44 |    94.44 |     100 |   98.44 | 318-319,420,428   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |    91.3 |    88.09 |   94.44 |    91.3 |                   
  LlmRewriter.ts   |      81 |       84 |     100 |      81 | ...,88-89,155-159 
  ...Middleware.ts |   96.74 |    86.84 |     100 |   96.74 | 135,143-145       
  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/commands      |   59.53 |     87.5 |      48 |   59.53 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
  serve.ts         |   46.52 |      100 |   33.33 |   46.52 | 29-31,260-467     
  sessions.ts      |     100 |      100 |      50 |     100 |                   
 ...mmands/channel |    39.2 |    79.45 |      50 |    39.2 |                   
  ...l-registry.ts |    8.33 |      100 |       0 |    8.33 | 6-22,25-43        
  config-utils.ts  |      92 |      100 |   66.66 |      92 | 21-26             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   30.98 |       52 |   69.23 |   30.98 | ...72-475,484-486 
  status.ts        |   17.85 |      100 |       0 |   17.85 | 15-26,32-76       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   85.44 |    89.39 |   81.81 |   85.44 |                   
  consent.ts       |   72.68 |       90 |   42.85 |   72.68 | ...86-142,157-163 
  disable.ts       |     100 |      100 |     100 |     100 |                   
  enable.ts        |     100 |      100 |     100 |     100 |                   
  install.ts       |    75.6 |    66.66 |   66.66 |    75.6 | ...39-142,145-153 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |      100 |     100 |     100 |                   
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  uninstall.ts     |    37.5 |      100 |   33.33 |    37.5 | 23-45,57-64,67-70 
  update.ts        |   96.32 |      100 |     100 |   96.32 | 101-105           
  utils.ts         |   67.77 |    38.88 |     100 |   67.77 | ...,94-98,100-104 
 ...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.28 |    88.88 |   83.33 |   90.28 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 293               
  approve.ts       |   76.19 |     87.5 |   66.66 |   76.19 | ...,89-99,114-124 
  list.ts          |   92.48 |    86.66 |      80 |   92.48 | ...60-162,178-179 
  reconnect.ts     |   77.71 |    78.57 |   85.71 |   77.71 | 40-53,160-182     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   11.57 |      100 |       0 |   11.57 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   11.32 |      100 |       0 |   11.32 | ...41-153,155-156 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 ...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        |   91.45 |    85.75 |   91.66 |   91.45 |                   
  auth.ts          |   88.94 |    83.56 |     100 |   88.94 | ...86-287,303-304 
  ...eMcpImport.ts |   87.88 |    81.52 |     100 |   87.88 | ...57-365,447-448 
  config.ts        |   87.14 |    84.58 |   82.14 |   87.14 | ...2040,2042-2050 
  keyBindings.ts   |   96.87 |       50 |     100 |   96.87 | 201-204           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  mcpApprovals.ts  |   96.12 |    94.87 |     100 |   96.12 | 193-194,199-201   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  settings.ts      |   79.18 |    86.71 |    87.8 |   79.18 | ...1550,1565-1568 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.22 |    94.33 |     100 |   96.22 | ...95-197,212-213 
 ...nfig/migration |   94.89 |    78.94 |   83.33 |   94.89 |                   
  index.ts         |   94.87 |    88.88 |     100 |   94.87 | 91-92             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.74 |    96.06 |     100 |   94.74 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.56 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
 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    |   69.39 |    66.66 |   63.15 |   69.39 |                   
  ...tputBridge.ts |   69.48 |     67.3 |    64.7 |   69.48 | ...82-383,391-394 
  ...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/i18n          |   82.47 |    75.94 |   65.71 |   82.47 |                   
  index.ts         |   63.68 |    69.56 |   53.84 |   63.68 | ...70-271,281-286 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,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 |   72.45 |    71.03 |   74.07 |   72.45 |                   
  session.ts       |   76.46 |    69.34 |   85.71 |   76.46 | ...32-833,842-852 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...90-591,594-595 
 ...active/control |   76.29 |    88.23 |      80 |   76.29 |                   
  ...rolContext.ts |    6.89 |        0 |       0 |    6.89 | 50-86             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...49-367,383,386 
  ...rolService.ts |     7.4 |        0 |       0 |     7.4 | 46-185            
 ...ol/controllers |    26.7 |    37.93 |   35.48 |    26.7 |                   
  ...Controller.ts |   36.97 |       80 |      80 |   36.97 | ...15-117,127-210 
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   31.32 |     38.7 |      40 |   31.32 | ...68-577,592-597 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |   21.97 |    28.57 |   27.27 |   21.97 | ...39-451,460-489 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.01 |    93.77 |   95.23 |   98.01 |                   
  ...putAdapter.ts |   97.89 |    92.82 |   98.07 |   97.89 | ...1303,1398-1399 
  ...putAdapter.ts |      96 |     90.9 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 83-84,124-125     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |   79.84 |    81.96 |   80.74 |   79.84 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.26 |    92.64 |     100 |   93.26 | ...07-308,311-313 
  ...temAdapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    95.45 |     100 |     100 | 342               
  daemonLogger.ts  |   98.63 |    90.32 |   95.83 |   98.63 | 161,165           
  daemonStatus.ts  |    98.3 |    82.99 |     100 |    98.3 | ...11,513-514,563 
  ...usProvider.ts |   67.01 |    51.42 |     100 |   67.01 | ...40-245,278-286 
  debugMode.ts     |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  envSnapshot.ts   |   92.75 |       84 |     100 |   92.75 | 110-113,179-186   
  eventBus.ts      |     100 |      100 |     100 |     100 |                   
  ...oryChannel.ts |       0 |        0 |       0 |       0 | 1-14              
  index.ts         |       0 |        0 |       0 |       0 | 1-143             
  loopbackBinds.ts |     100 |      100 |     100 |     100 |                   
  ...ssionAudit.ts |     100 |      100 |   93.33 |     100 |                   
  rateLimit.ts     |   90.37 |    87.77 |   93.75 |   90.37 | ...95-297,348-352 
  runQwenServe.ts  |   68.51 |     82.2 |      32 |   68.51 | ...1392,1395-1402 
  server.ts        |   80.46 |     83.3 |   84.93 |   80.46 | ...4710,4776-4785 
  status.ts        |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...paceAgents.ts |   62.47 |    70.34 |   90.47 |   62.47 | ...1346,1356-1366 
  ...paceMemory.ts |   87.13 |    78.46 |     100 |   87.13 | ...54-361,421-428 
 src/serve/acpHttp |   66.04 |     67.9 |   93.61 |   66.04 |                   
  ...onRegistry.ts |   89.08 |    82.43 |   93.33 |   89.08 | ...05,479,499-513 
  dispatch.ts      |   56.25 |    58.89 |     100 |   56.25 | ...2469,2543-2546 
  index.ts         |   75.63 |    68.21 |    90.9 |   75.63 | ...31,734,760-762 
  jsonRpc.ts       |     100 |    96.96 |     100 |     100 | 92                
  sseStream.ts     |   93.91 |    87.87 |   84.61 |   93.91 | ...50-152,154-156 
  ...portStream.ts |       0 |        0 |       0 |       0 | 1                 
  wsStream.ts      |   91.86 |       80 |     100 |   91.86 | 45,50,93,97-100   
 src/serve/auth    |   86.86 |    79.18 |   93.87 |   86.86 |                   
  deviceFlow.ts    |   96.35 |       80 |   97.61 |   96.35 | ...1358,1453,1519 
  ...owProvider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 src/serve/fs      |   85.12 |    81.01 |     100 |   85.12 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 201               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.82 |    77.08 |     100 |   77.82 | ...64,493-497,510 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...FileSystem.ts |   84.03 |    78.55 |     100 |   84.03 | ...2031,2058-2059 
 src/serve/routes  |   75.89 |    76.51 |   94.28 |   75.89 |                   
  a2uiAction.ts    |     100 |    93.65 |     100 |     100 | 114-118,163,267   
  ...ceFileRead.ts |   94.41 |    76.92 |     100 |   94.41 | ...28-329,390-392 
  ...eFileWrite.ts |    82.1 |    60.52 |     100 |    82.1 | ...42-244,247-249 
  ...ceSettings.ts |   23.62 |      100 |      50 |   23.62 | ...10-223,230-327 
 ...kspace-service |   81.05 |     82.4 |   86.66 |   81.05 |                   
  index.ts         |   81.23 |    83.17 |   92.85 |   81.23 | ...92-497,557-622 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/services      |   91.95 |    90.65 |   97.56 |   91.95 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 97-110            
  ...killLoader.ts |     100 |    93.33 |     100 |     100 | 48,67             
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.84 |    80.64 |   83.33 |   75.84 | ...10-211,277-278 
  ...mandLoader.ts |     100 |    97.14 |     100 |     100 | 66                
  ...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.21 |    96.66 |     100 |   98.21 | 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 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |    88.3 |    85.49 |   92.59 |    88.3 |                   
  DataProcessor.ts |   88.22 |    85.48 |      95 |   88.22 | ...1341,1345-1352 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...teRenderer.ts |   45.45 |      100 |       0 |   45.45 | 13-51             
 .../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 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.35 |    84.84 |     100 |   97.35 |                   
  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       |   66.82 |    78.94 |   66.66 |   66.82 |                   
  ...reeStartup.ts |   66.82 |    78.94 |   66.66 |   66.82 | ...08-312,363-426 
 src/test-utils    |   93.71 |    83.33 |      80 |   93.71 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   69.74 |       75 |   60.31 |   69.74 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   70.12 |    68.63 |   52.63 |   70.12 | ...3251,3255-3259 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...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 |                   
  ...inePresets.ts |   98.28 |    89.87 |     100 |   98.28 | ...34,261,420-422 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   59.16 |    65.94 |   51.11 |   59.16 |                   
  AuthDialog.tsx   |   62.87 |     42.1 |   18.18 |   62.87 | ...03,310-332,336 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.03 |    70.37 |      56 |   60.03 | ...87,791,800,803 
  useAuth.ts       |   94.55 |    73.52 |     100 |   94.55 | ...19-220,239-245 
  ...rSetupFlow.ts |   43.52 |    33.33 |      50 |   43.52 | ...72-393,410-453 
 src/ui/commands   |   77.18 |    81.68 |   85.43 |   77.18 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.47 |    81.25 |     100 |   89.47 | 92-93,95-100      
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...90-595,680-688 
  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     |   89.44 |    80.35 |     100 |   89.44 | ...81,106-111,190 
  clearCommand.ts  |   79.64 |       68 |     100 |   79.64 | ...24-125,133-142 
  ...essCommand.ts |   67.95 |    55.88 |      75 |   67.95 | ...86-187,201-204 
  ...astCommand.ts |   70.86 |    74.07 |      75 |   70.86 | ...,61-93,117-122 
  ...extCommand.ts |   65.35 |     66.1 |   84.61 |   65.35 | ...42-575,586-587 
  copyCommand.ts   |   98.49 |    95.78 |     100 |   98.49 | ...80,280,321,327 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |     87.5 |     100 |     100 | ...61,224-225,238 
  ...ryCommand.tsx |   81.84 |    86.11 |   91.66 |   81.84 | ...66-271,318-325 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   61.27 |    87.06 |    87.5 |   61.27 | ...71-372,445-665 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   51.54 |    48.14 |   69.23 |   51.54 | ...97,251-303,364 
  forgetCommand.ts |     100 |       90 |     100 |     100 | 59                
  forkCommand.ts   |     100 |    94.11 |     100 |     100 | 96,147            
  goalCommand.ts   |   91.46 |    84.44 |      90 |   91.46 | ...87-190,202-205 
  helpCommand.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   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   92.17 |    82.69 |     100 |   92.17 | ...39,159,168-178 
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   75.28 |    78.18 |      75 |   75.28 | ...27-232,269-274 
  ...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             
  ...berCommand.ts |      96 |       70 |     100 |      96 | 57,62             
  renameCommand.ts |   85.71 |    86.04 |     100 |   85.71 | ...02-209,216-221 
  ...oreCommand.ts |   90.47 |    84.61 |     100 |   90.47 | ...32-137,167-168 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |    85.5 |    81.25 |     100 |    85.5 | 36-44,70          
  statsCommand.ts  |   91.48 |    89.47 |     100 |   91.48 | 40-43,134-141     
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.46 |      100 |      50 |    6.46 | 31-329            
  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 |                   
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  ...owsCommand.ts |   89.82 |    87.03 |      60 |   89.82 | ...23-124,133-138 
 src/ui/components |   62.65 |    77.66 |   60.68 |   62.65 |                   
  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 |   16.27 |      100 |       0 |   16.27 | 19-58             
  ...TextInput.tsx |   77.01 |       76 |     100 |   77.01 | ...20,234-236,263 
  Composer.tsx     |   80.83 |    57.14 |     100 |   80.83 | ...90,102,154,167 
  ...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 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.86 |      100 |       0 |   11.86 | 69-550            
  DiffDialog.tsx   |    2.47 |      100 |       0 |    2.47 | 68-732            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  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       |   78.12 |    51.16 |     100 |   78.12 | ...43,176,198-203 
  ...ngSpinner.tsx |   68.42 |       80 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   76.19 |    81.81 |     100 |   76.19 | 24-30,46-50       
  Header.tsx       |   98.62 |    94.28 |     100 |   98.62 | 162,164           
  Help.tsx         |   98.32 |       90 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |   65.03 |    55.55 |     100 |   65.03 | ...75,378,381-387 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |    83.1 |    78.07 |   83.33 |    83.1 | ...1652,1667,1717 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |     100 |     90.9 |     100 |     100 | 62,74             
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   87.11 |    88.31 |   66.66 |   87.11 | ...26,284,343-347 
  MemoryDialog.tsx |   61.87 |    76.05 |    62.5 |   61.87 | ...72,391,428-430 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   85.31 |    70.42 |     100 |   85.31 | ...03-619,676-680 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-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 |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-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 |   92.42 |    84.37 |     100 |   92.42 | ...,70-71,143-145 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   66.31 |    71.16 |      75 |   66.31 | ...16-824,830-831 
  ...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 |      28 |      100 |       0 |      28 | 18-40             
  ...ionPicker.tsx |   17.59 |      100 |       0 |   17.59 | 55-172            
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.85 |      100 |       0 |    8.85 | ...5,49-84,92-238 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    3.28 |      100 |       0 |    3.28 | 25-258            
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |    5.46 |      100 |       0 |    5.46 | 24-215            
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.33 |    88.23 |     100 |   96.33 | 137-140           
  ...nsDisplay.tsx |   87.61 |    65.38 |     100 |   87.61 | ...67-169,176-178 
  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 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   91.42 |    64.28 |     100 |   91.42 | 15,21,24          
  ...s-helpers.tsx |      25 |      100 |       0 |      25 | ...3,86-89,94-102 
 ...nts/agent-view |   38.22 |    78.82 |   41.66 |   38.22 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   10.84 |      100 |       0 |   10.84 | 59-308            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |   87.39 |    62.85 |     100 |   87.39 | ...,85,98-106,124 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.59 |    70.53 |   60.86 |   45.59 |                   
  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 |    9.92 |      100 |       0 |    9.92 | 27-164            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   77.88 |       80 |   89.47 |   77.88 |                   
  ...sksDialog.tsx |   74.53 |       77 |    82.6 |   74.53 | ...1444,1506-1508 
  ...TasksPill.tsx |   67.03 |     86.2 |     100 |   67.03 | ...02-122,130-138 
  ...gentPanel.tsx |    97.4 |    85.39 |     100 |    97.4 | 120,433-437       
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.88 |    94.23 |   66.66 |   54.88 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 20-131            
  ...nListStep.tsx |   88.43 |    94.73 |      80 |   88.43 | 52-53,59-72,106   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   86.85 |    81.37 |   91.89 |   86.85 |                   
  ...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 |   21.66 |    89.36 |   76.92 |   21.66 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |    3.66 |      100 |       0 |    3.66 | 41-712            
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-30              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |     92.1 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   26.36 |    54.54 |   42.85 |   26.36 |                   
  ...icateStep.tsx |    5.67 |      100 |       0 |    5.67 | 40-66,69-307      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.15 |      100 |       0 |    5.15 | 31-251            
  ...rListStep.tsx |   75.18 |    59.37 |     100 |   75.18 | ...53-158,169-173 
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |   69.02 |       50 |     100 |   69.02 | ...22,125,134-143 
 ...nents/messages |   83.08 |    79.44 |   78.82 |   83.08 |                   
  ...ionDialog.tsx |   80.84 |     77.6 |    62.5 |   80.84 | ...98,516,534-536 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.72 |     100 |   97.67 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   80.85 |    70.73 |    92.3 |   80.85 | ...08,427,462-468 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...tsDisplay.tsx |    95.1 |    88.05 |     100 |    95.1 | ...29,131,164-169 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   55.67 |       40 |   28.57 |   55.67 | ...20-125,133-145 
  ...ryMessage.tsx |   14.28 |      100 |       0 |   14.28 | 23-62             
  ...onMessage.tsx |   82.31 |    74.02 |   33.33 |   82.31 | ...69-471,478-480 
  ...upMessage.tsx |   82.63 |    92.85 |     100 |   82.63 | ...85-412,434-449 
  ToolMessage.tsx  |    87.8 |    73.28 |    92.3 |    87.8 | ...59-764,791-793 
 ...ponents/shared |   84.43 |    80.52 |    95.5 |   84.43 |                   
  ...ctionList.tsx |   99.14 |       96 |     100 |   99.14 | 99                
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   83.01 |    86.15 |   88.88 |   83.01 | ...12-513,618-619 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   76.25 |       80 |     100 |   76.25 | 44-58,65-68       
  StaticRender.tsx |   72.72 |      100 |     100 |   72.72 | 31-33             
  TextInput.tsx    |    80.8 |    66.07 |      80 |    80.8 | ...36-240,252-258 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   84.26 |    80.88 |      90 |   84.26 | ...68-696,743-765 
  text-buffer.ts   |   85.94 |    81.18 |   97.91 |   85.94 | ...2651,2749-2750 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |    3.61 |      100 |       0 |    3.61 |                   
  ...gerDialog.tsx |    3.61 |      100 |       0 |    3.61 | ...90-148,151-694 
 ...ents/subagents |   30.87 |        0 |       0 |   30.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   10.95 |      100 |       0 |   10.95 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |   21.51 |    59.52 |   27.27 |   21.51 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   70.21 |    67.32 |    64.7 |   70.21 |                   
  ContextUsage.tsx |   70.88 |    63.88 |      80 |   70.88 | ...20-426,463-557 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   77.47 |    77.77 |   81.03 |   77.47 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   92.45 |    62.79 |      50 |   92.45 | ...69-270,272-276 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   81.67 |     81.6 |     100 |   81.67 | ...1199,1203-1205 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   43.26 |     62.5 |    62.5 |   43.26 | ...64-267,276-279 
  ...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             
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 134-135           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 203-204           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
 src/ui/daemon     |   90.65 |    73.61 |   95.45 |   90.65 |                   
  ...TuiAdapter.ts |   90.65 |    73.61 |   95.45 |   90.65 | ...44,762-763,849 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |    81.9 |    81.04 |    86.5 |    81.9 |                   
  ...dProcessor.ts |   84.36 |    80.53 |     100 |   84.36 | ...44-445,451-456 
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...dProcessor.ts |    94.8 |    70.58 |     100 |    94.8 | ...76-277,282-283 
  ...dProcessor.ts |   83.94 |    62.56 |      80 |   83.94 | ...1010,1031-1035 
  ...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 |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...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 |   91.79 |    86.88 |     100 |   91.79 | ...05-206,243-246 
  ...ifications.ts |   86.91 |    96.29 |     100 |   86.91 | 116-130           
  ...tIndicator.ts |   83.49 |    70.96 |     100 |   83.49 | ...60,168,170-178 
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   93.84 |    74.46 |     100 |   93.84 | ...25-129,218,224 
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   92.53 |    71.42 |     100 |   92.53 | ...32,172,245-248 
  ...ompletion.tsx |   96.01 |    83.87 |     100 |   96.01 | ...22-223,225-226 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   77.27 |       50 |     100 |   77.27 | ...2,75-79,93-101 
  ...eteCommand.ts |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...ialogClose.ts |    12.5 |      100 |     100 |    12.5 | 85-181            
  useDiffData.ts   |   11.62 |      100 |       0 |   11.62 | 44-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.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...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 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   89.15 |     62.5 |      50 |   89.15 | ...22-124,149-150 
  ...miniStream.ts |   80.61 |    78.42 |   93.33 |   80.61 | ...2852,2900-2908 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   97.43 |    98.18 |     100 |   97.43 | 52,139-142        
  ...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 |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   63.15 |       75 |      50 |   63.15 | 42-52,64-67       
  ...cpApproval.ts |   92.37 |    83.33 |     100 |   92.37 | ...00-103,115-116 
  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 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...ouseEvents.ts |   87.17 |    88.88 |   66.66 |   87.17 | 81-82,86-88       
  ...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 |   86.49 |    77.96 |    90.9 |   86.49 | ...26,288-300,348 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |    84.7 |    93.33 |     100 |    84.7 | ...71-276,372-382 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...tleRepaint.ts |     100 |      100 |     100 |     100 |                   
  ...umeCommand.ts |   96.96 |    83.33 |     100 |   96.96 | 101-102,131       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   97.05 |    96.11 |     100 |   97.05 | ...90-191,245-248 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.73 |    85.41 |   94.73 |   82.73 | ...70-672,680-716 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |    96.3 |    92.19 |     100 |    96.3 | ...77-380,466-473 
  ...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 |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  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 | 44-45,87          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    90.9 |    90.62 |     100 |    90.9 |                   
  ...AppLayout.tsx |   90.72 |       90 |     100 |   90.72 | 57-59,101-106     
  ...AppLayout.tsx |   91.17 |    91.66 |     100 |   91.17 | 70-75             
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |    7.14 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    7.14 |     100 |                   
 src/ui/state      |   94.91 |    81.81 |     100 |   94.91 |                   
  extensions.ts    |   94.91 |    81.81 |     100 |   94.91 | 68-69,88          
 src/ui/themes     |   98.39 |    72.83 |     100 |   98.39 |                   
  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   |   97.91 |       92 |     100 |   97.91 | ...51-352,354-355 
  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 |   87.98 |    82.89 |     100 |   87.98 | ...48-357,362-363 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   83.35 |     82.9 |   92.81 |   83.35 |                   
  ...Colorizer.tsx |   80.42 |    85.41 |     100 |   80.42 | ...00-201,298-324 
  ...nRenderer.tsx |   68.83 |    70.14 |      50 |   68.83 | ...52-254,274-293 
  ...wnDisplay.tsx |   86.01 |    87.66 |     100 |   86.01 | ...87,704,729-754 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.08 |    80.45 |      95 |   92.08 | ...76-679,723-728 
  ...odeDisplay.ts |   96.55 |     90.9 |     100 |   96.55 | 34                
  asciiCharts.ts   |   96.77 |    87.62 |     100 |   96.77 | 173-180,281       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   51.92 |    72.72 |   91.66 |   51.92 | ...21,624-633,636 
  commandUtils.ts  |      96 |    88.77 |     100 |      96 | ...72,174-175,302 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   88.37 |    72.22 |     100 |   88.37 | 23,25,29,31,33    
  formatters.ts    |   95.23 |    98.33 |     100 |   95.23 | 117-120           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    96.77 |     100 |     100 | 43                
  historyUtils.ts  |   94.11 |       94 |     100 |   94.11 | 94-97             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |    89.47 |     100 |     100 | 81,110            
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |   98.66 |    96.77 |     100 |   98.66 | 48-49             
  ...geRenderer.ts |   86.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   90.71 |    73.33 |   88.88 |   90.71 | ...40-143,200-201 
  osc8.ts          |   94.73 |    87.75 |     100 |   94.73 | ...49,434,438-439 
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |   99.02 |    97.14 |     100 |   99.02 | 106               
  ...storyUtils.ts |   62.71 |    72.41 |      90 |   62.71 | ...82,430,435-457 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.61 |    94.84 |   92.85 |   97.61 | ...50-251,386-387 
  todoSnapshot.ts  |   89.33 |    93.47 |     100 |   89.33 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |      57 |     40.8 |   79.41 |      57 |                   
  collect.ts       |   55.92 |    50.58 |   86.36 |   55.92 | ...25-640,642-647 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   58.11 |    20.51 |      80 |   58.11 | ...13-314,328-363 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   72.49 |    89.35 |   90.46 |   72.49 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.72 |    97.14 |     100 |   96.72 | 165-168           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   90.51 |    91.89 |     100 |   90.51 | 67-76,116         
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.38 |    71.83 |   88.88 |   70.38 | ...27,430-431,438 
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...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.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   97.14 |    96.42 |     100 |   97.14 | 125-126           
  errors.ts        |   90.85 |    96.36 |    92.3 |   90.85 | 69-70,298-310     
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |    92.2 |    95.23 |   88.88 |    92.2 | 130-141           
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |    98.4 |    96.34 |     100 |    98.4 | 241,258-259,304   
  languageUtils.ts |   98.19 |    96.87 |     100 |   98.19 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |     100 |    98.92 |     100 |     100 | 218               
  ...iveHelpers.ts |   96.37 |    93.07 |     100 |   96.37 | ...15-416,514,527 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   93.22 |    81.25 |     100 |   93.22 | 65-67,80          
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-1054            
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.51 |    91.79 |   89.74 |   82.51 | ...76-694,701-709 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   26.82 |    73.77 |   43.47 |   26.82 | ...36-837,840-859 
  ...upProfiler.ts |   98.46 |    94.52 |     100 |   98.46 | 130-131,305       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   95.12 |    89.06 |     100 |   95.12 | ...43-244,249-253 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  ...alSequence.ts |     100 |    95.23 |     100 |     100 | 60,90             
  ...iffPreview.ts |   94.11 |    83.33 |     100 |   94.11 | 13                
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |    62.1 |       75 |     100 |    62.1 | 93,107,118-157    
 ...s/housekeeping |   90.15 |     89.7 |   94.11 |   90.15 |                   
  cleanup.ts       |   94.33 |       95 |     100 |   94.33 | 60-62             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   89.71 |    88.23 |   85.71 |   89.71 | 51-55,66,116-120  
  throttledOnce.ts |   86.66 |    85.18 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   82.52 |     84.1 |   84.21 |   82.52 |                   
 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        |   89.14 |    80.96 |   94.21 |   89.14 |                   
  ...transcript.ts |   92.25 |    85.71 |     100 |   92.25 | ...01,320-321,452 
  ...ent-resume.ts |   83.08 |    69.86 |   78.12 |   83.08 | ...1120-1124,1127 
  ...ound-tasks.ts |   95.07 |    88.12 |     100 |   95.07 | ...1151,1171-1174 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...n-registry.ts |   95.36 |    88.31 |     100 |   95.36 | ...64-365,437-441 
 src/agents/arena  |   76.54 |    66.87 |   78.72 |   76.54 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.37 |    63.37 |   78.26 |   75.37 | ...1860,1866-1867 
  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 |   76.43 |    86.23 |   73.04 |   76.43 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.98 |     90.9 |   86.66 |   91.98 | ...95,250-270,329 
  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 |   86.39 |    85.14 |   78.85 |   86.39 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   77.48 |    73.56 |   65.21 |   77.48 | ...1713,1740-1787 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   84.48 |    78.04 |   63.63 |   84.48 | ...00-401,404-405 
  ...nteractive.ts |   80.55 |    81.35 |   74.07 |   80.55 | ...79,481,483,486 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...chestrator.ts |   91.64 |    89.82 |   80.64 |   91.64 | ...1493,1542-1545 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...ow-sandbox.ts |   96.85 |    94.54 |     100 |   96.85 | ...24-325,330-331 
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   80.31 |    83.19 |    86.5 |   80.31 |                   
  TeamManager.ts   |   67.11 |    76.25 |   74.41 |   67.11 | ...1433,1456-1457 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   94.76 |    86.36 |   92.85 |   94.76 | 86-87,348-354     
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   88.85 |    82.47 |   96.29 |   88.85 | ...-990,1034-1035 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...37-141,148-152 
  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 |    93.38 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    77.77 |     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        |   78.62 |    83.69 |   63.94 |   78.62 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   77.01 |    82.85 |   60.28 |   77.01 | ...4937,4942-4943 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.24 |    91.13 |   88.09 |   94.24 | ...68-369,372-373 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   88.24 |    83.94 |   91.82 |   88.24 |                   
  baseLlmClient.ts |   81.74 |    77.52 |   77.77 |   81.74 | ...24,526-536,545 
  client.ts        |   87.71 |    81.49 |   89.83 |   87.71 | ...2584,2678-2679 
  ...tGenerator.ts |   84.86 |    69.23 |     100 |   84.86 | ...84,386,393-396 
  ...lScheduler.ts |   87.27 |    81.79 |   95.89 |   87.27 | ...4132,4160-4171 
  geminiChat.ts    |   89.04 |    87.24 |      95 |   89.04 | ...3253,3320-3321 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |    95.83 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   86.48 |    72.22 |     100 |   86.48 | ...97-198,212-221 
  ...issionFlow.ts |   98.78 |       96 |     100 |   98.78 | 93                
  prompts.ts       |   88.93 |    87.87 |   72.72 |   88.93 | ...-910,1113-1114 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...allIdUtils.ts |      98 |    91.42 |     100 |      98 | 31,40             
  ...okTriggers.ts |   99.43 |    91.34 |     100 |   99.43 | 172,183           
  turn.ts          |   96.35 |    88.67 |     100 |   96.35 | ...28,441-442,486 
 ...ntentGenerator |   94.88 |    82.07 |      94 |   94.88 |                   
  ...tGenerator.ts |   96.29 |    83.18 |   92.85 |   96.29 | ...1,971,999-1001 
  converter.ts     |   94.51 |    80.72 |     100 |   94.51 | ...06-607,617,823 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.53 |    71.64 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.96 |   92.85 |      90 | ...80-286,304-305 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   94.22 |    83.96 |   91.17 |   94.22 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   94.09 |     82.5 |   90.62 |   94.09 | ...1025-1026,1054 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   86.47 |    84.42 |   93.67 |   86.47 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   85.16 |    82.33 |   96.15 |   85.16 | ...1485,1654-1669 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   54.54 |    68.75 |      50 |   54.54 | ...79,87-91,95-99 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   94.38 |     86.5 |     100 |   94.38 | ...38-539,547,615 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |    90.2 |    87.65 |     100 |    90.2 | ...39-343,373-374 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.67 |    88.94 |   96.07 |   96.67 |                   
  dashscope.ts     |   97.37 |    91.39 |   93.33 |   97.37 | ...90-291,369-370 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   95.79 |    89.65 |   88.88 |   95.79 | 122-123,193-195   
  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 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
 src/extension     |   62.64 |    79.47 |   80.31 |   62.64 |                   
  ...-converter.ts |   66.28 |    52.03 |     100 |   66.28 | ...98-799,808-840 
  ...ionManager.ts |   47.85 |    82.31 |    65.9 |   47.85 | ...1402,1412-1431 
  ...onSettings.ts |   93.46 |    93.05 |     100 |   93.46 | ...17-221,228-232 
  ...-converter.ts |   54.88 |    94.44 |      60 |   54.88 | ...35-146,158-192 
  github.ts        |   46.41 |     87.3 |   63.63 |   46.41 | ...66-372,411-464 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.31 |    93.75 |     100 |   97.31 | ...65,185-186,275 
  npm.ts           |   59.01 |    71.69 |    87.5 |   59.01 | ...23-425,432-436 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   75.82 |    71.49 |    90.9 |   75.82 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   96.29 |    88.88 |     100 |   96.29 | 78,108,122        
  speculation.ts   |   63.01 |    40.29 |   71.42 |   63.01 | ...73-574,577-582 
  ...onToolGate.ts |     100 |    96.55 |     100 |     100 | 95                
  ...nGenerator.ts |   70.23 |    74.57 |   83.33 |   70.23 | ...83-247,317-319 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   89.57 |    83.57 |   94.44 |   89.57 |                   
  ...eGoalStore.ts |    85.1 |    95.45 |   84.61 |    85.1 | ...63-166,174-182 
  goalHook.ts      |   97.26 |    91.66 |     100 |   97.26 | 100-105           
  goalJudge.ts     |   84.33 |    74.28 |     100 |   84.33 | ...57-358,366-368 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   86.88 |    85.58 |   88.01 |   86.88 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.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.35 |    90.69 |     100 |   96.35 | ...00-301,382,384 
  ...entHandler.ts |   95.27 |    86.74 |   94.11 |   95.27 | ...63,920-921,931 
  hookPlanner.ts   |   86.29 |    83.33 |   85.71 |   86.29 | ...15-219,226-237 
  hookRegistry.ts  |   91.48 |    84.61 |     100 |   91.48 | ...97,416,420,424 
  hookRunner.ts    |   62.42 |    72.04 |   66.66 |   62.42 | ...64-765,774-775 
  hookSystem.ts    |   86.78 |      100 |   68.88 |   86.78 | ...07-708,714-715 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   96.37 |     90.9 |      90 |   96.37 | 342-350,424-425   
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   96.66 |    91.66 |     100 |   96.66 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   92.83 |       94 |    87.5 |   92.83 | ...87-488,573-577 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   75.55 |    83.52 |   78.33 |   75.55 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   66.14 |    81.75 |   66.66 |   66.14 | ...3-964,993-1001 
  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           |   42.42 |     51.9 |   52.14 |   42.42 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...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 |   25.31 |    62.06 |   41.66 |   25.31 | ...85-704,710-740 
  ...eLspClient.ts |   32.77 |       80 |   17.64 |   32.77 | ...84-288,294-295 
  ...LspService.ts |   51.85 |    65.98 |   68.57 |   51.85 | ...1339,1399-1409 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   79.21 |    76.52 |   76.36 |   79.21 |                   
  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 |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.64 |    97.77 |     100 |   98.64 | 88-89             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.72 |    87.05 |   86.36 |   79.72 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   83.44 |    84.21 |   92.85 |   83.44 | ...68-178,186-187 
  ...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        |   73.76 |    77.49 |   72.68 |   73.76 |                   
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |      66 |    73.33 |      50 |      66 | 51,108-149        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   63.77 |    79.16 |      50 |   63.77 | ...72-180,183-189 
  extract.ts       |   92.72 |    74.19 |     100 |   92.72 | ...32,151-154,211 
  ...entPlanner.ts |   67.59 |     73.8 |      50 |   67.59 | ...31,240-243,415 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |      46 |    61.53 |   44.44 |      46 | ...05,212,215-347 
  indexer.ts       |    86.3 |       50 |     100 |    86.3 | ...56,62-63,75-76 
  manager.ts       |    75.5 |    81.04 |    75.6 |    75.5 | ...1292,1305-1307 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   79.06 |    95.12 |     100 |   79.06 | 32-33,49-86       
  prompt.ts        |   94.87 |    78.57 |     100 |   94.87 | ...63,166,304-305 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  ...ceSelector.ts |   93.02 |    81.81 |     100 |   93.02 | ...24,126-127,135 
  scan.ts          |   92.92 |    73.91 |     100 |   92.92 | ...51-52,62,90-91 
  ...entPlanner.ts |   58.33 |    66.66 |   56.25 |   58.33 | ...61-282,358-403 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   93.33 |    81.25 |     100 |   93.33 | ...,94-95,119-120 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   79.38 |    78.33 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.98 |    87.37 |   88.15 |   89.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.24 |    91.42 |     100 |   90.24 | 142,148,151-160   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.66 |    92.85 |     100 |   98.66 | 162,324,330       
  modelRegistry.ts |     100 |    98.63 |     100 |     100 | 229               
  modelsConfig.ts  |   86.24 |    85.23 |   82.92 |   86.24 | ...1328,1357-1358 
  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   |   82.66 |    91.91 |   68.46 |   82.66 |                   
  autoMode.ts      |   97.84 |    94.27 |     100 |   97.84 | 523-524,545-552   
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |   93.95 |    94.44 |     100 |   93.95 | 158-165,383-387   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   84.86 |     89.1 |      80 |   84.86 | ...1024,1130-1134 
  rule-parser.ts   |   97.39 |    93.82 |     100 |   97.39 | ...-882,1031-1033 
  ...-semantics.ts |   70.33 |    90.79 |   46.66 |   70.33 | ...2237,2300-2303 
  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 | 219               
 src/plan-gate     |    79.3 |    92.75 |   81.25 |    79.3 |                   
  ...viewAgents.ts |   56.02 |    88.46 |   66.66 |   56.02 | ...09-175,197-198 
  ...provalGate.ts |      95 |    95.12 |    87.5 |      95 | 164-165,252-258   
  state.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 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     |   79.48 |    64.39 |   64.28 |   79.48 |                   
  all-providers.ts |      68 |      100 |       0 |      68 | 68-69,73-79,83-89 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   98.88 |    87.27 |     100 |   98.88 | 274-275           
  ...der-config.ts |   69.73 |    47.29 |   68.42 |   69.73 | ...10-411,418-427 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.31 |    86.36 |      50 |   97.31 |                   
  ...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.01 |    81.25 |      75 |   97.01 | 120-121           
  deepseek.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 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |    85.3 |     78.8 |   95.89 |    85.3 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.55 |    73.71 |   90.62 |   82.55 | ...1183-1199,1229 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/services      |   87.26 |    84.21 |   93.72 |   87.26 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.35 |    85.34 |     100 |   97.35 | ...94,117,417-418 
  ...ionService.ts |   96.45 |    94.44 |     100 |   96.45 | ...34,650,779-787 
  ...ingService.ts |    84.2 |    81.92 |   83.33 |    84.2 | ...1438,1453-1454 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |     100 |    97.43 |     100 |     100 | 215,268           
  cronScheduler.ts |   94.18 |     88.6 |     100 |   94.18 | ...-774,1034-1035 
  cronTasksFile.ts |   93.97 |    83.63 |     100 |   93.97 | ...82-183,192-193 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   80.43 |    95.45 |      75 |   80.43 | ...19-134,140-141 
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   91.27 |    82.69 |    90.9 |   91.27 | ...94,196,294-301 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    69.4 |    68.82 |   93.33 |    69.4 | ...2064,2092-2093 
  ...ionService.ts |   98.86 |    98.09 |     100 |   98.86 | 368-369,416-417   
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   96.06 |    91.48 |   96.96 |   96.06 | ...49,850,864-866 
  ...orRegistry.ts |   97.26 |    91.22 |     100 |   97.26 | ...50-451,605-606 
  ...ttachments.ts |   97.24 |    90.39 |     100 |   97.24 | ...08,646,661-662 
  sessionRecap.ts  |     9.7 |      100 |       0 |     9.7 | 44-174            
  ...ionService.ts |   87.31 |    79.37 |   94.44 |   87.31 | ...1483,1553-1573 
  sessionTitle.ts  |   93.87 |    71.15 |     100 |   93.87 | ...33-236,267-268 
  ...ionService.ts |      83 |    79.17 |   90.47 |      83 | ...2103,2109-2114 
  ...pInhibitor.ts |   97.02 |    90.74 |     100 |   97.02 | ...14-115,289-290 
  ...Estimation.ts |     100 |    86.66 |     100 |     100 | 96-97             
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...oryService.ts |   89.03 |    65.38 |     100 |   89.03 | ...23-325,330-331 
  ...reeCleanup.ts |   14.56 |      100 |   33.33 |   14.56 | 58-185            
  ...ionService.ts |   84.21 |    79.41 |     100 |   84.21 | ...18-219,235-236 
 ...icrocompaction |   98.76 |    92.85 |     100 |   98.76 |                   
  microcompact.ts  |   98.76 |    92.85 |     100 |   98.76 | ...24,432,436,571 
 src/skills        |   88.14 |    86.62 |      90 |   88.14 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   83.39 |    81.42 |   82.35 |   83.39 | ...1199,1206-1210 
  skill-paths.ts   |   89.15 |    86.36 |     100 |   89.15 | ...00-101,106-107 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |       98 |     100 |   97.91 | 277-278           
 src/subagents     |   85.84 |    85.55 |   94.33 |   85.84 |                   
  ...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 |    81.2 |    79.93 |   91.17 |    81.2 | ...1432,1509-1510 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   78.56 |    87.65 |   80.33 |   78.56 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   98.96 |    79.48 |     100 |   98.96 | 169,183           
  ...on-tracing.ts |   74.55 |    73.21 |   70.58 |   74.55 | ...95,336-338,354 
  ...attributes.ts |   98.13 |       88 |     100 |   98.13 | 185-187           
  ...-exporters.ts |   46.37 |      100 |   44.44 |   46.37 | ...85,88-89,92-93 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.09 |    95.61 |      95 |   99.09 | 141,365-366       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   54.08 |    65.85 |   60.86 |   54.08 | ...1250,1267-1287 
  metrics.ts       |   75.31 |    80.85 |   77.19 |   75.31 | ...1021,1024-1035 
  ...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       
  sdk.ts           |   86.75 |     88.4 |   66.66 |   86.75 | ...17-621,659-681 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.04 |    87.94 |   96.55 |   90.04 | ...1504,1535-1538 
  ...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         |   79.46 |    93.91 |   84.21 |   79.46 | ...1241,1244-1273 
  uiTelemetry.ts   |      92 |    95.34 |   80.95 |      92 | ...00,206-216,244 
 ...ry/qwen-logger |   68.17 |     80.2 |   65.51 |   68.17 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.17 |       80 |   64.91 |   68.17 | ...1077,1115-1116 
 src/test-utils    |   93.44 |    96.15 |   77.77 |   93.44 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   91.71 |    97.36 |   74.19 |   91.71 | ...54,218-219,232 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   79.99 |    82.22 |   85.97 |   79.99 |                   
  ...erQuestion.ts |   90.03 |    79.36 |   91.66 |   90.03 | ...99-400,407-408 
  cron-create.ts   |   88.18 |    93.33 |    62.5 |   88.18 | ...,45-46,177-185 
  cron-delete.ts   |   97.53 |      100 |   83.33 |   97.53 | 31-32             
  cron-list.ts     |   97.82 |    95.45 |   83.33 |   97.82 | 30-31             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   80.82 |    83.48 |      75 |   80.82 | ...08-709,819-869 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |   90.69 |       75 |   85.71 |   90.69 | 55-56,74-79       
  exit-worktree.ts |   84.23 |    85.96 |   91.66 |   84.23 | ...92-293,298-312 
  exitPlanMode.ts  |   82.89 |    77.35 |     100 |   82.89 | ...63-375,387-390 
  glob.ts          |   90.63 |    88.33 |   84.61 |   90.63 | ...28,171,302,305 
  grep.ts          |   79.04 |    85.71 |      75 |   79.04 | ...73-580,604-605 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.77 |    60.09 |   90.32 |   72.77 | ...1211,1213-1214 
  ...nt-manager.ts |   80.51 |     78.4 |   84.44 |   80.51 | ...2981,2983-2984 
  mcp-client.ts    |      43 |    87.57 |      75 |      43 | ...1790,1794-1797 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   77.21 |    83.96 |   79.41 |   77.21 | ...1259,1267-1268 
  ...ool-events.ts |       8 |      100 |       0 |       8 | 123-149           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 175-176           
  mcp-tool.ts      |   91.36 |    89.32 |   96.55 |   91.36 | ...40-641,691-692 
  ...sport-pool.ts |   83.27 |       80 |   84.61 |   83.27 | ...1399,1406-1410 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-47              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   91.65 |    84.05 |   88.46 |   91.65 | ...87,600,796-801 
  notebook-edit.ts |   85.11 |    76.42 |   81.25 |   85.11 | ...54-870,916-917 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   82.57 |    89.74 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   94.75 |    90.32 |   81.81 |   94.75 | ...02,305,388-389 
  ripGrep.ts       |   94.17 |    85.71 |    87.5 |   94.17 | ...96-497,547-548 
  ...-transport.ts |    6.34 |      100 |       0 |    6.34 | 47-145            
  send-message.ts  |   79.48 |    86.95 |    62.5 |   79.48 | ...97-203,286-294 
  ...n-mcp-view.ts |   92.37 |    93.54 |   88.88 |   92.37 | 118-126           
  shell.ts         |   76.79 |    81.56 |   91.11 |   76.79 | ...4716,4775-4776 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |    89.4 |     92.5 |   88.88 |    89.4 | ...43,447,476-498 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |   93.85 |     92.3 |   81.81 |   93.85 | 41-45,59-60,91    
  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   |   80.67 |       78 |    92.3 |   80.67 | ...75-383,415-426 
  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 
  todoWrite.ts     |   89.27 |    82.05 |   92.85 |   89.27 | ...50-555,577-578 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   76.19 |     76.1 |   81.39 |   76.19 | ...53-854,862-863 
  tool-search.ts   |   92.35 |    85.84 |    92.3 |   92.35 | ...08-213,320-329 
  tools.ts         |   92.36 |    90.74 |   90.47 |   92.36 | ...99-500,516-522 
  web-fetch.ts     |   88.84 |       80 |   92.85 |   88.84 | ...12-313,315-316 
  write-file.ts    |   82.65 |    80.45 |   84.61 |   82.65 | ...65-668,696-731 
 src/tools/agent   |   76.31 |    84.65 |   76.66 |   76.31 |                   
  agent.ts         |   76.53 |    84.86 |    77.1 |   76.53 | ...3091,3118-3181 
  fork-subagent.ts |   71.08 |       75 |   71.42 |   71.08 | ...25-126,161-172 
 ...s/computer-use |   90.03 |    81.27 |   75.36 |   90.03 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   73.22 |    89.65 |   64.28 |   73.22 | ...70-172,233-242 
  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.24 |    85.29 |     100 |   96.24 | 75-76,184,251-257 
 ...tools/workflow |   85.51 |    79.01 |      90 |   85.51 |                   
  workflow.ts      |   85.51 |    79.01 |      90 |   85.51 | ...27-528,540-543 
 src/utils         |   89.69 |    88.34 |   94.24 |   89.69 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.76 |    93.26 |     100 |   94.76 | ...30-531,634-638 
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |   76.31 |    53.33 |     100 |   76.31 | ...37,43-44,65-66 
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...ncyLimiter.ts |   94.64 |    95.23 |     100 |   94.64 | 64-66             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.11 |    89.47 |     100 |   91.11 | ...46-147,154-155 
  cronDisplay.ts   |   83.33 |    81.48 |     100 |   83.33 | 44-45,47-51       
  cronParser.ts    |   93.16 |       90 |     100 |   93.16 | ...46,60-61,63-64 
  debugLogger.ts   |   96.42 |    94.11 |   88.23 |   96.42 | 185-189           
  editHelper.ts    |   93.63 |    83.52 |     100 |   93.63 | ...28-429,463-464 
  editor.ts        |    97.6 |     95.4 |     100 |    97.6 | ...25-326,328-329 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.78 |    89.13 |      95 |   96.78 | ...51-252,257,403 
  errorParsing.ts  |    97.7 |    97.05 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.54 |       80 |      50 |   70.54 | ...15-231,235-241 
  fetch.ts         |    70.8 |     77.5 |   71.42 |    70.8 | ...41-142,161,186 
  fileUtils.ts     |    91.5 |    86.13 |   95.23 |    91.5 | ...1191,1195-1201 
  forkedAgent.ts   |   80.68 |    78.12 |   83.33 |   80.68 | ...39-545,550-556 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  gitDiff.ts       |   92.36 |    79.53 |     100 |   92.36 | ...55-856,928-929 
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   72.91 |    90.32 |   83.33 |   72.91 | ...,77-78,102-153 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   88.98 |    90.66 |   91.66 |   88.98 | ...46-349,359-365 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.01 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   93.77 |    89.02 |     100 |   93.77 | ...13-319,406-407 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  modelId.ts       |   98.96 |    98.18 |     100 |   98.96 | 153               
  ...kerChecker.ts |   90.78 |    91.66 |     100 |   90.78 | 73-79             
  notebook.ts      |   94.57 |    89.83 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   90.85 |    87.87 |     100 |   90.85 | ...97-199,222-227 
  partUtils.ts     |     100 |    98.61 |     100 |     100 | 206               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.21 |    91.95 |     100 |   93.21 | ...89-390,392-394 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  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 |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   93.75 |    88.34 |     100 |   93.75 | ...13,218-219,262 
  readManyFiles.ts |   87.59 |       84 |     100 |   87.59 | ...09-211,227-238 
  retry.ts         |   95.93 |    91.83 |     100 |   95.93 | ...33,524-525,543 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.52 |    96.84 |     100 |   97.52 | ...05,255-256,282 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   46.79 |    83.33 |   66.66 |   46.79 | ...45-246,258-335 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   82.18 |    85.18 |   95.23 |   82.18 | ...24,549,578-587 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |    97.5 |    88.57 |     100 |    97.5 | 162-163           
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    88.23 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   91.97 |    83.42 |     100 |   91.97 | ...44,866-867,880 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  sedEditParser.ts |   91.72 |    92.12 |     100 |   91.72 | ...36-539,615-616 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   96.89 |    85.84 |     100 |   96.89 | ...51,367,447,466 
  shell-utils.ts   |   84.39 |    90.46 |     100 |   84.39 | ...1583,1590-1594 
  ...lAstParser.ts |   95.57 |    85.88 |     100 |   95.57 | ...1066-1068,1078 
  ...ContextEnv.ts |     100 |      100 |     100 |     100 |                   
  ...nlyChecker.ts |   95.08 |    91.66 |     100 |   95.08 | ...15-316,324-325 
  sideQuery.ts     |   86.17 |    86.53 |     100 |   86.17 | ...55-161,163-169 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   81.48 |       75 |     100 |   81.48 | 54-59             
  ...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 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  ...ultCleanup.ts |   15.45 |    33.33 |      25 |   15.45 | 33-136            
  truncation.ts    |   75.31 |    85.71 |   71.42 |   75.31 | ...49-454,458-482 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   95.81 |    89.39 |     100 |   95.81 | ...74-275,299-301 
  xml.ts           |    97.8 |     87.5 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    73.84 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.58 |    81.02 |   94.28 |   83.58 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   83.07 |    77.74 |   94.82 |   83.07 | ...1468,1502-1503 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...70-271,273-274 
  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 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |     92.3 |     100 |     100 | 46                
 ...uest-tokenizer |   65.76 |    73.38 |   80.64 |   65.76 |                   
  ...eTokenizer.ts |    59.8 |    73.13 |   84.61 |    59.8 | ...50-451,464-518 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |      76 |      100 |   33.33 |      76 | 45-48,55-56       
  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.

@LaZzyMan
LaZzyMan requested a review from wenshao June 17, 2026 06:40

@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.

Qwen Code Review — PR #5231

Reviewer: Qwen Code (automated) · Model: qwen3.7-max
Approach: Multi-agent adversarial review (9 parallel agents) + 2-round reverse audit convergence

Summary

This PR adds a per-run output-token budget for the Workflow tool (P5 of Dynamic Workflows port). The implementation is well-structured and the PR description is thorough. Tests cover the happy paths well (175 tests passing). The review identified 4 critical issues and 7 suggestions — the critical items are token-tracking gaps in the orchestrator that could lead to budget gate bypass or silent undercounting.

Findings

Critical (4):

  1. Schema-mode success path missing onTokens — structured-output agents never report tokens
  2. Budget gate bypassed by parallel() batch — overshoot can be N× worse than documented
  3. Failed/timed-out/cancelled agents' tokens never recorded — budget undercounts
  4. No debugLogger call when budget gate rejects — diagnostic gap

Suggestions (7):
5. resolveUsageBanner JSDoc says "BOTH paths" but only called from success
6. perPhaseTokens null sentinel not surfaced in /workflows detail or phase tree UI
7. Token counts as raw integers vs formatTokenCount — inconsistent formatting
8. onBudgetUpdated fires emitStatusChange unconditionally on no-op mutations
9. No test for concurrent fan-out overshoot behavior
10. Capped banner shape (total !== null) never tested
11. Final display vs live display tokens condition inconsistent

Low-confidence finding omitted: duplicated budget chip formatting (only 2 sites, acceptable)

Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts Outdated
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/tools/workflow/workflow.ts
Comment thread packages/cli/src/ui/commands/workflowsCommand.ts Outdated
Comment thread packages/core/src/agents/workflow-run-registry.ts
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/tools/workflow/workflow.ts
Comment thread packages/core/src/tools/workflow/workflow.ts Outdated
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

P5 E2E test report

Real-LLM end-to-end verification of the P5 changes against a live qwen3.7-plus model on DashScope. Three test groups: real-LLM tmux real-scenario, real-LLM headless JSON, and full unit/integration sweep. All passing.

Environment

Item Value
Binary node dist/cli.js from local npm run bundle of branch lazzy/workflow-p5-budget @ d82c02065
Model qwen3.7-plus (DashScope compatible-mode endpoint)
Auth --auth-type openai --openai-base-url https://dashscope.aliyuncs.com/compatible-mode/v1 --openai-api-key sk-…
Workflows gate QWEN_CODE_ENABLE_WORKFLOWS=1
Approval mode yolo
OS macOS Darwin 25.5.0 (CI matrix covers Linux + Windows for unit suites)

Group 1: tmux real-scenario (P5 surfaces in the live TUI)

Started a fresh tmux session, pointed the binary at a clean /tmp/p5-tmux git repo, drove the model through three interactions: workflow success → /workflows listing → /workflows <runId> detail → second workflow run (banner suppression).

1.1 First workflow call — banner appears

> Use the Workflow tool to run this exact script and return its result:
  phase('Plan'); log('hello'); return 'world';

✦ The user wants me to run a workflow script using the Workflow tool. Let me find and load that tool first.
✓ ToolSearch select:workflow
✦ Now I can call the workflow tool with the exact script the user provided.
✓ Workflow Run a workflow script (43 chars)
   > Workflows have no per-run token cap. Set `QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<n>` (env) for a soft cap. Suppress this notice with `skipWorkflowUsageWarning: true` in settings.
     "runId": "wf_0136708878ab3b07",
       "Plan",
       "hello",
     "result": "world"
✦ The workflow returned 'world' as expected.
✦ The workflow executed successfully and returned: `world`

Verified:

  • Banner appears verbatim in returnDisplay, prepended before the JSON code block.
  • Banner mentions both knobs: QWEN_CODE_MAX_TOKENS_PER_WORKFLOW and skipWorkflowUsageWarning.
  • The run is registered (wf_0136708878ab3b07) and reaches result: "world".

1.2 /workflows listing

> /workflows

Workflow runs (1 total · 0 running)
Recent
  wf_0136708878ab3b07  completed       2ms  wf_0136708878ab3b07 · Plan · 1 phase

Verified:

  • Slash command is registered.
  • Listing splits Active/Recent buckets (no active here because the run finished).
  • Row format: runId | status | runtime | label · currentPhase · phaseCount. Budget chip is correctly omitted because the script had no agent() dispatches and no cap was set.

1.3 /workflows <runId> detail

> /workflows wf_0136708878ab3b07

● Workflow wf_0136708878ab3b07
    status      : completed
    runtime     : 2ms
    agents      : 0/0
    tokens      : 0
    cap         : (no cap)
    Phases (1)
      · Plan

Verified:

  • tokens: 0 line is rendered (P5 surface).
  • cap: (no cap) line is rendered (P5 surface, uncapped state explicit).
  • Phases (1) block with phase tree (· Plan).

1.4 Second workflow call — banner suppressed (latch consumed)

> Call the Workflow tool again with script: "return 'second-run';" — please just one tool call.

✓ Workflow Run a workflow script (20 chars)
    "runId": "wf_2dcc20743737dda3",
    "result": "second-run"

Verified:

  • Second workflow tool call works.
  • returnDisplay for the second run does NOT contain the banner.
  • Across the full tmux scrollback, grep -cE "Workflows have no per-run|skipWorkflowUsageWarning" returns exactly 1 — confirming the latch on WorkflowRunRegistry.shouldShowUsageWarning() fires once per session as designed.

Group 2: real-LLM headless --output-format json

Single workflow invocation in headless mode to confirm the banner is also present in the structured stream consumed by non-TUI clients.

QWEN_CODE_ENABLE_WORKFLOWS=1 node /Users/.../dist/cli.js \
  "Call the Workflow tool to run script: phase('Plan'); log('hello'); return 'world'; — no args, just the script." \
  --approval-mode yolo \
  --auth-type openai \
  --openai-api-key sk-... \
  --openai-base-url https://dashscope.aliyuncs.com/compatible-mode/v1 \
  --model qwen3.7-plus \
  --output-format json

Captured assistant tool call + tool_result events:

TOOL_USE: workflow
  input keys: ['script']
  script: phase('Plan'); log('hello'); return 'world';

TOOL_RESULT (is_error=False):
  > Workflows have no per-run token cap. Set `QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<n>` (env) for a soft cap. Suppress this notice with `skipWorkflowUsageWarning: true` in settings.

  ```json
  {
    "runId": "wf_b7c9a79ddb446fc3",
    "phases": ["Plan"],
    "logs": ["hello"],
    "result": "world"
  }

TEXT: Workflow executed successfully — returned world.
RESULT: Workflow executed successfully — returned world.
duration=10888ms tools=1


Verified:
- Exit code 0.
- `tool_result.is_error = False`.
- `tool_result.content` contains the full banner text + the display JSON.
- The script's return value (`"world"`) reaches the final assistant message via `llmContent`.

## Group 3: unit + integration sweep

All workflow-touching suites green.

### 3.1 Core workflow suites (272 tests)

```bash
cd packages/core && npx vitest run --no-coverage \
  src/agents/runtime/workflow-budget.test.ts \
  src/agents/runtime/workflow-orchestrator.test.ts \
  src/agents/runtime/workflow-sandbox.test.ts \
  src/tools/workflow/workflow.test.ts \
  src/agents/workflow-run-registry.test.ts
✓ src/agents/runtime/workflow-budget.test.ts (18 tests)
✓ src/agents/workflow-run-registry.test.ts (29 tests)
✓ src/tools/workflow/workflow.test.ts (27 tests)
✓ src/agents/runtime/workflow-orchestrator.test.ts (91 tests)
✓ src/agents/runtime/workflow-sandbox.test.ts (107 tests)

Test Files  5 passed (5)
     Tests  272 passed (272)
  Duration  30.96s

Of the 272 total, the 20 new P5 tests are:

Suite New Coverage
workflow-budget.test.ts 18 resolveMaxTokensPerWorkflow (env unset/empty/non-int/negative/0/clamp), WorkflowBudgetImpl (recordSpent monotonic, remaining() clamps at 0, null total → Infinity, NaN/negative deltas dropped), WorkflowBudgetExceededError (carries runId/budgetTotal/spent, name field)
workflow-orchestrator.test.ts 8 Budget gate exhausted → throw, mid-run overshoot stops at boundary, null total = no gate, no budget = legacy callers unaffected, budgetUpdated emitter fires per success with cumulative spent + total, never on rejection, no fire when budget omitted, subscriber error swallowed
workflow-run-registry.test.ts 10 Register initializes new fields, register seeds tokenBudgetTotal from caller cap, onBudgetUpdated mutates spent + total, per-phase attribution to currentPhase, null-phase sentinel for pre-phase agents, no-op on missing/terminal entries, backwards/zero deltas ignored, fires statusChange, latch one-shot, latch survives reset()
workflow.test.ts 4 Banner appears on first success, banner suppressed by skipWorkflowUsageWarning, failure-path does NOT emit banner or consume latch + status='failed', failed-then-success → banner on the success run

3.2 CLI surface suites (42 tests)

cd packages/cli && npx vitest run --no-coverage \
  src/ui/commands/workflowsCommand.test.ts \
  src/ui/components/background-view/BackgroundTasksDialog.test.tsx
✓ src/ui/commands/workflowsCommand.test.ts (10 tests)
✓ src/ui/components/background-view/BackgroundTasksDialog.test.tsx (32 tests)

Test Files  2 passed (2)
     Tests  42 passed (42)

Of the 42 total, the 4 new P5 tests in workflowsCommand.test.ts:

  • List row chips tokens/cap when capped (1500/10000t)
  • List row chips plain spent when uncapped (500t, no slash)
  • Detail view renders tokens / cap / per-phase chips (· Find · 300t, · Verify · 150t)
  • Detail view renders cap: (no cap) when uncapped

3.3 Sibling-drift / regression suites (35 tests)

The memory config_method_test_mock_drift.md recorded that adding a Config method requires stubbing it in every CLI mock — verified no regression by running the suites that exercise mock Configs:

cd packages/cli && npx vitest run --no-coverage \
  src/services/BuiltinCommandLoader.test.ts \
  src/ui/commands/clearCommand.test.ts \
  src/ui/hooks/useResumeCommand.test.ts
✓ src/ui/hooks/useResumeCommand.test.ts (9 tests)
✓ src/ui/commands/clearCommand.test.ts (15 tests)
✓ src/services/BuiltinCommandLoader.test.ts (11 tests)

Test Files  3 passed (3)
     Tests  35 passed (35)

getSkipWorkflowUsageWarning() is invoked as this.config.getSkipWorkflowUsageWarning?.() (optional call), so a missing method on a mock Config returns undefined!undefined = true (safe-default banner-on path). Confirmed by these tests passing without any mock updates.

3.4 Typecheck + lint

cd packages/core && npx tsc --noEmit
cd packages/cli && npx tsc --noEmit

Clean for workflow-related files. (Pre-existing acp-integration/* errors on this branch base — unrelated to P5.)

npx eslint <14 touched files>

Clean.

Self-review pass — 2 bugs caught and fixed before push

Adversarial Explore sweep before opening the PR. Two real issues caught in my own implementation:

  1. "hard ceiling" docstring drift — the cap is a soft gate (overshoots up to (concurrency_window − 1) × per_dispatch_tokens), but the docstring + banner copy said "hard ceiling". Softened both to "soft cap" with the overshoot bound documented in the workflow-budget.ts threat-model block.
  2. Failure-path banner self-inflicted regression — initial attempt fired the banner on the failure path too. Inspecting coreToolScheduler.ts:801: when result.error is set, createErrorResponse hard-codes resultDisplay = error.message, dropping any custom returnDisplay. The banner would have been invisible AND would have silently consumed the registry latch, causing the next successful run to skip the banner too. Reverted. Failure path no longer touches the latch; new test P5 T7 R1: failure path does NOT emit banner or consume the latch and P5 T7 R1: failed-then-succeeded → banner appears on the SUCCESS run asserts the contract.

Also clarified: QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=0 is treated as unset (no cap) — operators wanting "no workflows at all" should use QWEN_CODE_DISABLE_WORKFLOWS=1.

Coverage summary

Reported by the CI Code Coverage Summary job:

Package Lines Statements Functions Branches
CLI 76.47% 76.47% 80.35% 79.74%
Core 82.42% 82.42% 84.11% 84.01%

(Coverage delta from P5 changes: new workflow-budget.ts is 100% covered by its colocated test file; new WorkflowTool banner / budget paths and registry onBudgetUpdated / shouldShowUsageWarning paths all covered by the 20 new P5 unit tests.)

@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

@qwen-code-ci-bot PR body restructured under the template headings (What this PR does / Why it's needed / Reviewer Test Plan with How to verify + Evidence + Tested on + Environment / Risk & Scope / Linked Issues / 中文说明 block) via gh pr edit --body. The full E2E test report (tmux real-scenario + headless JSON + unit/integration sweeps) is posted as the previous comment for the reviewer's reference. No code change in this round.

LaZzyMan added a commit that referenced this pull request Jun 17, 2026
…ish (PR #5231)

Addresses 4 Critical + 7 Suggestions from qwen-code-ci-bot's multi-agent review:

Critical fixes (orchestrator core):
- #1 (workflow-orchestrator.ts): schema-mode success path was missing the
  onTokens call entirely, so structured-output agents never recorded
  against the budget. Lifted the token report to a single `reportTokens`
  helper invoked once after `subagent.execute()` returns, BEFORE the
  schema/non-schema branch. Both fast-path and override-path dispatch
  now hit the same reporting site regardless of terminate mode.
- #2 (workflow-orchestrator.ts): the entry budget gate in countedDispatch
  was bypassed by `parallel()` batches — all N thunks fire-check-queue
  in a single microtask burst with spent=0, so every queued dispatch
  passed the gate before any could record tokens. Added a SECOND gate
  inside the limiter.run callback so queued thunks observe budget
  mutations from already-completed in-flight dispatches at slot-acquire
  time, restoring the documented overshoot bound of
  (concurrency_window - 1) × per_dispatch_tokens (previously up to
  N × per_dispatch_tokens for a single `parallel()` of N items).
- #3 (workflow-orchestrator.ts): CANCELLED / TIMEOUT / MAX_TURNS / ERROR
  terminations threw without recording tokens, so failed dispatches
  burned budget silently. Same `reportTokens` lift fixes this — tokens
  are now read before the terminate-mode check on both paths.
- #4 (workflow-orchestrator.ts): added debugLogger.warn at both gate
  sites (entry + intra-limiter) for budget-rejected dispatches.

Suggestion fixes:
- #5 (workflow.ts): `resolveUsageBanner` JSDoc still said "Called from
  BOTH the success and failure paths" after the earlier failure-path
  revert. Corrected to "SUCCESS path only" with the scheduler-override
  rationale moved into the docstring.
- #6 (workflowsCommand.ts, BackgroundTasksDialog.tsx): null-sentinel
  perPhaseTokens (tokens spent before the first phase() call) was
  attributed by the registry but never rendered. Detail view + phase
  tree now surface a "(no phase)" row when the null-key bucket has
  spend.
- #7 (workflowsCommand.ts, BackgroundTasksDialog.tsx): use the existing
  `formatTokenCount` helper from `cli/ui/utils/formatters.ts` (the same
  surface statusLinePresets and TurnCard use) so token counts render as
  `1.5k / 10k` instead of raw integers.
- #8 (workflow-run-registry.ts): `onBudgetUpdated` no longer fires
  `emitStatusChange` when neither tokensSpent nor tokenBudgetTotal
  changed. Production code fires `budgetUpdated` after every successful
  dispatch including zero-output-token ones; gating the emit avoids a
  no-op UI re-render burst on those.
- #11 (workflow.ts): final returnDisplay JSON now includes the `tokens`
  block whenever any usage is reported OR a cap is set, aligned with
  `buildLivePhaseTreeDisplay` (was only included when spend > 0,
  inconsistent with the live render).

Test additions:
- workflow-budget.test.ts: unchanged (18).
- workflow-orchestrator.test.ts: +6 R1 tests (parallel-batch overshoot
  regression for #2, GOAL+CANCELLED/MAX_TURNS/TIMEOUT/ERROR token
  recording for #3 via createProductionDispatch, schema-mode success
  token recording for #1, no-onTokens crash safety). Mock subagent
  extended with getExecutionSummary + nextOutputTokens to drive these.
- workflow-run-registry.test.ts: +1 R1 test for #8 emit gating;
  rewrote the backwards/zero-delta test to the new monotonic-spent
  contract.
- workflow.test.ts: +1 R1 test for #10 (capped banner shape — was
  untested; only the uncapped shape had coverage).
- workflowsCommand.test.ts: +1 R1 test for #6 null-sentinel surfacing.
  Updated assertions for #7 formatTokenCount output (`1.5k/10kt`).

Total: 282 core tests passing (+10 R1), 43 CLI tests passing (+1 R1),
0 lint, 0 typecheck for workflow-touching files. Real-LLM tmux + JSON
E2E reconfirmed end-to-end (banner now says "soft cap", display payload
shape unchanged, run registers + completes cleanly).

#9 fold: the parallel-batch overshoot test serves as the regression
guard for the intra-limiter gate fix in #2.
#7 partial: workflowsCommand.ts and BackgroundTasksDialog.tsx are the
only two `tokens` render sites in P5; both updated. Other token-bearing
surfaces (statusLinePresets, TurnCard) already use the helper.

PR: #5231
@LaZzyMan
LaZzyMan force-pushed the lazzy/workflow-p5-budget branch from d82c020 to 6c5de81 Compare June 17, 2026 08:20
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

P5 Review Round 1 — fixed in 6c5de81d8

Thanks for the thorough multi-agent pass. All 4 Critical + 7 Suggestions were verified against current code and addressed. Summary:

Critical (4)

# Status Notes
1 — schema-mode success path missing onTokens ✅ fixed Lifted token report to a single reportTokens helper invoked once after subagent.execute() returns, BEFORE the schema/non-schema branch. Both fast path and override path now hit the same site.
2 — budget gate bypassed by parallel() batch ✅ fixed Added a SECOND gate inside the limiter.run callback so queued thunks observe budget mutations from already-completed in-flight dispatches at slot-acquire time. Overshoot bound now matches the documented (concurrency_window - 1) × per_dispatch_tokens. Regression test asserts dispatchCalls < N for parallel([N thunks]) with the cap busted mid-flight.
3 — failed/timed-out/cancelled agents' tokens not recorded ✅ fixed Same reportTokens lift covers this — tokens are read BEFORE the terminate-mode check on both paths. Added it.each test asserting CANCELLED / MAX_TURNS / TIMEOUT / ERROR each report tokens before throwing.
4 — no debugLogger call on budget rejection ✅ fixed Added debugLogger.warn at both gate sites (entry + intra-limiter).

Suggestions (7)

# Status Notes
5 — resolveUsageBanner JSDoc drift ✅ fixed JSDoc now says "SUCCESS path only" with the coreToolScheduler override rationale inline.
6 — null-sentinel perPhaseTokens not surfaced ✅ fixed /workflows <runId> detail and dialog phase tree now render (no phase) rows when the null-key bucket has spend.
7 — token counts as raw integers vs formatTokenCount ✅ fixed workflowsCommand.ts and BackgroundTasksDialog.tsx now use the existing formatTokenCount helper from cli/ui/utils/formatters.ts (same surface as statusLinePresets and TurnCard).
8 — onBudgetUpdated no-op emitStatusChange ✅ fixed Skip the emit when neither tokensSpent nor tokenBudgetTotal changed.
9 — no test for concurrent fan-out overshoot ✅ folded into #2 The new R1 #2: parallel-batch overshoot is bounded by the intra-limiter re-check test is the regression guard.
10 — capped banner shape untested ✅ fixed Added test P5 R1 #10: capped banner shape (total !== null) — sets the env override, executes a tool call, asserts the Workflow token cap is N copy AND the absence of the uncapped copy.
11 — final vs live display tokens inconsistency ✅ fixed Final returnDisplay JSON now uses the same condition as buildLivePhaseTreeDisplay (include tokens when ANY usage is reported OR a cap is set).

Test count delta

  • Core workflow suites: 272 → 282 (+10 R1 tests)
  • CLI workflow surfaces: 42 → 43 (+1 R1 test)
  • All lint + typecheck clean for workflow-touching files

E2E re-confirmation

Real-LLM tmux + headless JSON re-run against qwen3.7-plus post-R1:

  • Banner copy now reads "soft cap" instead of "hard ceiling" (matches the actual gate semantics documented in workflow-budget.ts).
  • Display payload unchanged on uncapped success path.
  • Run still registers + completes cleanly (wf_125a5ca48834059c → "r1-ok").

The branch was rebased onto current main (004b8bd15) — two commits ahead: 8069e4a84 (original P5) + 6c5de81d8 (this R1).

Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/agents/runtime/workflow-budget.ts
Comment thread packages/core/src/agents/runtime/workflow-budget.ts Outdated
LaZzyMan added a commit that referenced this pull request Jun 17, 2026
…ish (PR #5231)

Addresses 4 Critical + 7 Suggestions from qwen-code-ci-bot's multi-agent review:

Critical fixes (orchestrator core):
- #1 (workflow-orchestrator.ts): schema-mode success path was missing the
  onTokens call entirely, so structured-output agents never recorded
  against the budget. Lifted the token report to a single `reportTokens`
  helper invoked once after `subagent.execute()` returns, BEFORE the
  schema/non-schema branch. Both fast-path and override-path dispatch
  now hit the same reporting site regardless of terminate mode.
- #2 (workflow-orchestrator.ts): the entry budget gate in countedDispatch
  was bypassed by `parallel()` batches — all N thunks fire-check-queue
  in a single microtask burst with spent=0, so every queued dispatch
  passed the gate before any could record tokens. Added a SECOND gate
  inside the limiter.run callback so queued thunks observe budget
  mutations from already-completed in-flight dispatches at slot-acquire
  time, restoring the documented overshoot bound of
  (concurrency_window - 1) × per_dispatch_tokens (previously up to
  N × per_dispatch_tokens for a single `parallel()` of N items).
- #3 (workflow-orchestrator.ts): CANCELLED / TIMEOUT / MAX_TURNS / ERROR
  terminations threw without recording tokens, so failed dispatches
  burned budget silently. Same `reportTokens` lift fixes this — tokens
  are now read before the terminate-mode check on both paths.
- #4 (workflow-orchestrator.ts): added debugLogger.warn at both gate
  sites (entry + intra-limiter) for budget-rejected dispatches.

Suggestion fixes:
- #5 (workflow.ts): `resolveUsageBanner` JSDoc still said "Called from
  BOTH the success and failure paths" after the earlier failure-path
  revert. Corrected to "SUCCESS path only" with the scheduler-override
  rationale moved into the docstring.
- #6 (workflowsCommand.ts, BackgroundTasksDialog.tsx): null-sentinel
  perPhaseTokens (tokens spent before the first phase() call) was
  attributed by the registry but never rendered. Detail view + phase
  tree now surface a "(no phase)" row when the null-key bucket has
  spend.
- #7 (workflowsCommand.ts, BackgroundTasksDialog.tsx): use the existing
  `formatTokenCount` helper from `cli/ui/utils/formatters.ts` (the same
  surface statusLinePresets and TurnCard use) so token counts render as
  `1.5k / 10k` instead of raw integers.
- #8 (workflow-run-registry.ts): `onBudgetUpdated` no longer fires
  `emitStatusChange` when neither tokensSpent nor tokenBudgetTotal
  changed. Production code fires `budgetUpdated` after every successful
  dispatch including zero-output-token ones; gating the emit avoids a
  no-op UI re-render burst on those.
- #11 (workflow.ts): final returnDisplay JSON now includes the `tokens`
  block whenever any usage is reported OR a cap is set, aligned with
  `buildLivePhaseTreeDisplay` (was only included when spend > 0,
  inconsistent with the live render).

Test additions:
- workflow-budget.test.ts: unchanged (18).
- workflow-orchestrator.test.ts: +6 R1 tests (parallel-batch overshoot
  regression for #2, GOAL+CANCELLED/MAX_TURNS/TIMEOUT/ERROR token
  recording for #3 via createProductionDispatch, schema-mode success
  token recording for #1, no-onTokens crash safety). Mock subagent
  extended with getExecutionSummary + nextOutputTokens to drive these.
- workflow-run-registry.test.ts: +1 R1 test for #8 emit gating;
  rewrote the backwards/zero-delta test to the new monotonic-spent
  contract.
- workflow.test.ts: +1 R1 test for #10 (capped banner shape — was
  untested; only the uncapped shape had coverage).
- workflowsCommand.test.ts: +1 R1 test for #6 null-sentinel surfacing.
  Updated assertions for #7 formatTokenCount output (`1.5k/10kt`).

Total: 282 core tests passing (+10 R1), 43 CLI tests passing (+1 R1),
0 lint, 0 typecheck for workflow-touching files. Real-LLM tmux + JSON
E2E reconfirmed end-to-end (banner now says "soft cap", display payload
shape unchanged, run registers + completes cleanly).

#9 fold: the parallel-batch overshoot test serves as the regression
guard for the intra-limiter gate fix in #2.
#7 partial: workflowsCommand.ts and BackgroundTasksDialog.tsx are the
only two `tokens` render sites in P5; both updated. Other token-bearing
surfaces (statusLinePresets, TurnCard) already use the helper.

PR: #5231
@LaZzyMan
LaZzyMan force-pushed the lazzy/workflow-p5-budget branch from 6c5de81 to e7393e5 Compare June 17, 2026 09:27
LaZzyMan added a commit that referenced this pull request Jun 17, 2026
… dialog coverage (PR #5231)

3 real findings from qwen-code-ci-bot's round 2 review (the other 11
findings on the same review were already addressed by R1 commit
6c5de81 — the bot used a stale snapshot that did not include R1).

Fixes:
- #12 (workflow.ts): every dispatch completion produced TWO
  `safeEmitUpdate` calls — once in the `agentCompleted` handler, once in
  the `budgetUpdated` handler that fires right after. Over a 1000-agent
  workflow that's 2000 TUI redraws when 1000 suffices. Dropped the
  `safeEmitUpdate` call from the `agentCompleted` handler and kept it
  in `budgetUpdated`; the orchestrator fires the two events
  back-to-back, so the deferred render shows both updates atomically.
  Production `WorkflowTool.execute()` always wires
  `WorkflowBudgetImpl.fromEnv()`, so `budgetUpdated` always fires —
  test paths that omit budget use the injected dispatch shape and
  don't exercise this emitter wiring.
- #14 (workflow-budget.ts): the WorkflowBudgetExceededError message
  carried an advisory tail — "Increase QWEN_CODE_MAX_TOKENS_PER_WORKFLOW
  or unset it to remove the cap" — that reaches the LLM via
  `tool_result`. The model could surface this to the user and
  effectively coach them to remove the operator-set budget policy.
  Trimmed to the factual portion only. Operators can still find the
  env knob via the `debugLogger.warn` at both gate sites that names
  `MAX_TOKENS_PER_WORKFLOW_ENV` verbatim.
- #15 (BackgroundTasksDialog.test.tsx): WorkflowDetailBody had no
  rendering test coverage. Added 4 cases under a new R2 #15 describe:
  capped M/N chip with per-phase tally, uncapped plain-spent + zero-
  chip suppression, hidden chip when both spend and cap are zero/null,
  and null-sentinel `(no phase)` row.

Declined / declined-with-counter-evidence:
- #13 (workflow-budget.ts threat-model docstring): bot claimed the
  overshoot bound is off-by-one — `concurrency_window × per_dispatch`
  rather than `(concurrency_window - 1) × per_dispatch`. The latter is
  the correct tighter upper bound: when the gate first tips, the
  tipping dispatch's own tokens are already counted in `spent`, and
  only `concurrency_window - 1` other in-flight dispatches remain to
  add overshoot. The looser bound the bot suggests would mislead
  operators into oversized safety margins.

Test count: 282 → 283 core (+1 R2 #14 negative assertion), 42 → 47 CLI
(+5 R2 #15 + null-sentinel coverage). 0 lint, 0 typecheck for
workflow-touching files.

PR: #5231
@LaZzyMan

LaZzyMan commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator Author

P5 Review Round 2 — summary

Triage outcome of the 15 inline findings on the round-2 review: 11 already addressed by R1 commit 8e08d699f (bot used a snapshot from before the R1 push) + 3 fixed in R2 commit e7393e5bb + 1 declined with counter-evidence.

R2 commit e7393e5bb (rebased onto current main)

Finding Status Change
#12agentCompleted + budgetUpdated doubled UI re-renders ✅ fixed Dropped safeEmitUpdate from the agentCompleted handler; budgetUpdated fires immediately after and now drives a single atomic render. Halves UI re-renders per dispatch (1000-agent run: 2000 → 1000 redraws).
#14WorkflowBudgetExceededError advisory tail coaches LLM to disable cap ✅ fixed Trimmed message to factual portion only: Workflow <runId> exceeded the token budget (<spent> / <total> output tokens spent).. Env-knob discoverability preserved via debugLogger.warn at both gate sites. Test asserts the trim.
#15WorkflowDetailBody budget chip has no test coverage ✅ fixed Added 4 cases under WorkflowDetailBody budget chip (R2 #15): capped M/N + per-phase tally, uncapped plain-spent + zero-chip suppression, hidden chip when both are zero/null, null-sentinel (no phase) row.
#13 — overshoot bound claimed off-by-one ❌ declined The documented (concurrency_window − 1) × per_dispatch is the correct tighter upper bound: when the gate tips, the tipping dispatch's tokens are already in spent; only concurrency_window − 1 other in-flight dispatches contribute unaccounted overshoot. Full walkthrough in the per-thread reply.

R1 commit 8e08d699f re-affirmed (11 findings already addressed)

The bot's round-2 review pinned commit d82c0206 (the original P5 commit), missing R1. Each affected thread now has a per-thread reply citing the R1 fix location:

Test count

Branch state

Rebased onto current main (14e6ae8c2); 3 commits ahead:

  • cb2e02e3a original P5
  • 8e08d699f R1 (10 R1 tests + R1 fixes)
  • e7393e5bb R2 (this commit)

All 15 threads resolved.

Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/agents/workflow-run-registry.ts
Comment thread packages/core/src/agents/runtime/workflow-budget.ts
Comment thread packages/core/src/agents/workflow-run-registry.ts
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts Outdated
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Local build + real-test verification (maintainer)

Verified PR head e7393e5bba in an isolated worktree. No commits have landed since my CHANGES_REQUESTED review (2026-06-17 14:01 UTC; all three PR commits are dated 09:27 UTC), so this is the exact tree I flagged — the verification below double-checks both that the feature works and whether my earlier Critical finding still stands.

Verdict: the feature is solid and works end-to-end in a real binary, and every claimed suite is green. But the one Critical finding from my review — token accounting is bypassed on the execute()-throws path — is real and still open. I reproduced it deterministically and confirmed the ~6-line fix closes it. Recommend fixing before merge; everything else is good.


1. Build & test suites — ✅ green (counts even higher than claimed)

Step Result
npm ci exit 0
npm run build (full monorepo typecheck) exit 0
Core 5 suites (workflow-budget, workflow-orchestrator, workflow-sandbox, workflow.test, workflow-run-registry) 283 passed
CLI 2 suites (workflowsCommand, BackgroundTasksDialog) 47 passed

Minor note: the PR body states 272 / 42. Actual at HEAD is 283 / 47 (+11 / +5, presumably the R2 commit added tests after the body was written). More passing tests than claimed — not a regression, just a stale count in the description.

2. Real-TUI verification — ✅ user-facing half works in the real binary

Built node packages/cli/dist/index.js, driven in tmux against a live qwen3.7-max (YOLO), QWEN_CODE_ENABLE_WORKFLOWS=1.

Uncapped session:

  • First Workflow call — banner prepended verbatim:
    > Workflows have no per-run token cap. Set `QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<n>` (env) for a soft cap. Suppress this notice with `skipWorkflowUsageWarning: true` in settings.
    
  • /workflowsWorkflow runs (1 total · 0 running) + wf_… completed 2ms smoke · Plan · 1 phase (no budget chip — correct, 0 spent + no cap).
  • /workflows <runId>
    tokens      : 0
    cap         : (no cap)
    Phases (1)
      · Plan
    
  • Second Workflow call → banner suppressed (grep across full scrollback: Workflows have no per-run token cap count = 1). Once-per-session latch confirmed.

Capped session (QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=100):

  • Banner switches to the capped shape verbatim:
    > Workflow token cap is 100 (per `QWEN_CODE_MAX_TOKENS_PER_WORKFLOW`). Suppress this notice with `skipWorkflowUsageWarning: true` in settings.
    
  • /workflows row chips the cap: wf_… completed 1ms capped · Plan · 1 phase · 0/100t.

3. 🔴 Critical (re-confirmed, still open): token accounting bypassed when execute() throws

This is the finding from my review. It is not addressed at the current head, and I now have a deterministic runtime repro.

The gap. reportTokens(...) runs on the line after await subagent.execute(...) at both dispatch sites (workflow-orchestrator.ts:359 default path, :644 override path) — not in a finally. In production the ERROR terminate mode is reached by execute() re-throwing:

agent-headless.ts:285-294
  } catch (error) {
    this.terminateMode = AgentTerminateMode.ERROR;
    ...
    throw error;           // ← re-throws on any runReasoningLoop failure
  }

So when a dispatch errors (post-retry provider/stream failure — the common real ERROR path), control jumps past reportTokens, onTokens never fires, and budget.spent() under-counts that dispatch's burned tokens.

The PR's own test R1 #3: records tokens on ERROR failure path (still throws) passes only because its mock execute returns while getTerminateMode() yields ERROR — that models the rare !chat early-return (agent-headless.ts:224-227), not the reasoning-loop throw that produces ERROR in production.

Deterministic repro (standalone test, execute() mocked to throw — the real path):

Scenario onTokens fired?
GOAL (execute returns) [777]
ERROR via return (← the PR's test scenario) [777]
ERROR via throw (real production path) []leak

Fix-flip proof: wrapping the call so reportTokens runs in a finally flips the throw-path repro from [][777] (the test then fails on the old assertion). So the data is available — getExecutionSummary() is finalized in execute()'s own finally — the dispatch just never reads it on the throw path. The repro is non-vacuous and the fix is effective.

Why it matters: the cap exists to bound runaway runs. A flaky provider (or a script that catches and retries — a pattern the threat-model doc itself calls out) produces a stream of errored dispatches, each burning real output tokens that escape accounting → remaining() stays high → the gate never trips. The cap under-enforces in exactly the error-loop scenario it is designed to bound. CANCELLED / MAX_TURNS / TIMEOUT are unaffected (those return from execute()).

Suggested fix (both dispatch sites):

try {
  await subagent.execute(ctx, signal);
} finally {
  reportTokens(subagent, opts, onTokens); // valid on the throw path too
}

…plus a regression test where the mocked execute throws (not returns) and asserts onTokens still fired.

Standalone repro test (drop into packages/core/src/agents/runtime/ and run with vitest)
const { nextOutputTokens, nextExecuteThrows, nextTerminateMode } = vi.hoisted(() => ({
  nextOutputTokens: { value: 0 as number },
  nextExecuteThrows: { value: false as boolean },
  nextTerminateMode: { value: 'GOAL' as string },
}));

vi.mock('./agent-headless.js', () => ({
  AgentHeadless: {
    create: async () => ({
      execute: async () => {
        if (nextExecuteThrows.value)
          throw new Error('simulated provider stream error (runReasoningLoop threw)');
      },
      getFinalText: () => 'ok-text',
      getTerminateMode: () => nextTerminateMode.value,
      getExecutionSummary: () => ({ outputTokens: nextOutputTokens.value }),
    }),
  },
  ContextState: class { private s: Record<string, unknown> = {};
    get(k: string){return this.s[k];} set(k: string,v: unknown){this.s[k]=v;} },
}));

import { createProductionDispatch } from './workflow-orchestrator.js';
// ...3 cases: GOAL→[777], ERROR-via-return→[777], ERROR-via-throw→[] (the leak)

4. 🟡 Secondary (Suggestion, unchanged): agentCount gate ordering

agentCount += 1 (:1192) runs before the budget gate (:1216), and the budget-reject return sits above emitter?.agentDispatched?.() (:1232). So budget-rejected calls (a) still consume an agent-count slot, and (b) don't increment the UI's agentsDispatched. A script that catches the budget rejection and keeps calling agent() eventually trips the agentCount > maxAgents guard and throws the wrong terminal error ("exceeded the maximum of N agent() calls") when the real cause is budget exhaustion; agentCount (cap) and agentsDispatched (UI) also diverge. Low severity, but worth a fix while the Critical is being addressed: evaluate the budget gate before the increment, or decrement on reject.


Recommendation

Hold for one small turn: land the finally fix at both dispatch sites + a throw-path regression test (and ideally the agentCount reorder). Both are tiny and local. With those, this is a clean merge — the design, docs, test depth, and the user-facing surfacing are all genuinely good, and I verified the latter works end-to-end in the real binary.

🇨🇳 中文版(完整对应)

本地构建 + 真实测试验证(维护者)

在隔离 worktree 中验证了 PR head e7393e5bba。自我提交 CHANGES_REQUESTED(2026-06-17 14:01 UTC;PR 三个 commit 均为 09:27 UTC)之后没有新 commit 落地,所以这就是我当时标记的那棵树 —— 下面的验证既确认功能可用,也复核我之前那条 Critical 是否仍然成立。

结论: 功能扎实,在真实二进制里端到端可用,所有声称的测试套件全绿。但我 review 里那条 Critical —— execute() 抛错路径上 token 计账被绕过 —— 是真实存在且尚未修复的。 我做了确定性复现,并验证 ~6 行的修复能闭合它。建议合并前先修;其余都没问题。

1. 构建与测试套件 —— ✅ 全绿(数量甚至比声称的更多)

步骤 结果
npm ci exit 0
npm run build(整个 monorepo 类型检查) exit 0
Core 5 个套件 283 passed
CLI 2 个套件 47 passed

小提示:PR 正文写的是 272 / 42,HEAD 实际为 283 / 47(+11 / +5,应是 R2 commit 在正文写完后又加了测试)。通过的测试比声称的还多 —— 不是回归,只是描述里的数字陈旧了。

2. 真实 TUI 验证 —— ✅ 用户可见的那半部分在真实二进制里可用

构建 node packages/cli/dist/index.js,在 tmux 中对真实 qwen3.7-max(YOLO)驱动,QWEN_CODE_ENABLE_WORKFLOWS=1

未设上限的会话:

  • 第一次 Workflow 调用 —— banner 逐字前置:
    > Workflows have no per-run token cap. Set `QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<n>` (env) for a soft cap. Suppress this notice with `skipWorkflowUsageWarning: true` in settings.
    
  • /workflowsWorkflow runs (1 total · 0 running) + wf_… completed 2ms smoke · Plan · 1 phase(无预算 chip —— 正确,0 花费 + 无上限)。
  • /workflows <runId>
    tokens      : 0
    cap         : (no cap)
    Phases (1)
      · Plan
    
  • 第二次 Workflow 调用 → banner 被抑制(在整段 scrollback 里 grep Workflows have no per-run token cap 计数 = 1)。每会话一次的 latch 得到确认。

设上限的会话(QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=100):

  • banner 切换为「有上限」形态,逐字
    > Workflow token cap is 100 (per `QWEN_CODE_MAX_TOKENS_PER_WORKFLOW`). Suppress this notice with `skipWorkflowUsageWarning: true` in settings.
    
  • /workflows 行内 chip 出预算:wf_… completed 1ms capped · Plan · 1 phase · 0/100t

3. 🔴 Critical(复核后仍然存在):execute() 抛错时 token 计账被绕过

这就是我 review 里那条。当前 head 没有修复,我现在有了确定性运行时复现。

问题。 在两个分发点(workflow-orchestrator.ts:359 默认路径、:644 override 路径),reportTokens(...) 都写在 await subagent.execute(...)下一行 —— 不在 finally。而生产中 ERROR 这个 terminate mode 是靠 execute() 重新抛出达到的:

agent-headless.ts:285-294
  } catch (error) {
    this.terminateMode = AgentTerminateMode.ERROR;
    ...
    throw error;           // ← runReasoningLoop 任何失败都会重抛
  }

所以一次分发出错时(重试后的 provider/stream 失败 —— 常见的真实 ERROR 路径),控制流跳过 reportTokensonTokens 永不触发,budget.spent() 少算了这次分发已经烧掉的 token

PR 自己的测试 R1 #3: records tokens on ERROR failure path (still throws) 之所以能过,仅仅是因为它的 mock execute返回的、同时 getTerminateMode() 给出 ERROR —— 那模拟的是罕见的 !chat 提前返回(agent-headless.ts:224-227),不是生产中产生 ERROR 的那条 reasoning-loop 抛错路径。

确定性复现(独立测试,把 execute() mock 成抛出 —— 真实路径):

场景 onTokens 是否触发
GOAL(execute 返回) [777]
ERROR 经返回(← PR 测试模拟的场景) [777]
ERROR 经抛出(真实生产路径) []泄漏

修复翻转证明: 把这次调用包成让 reportTokens 跑在 finally 里,抛错路径的复现就从 [][777](旧断言随即失败)。说明数据本来就有 —— getExecutionSummary()execute() 自己的 finally 里已经定稿 —— 只是抛错路径上没去读它。复现非空过,修复有效。

为何重要: 这个上限的存在就是为了兜住失控的 run。一个不稳定的 provider(或一个 catch 后重试的脚本 —— 威胁模型文档自己点了这个模式)会产生一串出错的分发,每一次都烧掉真实输出 token 却逃过计账 → remaining() 一直偏高 → 闸门永不触发。上限恰恰在它被设计来兜底的「错误循环」场景下失守。CANCELLED / MAX_TURNS / TIMEOUT 不受影响(那几个是从 execute() 返回的)。

建议修复(两个分发点都改):

try {
  await subagent.execute(ctx, signal);
} finally {
  reportTokens(subagent, opts, onTokens); // 抛错路径上也成立
}

…再加一条回归测试:mock 的 execute 抛出(不是返回),断言 onTokens 仍触发。

4. 🟡 次要(Suggestion,未变):agentCount 闸门顺序

agentCount += 1:1192)跑在预算闸门(:1216之前,且预算 reject 的 return 位于 emitter?.agentDispatched?.():1232之上。于是被预算拒绝的调用:(a) 仍占掉一个 agent-count 名额;(b) 不会递增 UI 的 agentsDispatched。一个 catch 掉预算拒绝、继续调 agent() 的脚本,最终会触发 agentCount > maxAgents 守卫,抛出错误的终止错误("exceeded the maximum of N agent() calls"),而真正原因是预算耗尽;同时 agentCount(上限)与 agentsDispatched(UI)发生分歧。严重度低,但趁修 Critical 时一并处理较好:把预算闸门挪到自增之前,或在 reject 时自减。

建议

再走一个小回合:在两个分发点补上 finally 修复 + 一条抛错路径回归测试(最好把 agentCount 顺序也一并调整)。两处都很小、很局部。改完即可干净合并 —— 设计、文档、测试深度、以及用户可见的呈现都确实做得好,而后者我已在真实二进制里端到端验证可用。

Methodology: isolated git worktree off PR head e7393e5bba; npm ci + full npm run build; the exact suites from the PR's test plan; a standalone runtime repro with fix-flip proof; and a real qwen binary driven in tmux against a live model. Assisted by claude-opus-4-8 via Qwen Code.

LaZzyMan added 4 commits June 18, 2026 11:06
P5 of the Dynamic Workflows port (#4721): per-run output-token
budget for the Workflow tool, wired through the orchestrator
dispatch gate, WorkflowRunRegistry, BackgroundTasksDialog phase
tree, and the /workflows slash command. Also introduces a
one-time usage banner the first time a workflow runs in a
session, gated by the skipWorkflowUsageWarning setting.

Knobs:
  QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=<int>  env, per-run cap
  skipWorkflowUsageWarning: true           setting, suppress banner

Budget gate semantics: SOFT cap, not pre-commit reservation. Gate
is checked at dispatch entry, so concurrent fan-out
(parallel / pipeline) can overshoot by up to
(concurrency_window - 1) x per_dispatch_tokens before the first
overshoot dispatch throws WorkflowBudgetExceededError. Matches
upstream Claude Code 2.1.168 semantics. Operators sizing the cap
should subtract the overshoot margin.

Implementation:
- WorkflowBudgetImpl (workflow-budget.ts) + env resolver with
  HARD_MAX_TOKENS_CEILING=100M ceiling on the env override.
- WorkflowBudgetExceededError carries runId / budgetTotal / spent.
- countedDispatch budget gate + onTokens callback feeding
  budget.recordSpent from getExecutionSummary().outputTokens.
- WorkflowOrchestratorEmitter.budgetUpdated event; fires after
  each successful dispatch, skipped on rejection and when budget
  is null.
- WorkflowTask gains tokensSpent / tokenBudgetTotal /
  perPhaseTokens fields; WorkflowRunRegistry.onBudgetUpdated
  attributes deltas to currentPhase at fire time and re-emits
  statusChange.
- WorkflowRunRegistry.shouldShowUsageWarning latch fires once per
  registry instance; survives reset().
- WorkflowTool wires WorkflowBudgetImpl.fromEnv, threads onTokens
  into createProductionDispatch, mirrors budget into the registry
  via the emitter, and prepends the usage banner on the SUCCESS
  path only.
- WorkflowDetailBody + /workflows listing + live phase-tree render
  budget chip (tokens / cap) and per-phase token totals.

Verification (270 + 4 + 4 = 272 core + 42 cli):
- workflow-budget.test.ts (18) + workflow-orchestrator.test.ts
  (+8 P5 + budget-gate + budgetUpdated emitter)
- workflow-run-registry.test.ts (+10 P5: budget fields, latch,
  per-phase attribution, no-op on terminal entries)
- workflow.test.ts (+4 P5: banner appears once, suppressed by
  setting, failure-path latch unchanged, fail-then-success
  re-emits banner)
- workflowsCommand.test.ts (+4 P5: row chip capped/uncapped,
  detail tokens/cap/per-phase chips)
- BackgroundTasksDialog.test.tsx unchanged (32 still pass)
- Real-LLM E2E (DashScope qwen3.7-plus): tmux session driving
  Workflow tool, banner verified in returnDisplay, /workflows
  shows tokens 0 / cap (no cap) on uncapped run, banner
  suppression on 2nd run confirmed (latch consumed exactly once).

Self-review round 1 fixes:
- "hard ceiling" docstring softened to "soft cap" with
  per_dispatch x concurrency_window overshoot bound documented;
  banner copy aligned ("soft cap" instead of "hard ceiling").
- Attempted failure-path banner reverted after coreToolScheduler
  inspection: createErrorResponse hard-codes
  resultDisplay = error.message whenever result.error is set, so
  a failure-path banner would have been invisible AND would have
  silently flipped the registry latch, causing the next
  successful run to skip the banner too. Failure path now does
  not touch the latch; failure-path test asserts the
  fail-then-success run still gets the banner.
- skipWorkflowUsageWarning setting placement aligned with
  skipNextSpeakerCheck sibling under settings.model.*.
- QWEN_CODE_MAX_TOKENS_PER_WORKFLOW=0 documented as "treated as
  unset" with explicit pointer to QWEN_CODE_DISABLE_WORKFLOWS=1
  for the "no workflows at all" intent.

Refs #4721.
…ish (PR #5231)

Addresses 4 Critical + 7 Suggestions from qwen-code-ci-bot's multi-agent review:

Critical fixes (orchestrator core):
- #1 (workflow-orchestrator.ts): schema-mode success path was missing the
  onTokens call entirely, so structured-output agents never recorded
  against the budget. Lifted the token report to a single `reportTokens`
  helper invoked once after `subagent.execute()` returns, BEFORE the
  schema/non-schema branch. Both fast-path and override-path dispatch
  now hit the same reporting site regardless of terminate mode.
- #2 (workflow-orchestrator.ts): the entry budget gate in countedDispatch
  was bypassed by `parallel()` batches — all N thunks fire-check-queue
  in a single microtask burst with spent=0, so every queued dispatch
  passed the gate before any could record tokens. Added a SECOND gate
  inside the limiter.run callback so queued thunks observe budget
  mutations from already-completed in-flight dispatches at slot-acquire
  time, restoring the documented overshoot bound of
  (concurrency_window - 1) × per_dispatch_tokens (previously up to
  N × per_dispatch_tokens for a single `parallel()` of N items).
- #3 (workflow-orchestrator.ts): CANCELLED / TIMEOUT / MAX_TURNS / ERROR
  terminations threw without recording tokens, so failed dispatches
  burned budget silently. Same `reportTokens` lift fixes this — tokens
  are now read before the terminate-mode check on both paths.
- #4 (workflow-orchestrator.ts): added debugLogger.warn at both gate
  sites (entry + intra-limiter) for budget-rejected dispatches.

Suggestion fixes:
- #5 (workflow.ts): `resolveUsageBanner` JSDoc still said "Called from
  BOTH the success and failure paths" after the earlier failure-path
  revert. Corrected to "SUCCESS path only" with the scheduler-override
  rationale moved into the docstring.
- #6 (workflowsCommand.ts, BackgroundTasksDialog.tsx): null-sentinel
  perPhaseTokens (tokens spent before the first phase() call) was
  attributed by the registry but never rendered. Detail view + phase
  tree now surface a "(no phase)" row when the null-key bucket has
  spend.
- #7 (workflowsCommand.ts, BackgroundTasksDialog.tsx): use the existing
  `formatTokenCount` helper from `cli/ui/utils/formatters.ts` (the same
  surface statusLinePresets and TurnCard use) so token counts render as
  `1.5k / 10k` instead of raw integers.
- #8 (workflow-run-registry.ts): `onBudgetUpdated` no longer fires
  `emitStatusChange` when neither tokensSpent nor tokenBudgetTotal
  changed. Production code fires `budgetUpdated` after every successful
  dispatch including zero-output-token ones; gating the emit avoids a
  no-op UI re-render burst on those.
- #11 (workflow.ts): final returnDisplay JSON now includes the `tokens`
  block whenever any usage is reported OR a cap is set, aligned with
  `buildLivePhaseTreeDisplay` (was only included when spend > 0,
  inconsistent with the live render).

Test additions:
- workflow-budget.test.ts: unchanged (18).
- workflow-orchestrator.test.ts: +6 R1 tests (parallel-batch overshoot
  regression for #2, GOAL+CANCELLED/MAX_TURNS/TIMEOUT/ERROR token
  recording for #3 via createProductionDispatch, schema-mode success
  token recording for #1, no-onTokens crash safety). Mock subagent
  extended with getExecutionSummary + nextOutputTokens to drive these.
- workflow-run-registry.test.ts: +1 R1 test for #8 emit gating;
  rewrote the backwards/zero-delta test to the new monotonic-spent
  contract.
- workflow.test.ts: +1 R1 test for #10 (capped banner shape — was
  untested; only the uncapped shape had coverage).
- workflowsCommand.test.ts: +1 R1 test for #6 null-sentinel surfacing.
  Updated assertions for #7 formatTokenCount output (`1.5k/10kt`).

Total: 282 core tests passing (+10 R1), 43 CLI tests passing (+1 R1),
0 lint, 0 typecheck for workflow-touching files. Real-LLM tmux + JSON
E2E reconfirmed end-to-end (banner now says "soft cap", display payload
shape unchanged, run registers + completes cleanly).

#9 fold: the parallel-batch overshoot test serves as the regression
guard for the intra-limiter gate fix in #2.
#7 partial: workflowsCommand.ts and BackgroundTasksDialog.tsx are the
only two `tokens` render sites in P5; both updated. Other token-bearing
surfaces (statusLinePresets, TurnCard) already use the helper.

PR: #5231
… dialog coverage (PR #5231)

3 real findings from qwen-code-ci-bot's round 2 review (the other 11
findings on the same review were already addressed by R1 commit
6c5de81 — the bot used a stale snapshot that did not include R1).

Fixes:
- #12 (workflow.ts): every dispatch completion produced TWO
  `safeEmitUpdate` calls — once in the `agentCompleted` handler, once in
  the `budgetUpdated` handler that fires right after. Over a 1000-agent
  workflow that's 2000 TUI redraws when 1000 suffices. Dropped the
  `safeEmitUpdate` call from the `agentCompleted` handler and kept it
  in `budgetUpdated`; the orchestrator fires the two events
  back-to-back, so the deferred render shows both updates atomically.
  Production `WorkflowTool.execute()` always wires
  `WorkflowBudgetImpl.fromEnv()`, so `budgetUpdated` always fires —
  test paths that omit budget use the injected dispatch shape and
  don't exercise this emitter wiring.
- #14 (workflow-budget.ts): the WorkflowBudgetExceededError message
  carried an advisory tail — "Increase QWEN_CODE_MAX_TOKENS_PER_WORKFLOW
  or unset it to remove the cap" — that reaches the LLM via
  `tool_result`. The model could surface this to the user and
  effectively coach them to remove the operator-set budget policy.
  Trimmed to the factual portion only. Operators can still find the
  env knob via the `debugLogger.warn` at both gate sites that names
  `MAX_TOKENS_PER_WORKFLOW_ENV` verbatim.
- #15 (BackgroundTasksDialog.test.tsx): WorkflowDetailBody had no
  rendering test coverage. Added 4 cases under a new R2 #15 describe:
  capped M/N chip with per-phase tally, uncapped plain-spent + zero-
  chip suppression, hidden chip when both spend and cap are zero/null,
  and null-sentinel `(no phase)` row.

Declined / declined-with-counter-evidence:
- #13 (workflow-budget.ts threat-model docstring): bot claimed the
  overshoot bound is off-by-one — `concurrency_window × per_dispatch`
  rather than `(concurrency_window - 1) × per_dispatch`. The latter is
  the correct tighter upper bound: when the gate first tips, the
  tipping dispatch's own tokens are already counted in `spent`, and
  only `concurrency_window - 1` other in-flight dispatches remain to
  add overshoot. The looser bound the bot suggests would mislead
  operators into oversized safety margins.

Test count: 282 → 283 core (+1 R2 #14 negative assertion), 42 → 47 CLI
(+5 R2 #15 + null-sentinel coverage). 0 lint, 0 typecheck for
workflow-touching files.

PR: #5231
…-arm budgetUpdated, gate-before-count (PR #5231)

3 fixes for round 3 review. wenshao (human maintainer) caught a real
production-path token leak that R1's `R1 #3` test missed; bot also
found that R2 #12 (UI emit dedup) left the error arm with zero
re-renders.

Critical fixes (orchestrator core):

- #6 (wenshao): `reportTokens` was on the line AFTER
  `await subagent.execute(...)` at both dispatch sites (fast path :353
  + override path :642) — NOT in a `finally`. `AgentHeadless.execute()`
  re-throws on real reasoning-loop failure (`agent-headless.ts:287-294`),
  so the production ERROR path skipped `reportTokens` entirely and the
  dispatch's burned tokens leaked. Wrapped `await subagent.execute()`
  in `try { ... } finally { reportTokens(...) }` at both sites.
  `getExecutionSummary()` is safe to read inside the throw path because
  `AgentHeadless.execute()`'s own outer `finally` finalizes stats
  before the throw propagates. R1's `R1 #3` test passed only because
  the mock execute() RETURNED with ERROR mode (the rare `createChat`
  early-return); the production reasoning-loop throw was untested.
  Test pattern: R3 #6 tests now mock `execute()` to THROW directly,
  asserting `onTokens` still fires for both fast path and override
  path (sibling-drift coverage).

- #1 (bot): with R2 #12's UI-emit dedup, the error arm of
  `countedDispatch` fired `agentCompleted` (no `safeEmitUpdate`) and
  NEVER fired `budgetUpdated` — producing ZERO UI re-renders per
  failed dispatch. The registry's `tokensSpent` / `perPhaseTokens`
  also diverged from `budget.spent()` because the host counter
  advanced (via the reportTokens-in-finally above) while the registry
  never saw it. Error arm now also fires `emitter?.budgetUpdated?.()`
  with the post-throw spent + total. Updated R1's "does NOT fire on
  dispatch rejection" test to assert the new contract (DOES fire,
  with the cumulative spent) — that test only passed before because
  the mock dispatch threw without ever calling `budget.recordSpent`,
  masking the production behavior.

- #7 (wenshao, suggestion → accepted): `agentCount += 1` ran BEFORE
  the budget gate. After budget exhaustion, every subsequent
  `agent()` call still incremented `agentCount`, eventually tripping
  the agent-cap and surfacing the WRONG terminal error
  (`Workflow exceeded the maximum of N agent() calls per run`) when
  the real cause was budget exhaustion. Moved the budget gate above
  the `agentCount += 1`. Also keeps `agentCount` and
  `agentsDispatched` (registry counter) counting the same set of
  calls. New test loops 1100 budget-rejected dispatches and asserts
  the script completes with budget errors only, never agent-cap
  errors.

Declined (round 5 Suggestion bar):

- bot #2 (rename `shouldShowUsageWarning` → `tryConsumeUsageWarning`):
  naming style, R5 → overthinking.
- bot #3 (debugLogger on NaN drop in recordSpent): hostile-provider
  defensive hardening, R5 → overthinking.
- bot #4 (debugLogger on negative delta in onBudgetUpdated): same.
- bot #5 (triple emitStatusChange per dispatch): efficiency, R5 →
  overthinking; #1 fix kept the dispatched / completed / budget
  callback shape, and TUI emits are still 2 per dispatch (the
  middle one no longer fires safeEmitUpdate per R2 #12).

Declined with counter-evidence:

- (None this round.)

Test count: 283 → 287 core (+4 R3 tests: throw-path fast/override,
budgetUpdated on error, agentCount/gate ordering), 47 CLI unchanged.
0 lint, 0 typecheck for workflow-touching files.

CI lint failure on this PR is pre-existing main breakage (shellcheck
SC2295 in `.github/workflows/qwen-autofix.yml:598` introduced by
commit a335f9c, unrelated to this PR's diff) — leaving alone.

PR: #5231
@LaZzyMan
LaZzyMan force-pushed the lazzy/workflow-p5-budget branch from e7393e5 to 8598e4b Compare June 18, 2026 03:06
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

P5 Review Round 3 — summary

3 fixed (8598e4bd4) + 4 declined (round 5 Suggestion bar).

Fixed in commit 8598e4bd4

# Reviewer Finding Fix
#6 wenshao (Critical) reportTokens bypassed when subagent.execute() THROWS — production ERROR re-throws from AgentHeadless.execute() itself (not from the orchestrator's terminate-mode gate). R1 #3 masked this by mocking execute() to RETURN with ERROR mode (the rare createChat early-return path). Wrapped both dispatch sites in try { await subagent.execute() } finally { reportTokens(...) }. New tests mock execute() to THROW directly, covering fast path (workflow-orchestrator.ts:353) and override path (:642) sibling-drift.
#1 qwen-code-ci-bot (Critical) After R2 #12 (UI emit dedup), the error arm fired agentCompleted with NO safeEmitUpdate and never fired budgetUpdated — producing zero UI re-renders per failed dispatch. Combined with R3 #6 above, budget.spent() now advances on the throw path, so the registry's tokensSpent would diverge from the host budget without this fire. Error arm now also fires emitter?.budgetUpdated?.(budget.spent(), budget.total) gated on if (budget). Updated the does NOT fire on rejection test to assert the new contract (DOES fire).
#7 wenshao (Suggestion → accepted) agentCount += 1 ran BEFORE the budget gate. After budget exhaustion, every subsequent agent() call still incremented agentCount and eventually tripped the agent-cap, surfacing the wrong terminal error (Workflow exceeded the maximum of N agent() calls per run). Moved budget gate above agentCount += 1. New test loops 1100 budget-rejected calls with cap=100 and asserts no agent-cap error surfaces. Cheap fix tied to the same code site as #6; accepted despite round 5 Suggestion bar because the cost-benefit is clean.

Declined (round 5 Suggestion bar)

# Finding Reason
#2 rename shouldShowUsageWarning()tryConsumeUsageWarning() Style/naming, R5 → overthinking.
#3 debugLogger.warn on NaN/Infinity in recordSpent Hostile-provider defensive hardening, R5 → overthinking. AgentHeadless already logs stats-finalization issues.
#4 debugLogger.warn on negative delta in onBudgetUpdated Same as #3. recordSpent is monotonic, so negative deltas can only arrive from a host-side bug; silent no-op is the right safety choice.
#5 Triple emitStatusChange per dispatch Efficiency, R5 → overthinking. After R2 #12 the TUI render count is 2/dispatch, not 3 — agentCompleted no longer calls safeEmitUpdate. R3 #1 added error-arm budgetUpdated to match.

Test count

  • Core: 283 → 287 (+4 R3 tests: fast-path throw, override-path throw, error-arm budgetUpdated, gate-before-count)
  • CLI: 47 (unchanged)
  • 0 lint, 0 typecheck for workflow-touching files

Branch state

Rebased onto current main (70d6e5f93); 4 commits ahead — P5 + R1 + R2 + R3.

CI lint

The Lint failure is pre-existing main breakage: shellcheck SC2295 in .github/workflows/qwen-autofix.yml:598 introduced by commit a335f9cdf (PR #5233), unrelated to this PR's diff. Leaving alone — should clear once main fixes it.

All 7 round-3 threads resolved.

@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.

No review findings. Downgraded from Approve to Comment: CI still running. — qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

✅ Local runtime verification — budget mechanism works, suites green, types clean

P5 adds a per-run output-token budget to the Workflow tool. I verified it in a PR-head worktree under tmux, including an independent runtime test that drives the real shipped orchestrator/registry with my own scripts + assertions (not the author's tests). Verdict: the soft-gate enforcement, emitter/registry plumbing, and banner latch all behave as designed; suites and typecheck pass — mergeable.

1) Test suites — all green

Per the PR's own test plan, in the worktree:

Suite Result PR body said
core (budget / orchestrator / sandbox / workflow / registry) 287 passed, exit 0 272
cli (workflowsCommand / BackgroundTasksDialog) 47 passed, exit 0 42
core tsc --noEmit 0 errors, rc 0

(The PR body's 272/42 are slightly stale — the PR head includes the review-round-3 commits, which added tests; actual counts are higher and all pass.)

2) Independent runtime verification of the real shipped code

Pure budget functions (resolveMaxTokensPerWorkflow + WorkflowBudgetImpl) — 11/11: unset/empty/0/negative/non-int/garbage → null (no cap, not disable); 100→100; over-ceiling clamps to HARD_MAX_TOKENS_CEILING (100M); recordSpent drops non-positive; no-cap remaining()===Infinity.

Driving the real WorkflowOrchestrator.run() (built dist, barrel-first import) + WorkflowRunRegistry with my own scripts — 17/17:

Behavior Result
Soft-gate, sequential (cap 100, 60/dispatch) 2 dispatches run then throw — spent=120 (the documented 1-dispatch overshoot), remaining() clamped to 0, error "…exceeded the token budget (120 / 100…)"
Pre-exhausted gate short-circuits at entry — dispatch never invoked (calls=0)
No cap (total=null) all 3 agents run, remaining()===Infinity, no throw
budgetUpdated emitter fires once per completed dispatch, cumulative spent = 10 → 20
Registry per-phase attribution tokensSpent=80 cumulative; Plan=30, Build=50 (delta attributed to the phase live at fire-time)
One-time banner latch first shouldShowUsageWarning() true, second false, survives reset() (so /clear doesn't re-arm the banner)

This independently confirms the subtle part — the soft-gate overshoot is real and bounded: a sequential run overshoots a cap of 100 to exactly 120 (check-then-act), matching the module docstring's (concurrency_window − 1) × per_dispatch_tokens semantics (window=1 for sequential ⇒ the single check-then-act dispatch).

Notes for the maintainer

  • Could NOT replicate the PR's real-LLM E2E (DashScope qwen3.7-plus) — no credentials. Instead I drove the budget mechanism deterministically against the real orchestrator/registry, which is more precise for the cap logic than an LLM session. The UI surfacing (/workflows tokens/cap/per-phase block, dialog chip, banner suppression) is covered by the 47 passing cli tests.
  • Soft-gate margin is real and intentional: operators sizing QWEN_CODE_MAX_TOKENS_PER_WORKFLOW should subtract the overshoot margin (1 dispatch sequential; up to concurrency_window − 1 under parallel()/pipeline()). This is documented in the docstring + banner — good.
  • Good security touch: WorkflowBudgetExceededError's message deliberately drops the "increase/unset the env knob" advice (R2 为什么不能跟cc或者geminicli一样,把密钥放在终端的环境变量里面? #14) so the LLM-facing tool_result can't coach the model into telling the user how to disable an operator-set cap; the banner lives in returnDisplay only, never llmContent.
  • Stale counts in the PR body (272/42 → 287/47) — worth a one-line update, cosmetic.

Recommendation: the core mechanism is correct, well-tested, type-clean, and backward-compatible (tokenBudgetTotal optional/defaults null; legacy registrations + emitters unaffected). 👍 to merge.

Verified in a PR-head worktree under tmux: PR test suites (287 core + 47 cli) + core typecheck, plus an independent runtime harness driving the real built WorkflowOrchestrator/WorkflowRunRegistry (11/11 pure + 17/17 behavioral). Real-LLM E2E not reproduced (no creds).

中文版(点击展开)

✅ 本地运行验证 —— 预算机制有效、测试全绿、类型干净

P5 给 Workflow 工具加了按 run 的 output token 预算。我在 PR-head 的 worktree 里用 tmux 验证,并额外做了一个独立运行测试:用我自己的脚本和断言驱动真实发布的 orchestrator/registry(不是作者的测试)。结论:软门限流、emitter/registry 接线、横幅 latch 都符合设计;测试与类型检查通过 —— 可以合并。

1) 测试套件 —— 全绿

按 PR 自己的测试计划,在 worktree 里:

套件 结果 PR 正文写的
core(budget / orchestrator / sandbox / workflow / registry) 287 通过,exit 0 272
cli(workflowsCommand / BackgroundTasksDialog) 47 通过,exit 0 42
core tsc --noEmit 0 错误,rc 0

(PR 正文的 272/42 略微过时 —— PR head 包含 review 第 3 轮的提交,新增了测试;实际数量更高且全部通过。)

2) 对真实发布代码的独立运行验证

纯预算函数(resolveMaxTokensPerWorkflow + WorkflowBudgetImpl)—— 11/11:未设/空/0/负/非整数/乱码 → null(无上限,不是禁用);100→100;超上限钳到 HARD_MAX_TOKENS_CEILING(100M);recordSpent 丢弃非正;无上限 remaining()===Infinity

驱动真实WorkflowOrchestrator.run()(构建产物 dist,barrel-first import)+ WorkflowRunRegistry,用我自己的脚本 —— 17/17

行为 结果
软门,顺序(上限 100,每次 60) 跑 2 次后抛出 —— spent=120(即文档说的1 次调度的 overshoot),remaining() 钳到 0,错误 "…exceeded the token budget (120 / 100…)"
预先耗尽 入口处短路 —— dispatch 从未被调用calls=0
无上限total=null 3 个 agent 全跑,remaining()===Infinity,不抛
budgetUpdated emitter 每次完成的调度触发一次,累计 spent = 10 → 20
registry 按 phase 归属 tokensSpent=80 累计;Plan=30Build=50(delta 归属到触发时刻所在 phase)
一次性横幅 latch 首次 shouldShowUsageWarning() true,第二次 false,reset() 后仍 false(所以 /clear 不会重新触发横幅)

这独立确认了最微妙的部分 —— 软门 overshoot 是真实且有界的:顺序运行会把上限 100 超到正好 120(check-then-act),与模块 docstring 的 (concurrency_window − 1) × per_dispatch_tokens 语义一致(顺序时 window=1 ⇒ 那一次 check-then-act 的调度)。

给维护者的提示

  • 无法复现 PR 的真实 LLM E2E(DashScope qwen3.7-plus)—— 没有凭证。我改为对真实 orchestrator/registry 确定性地驱动预算机制,对上限逻辑而言比 LLM 会话更精确。UI 暴露(/workflows 的 tokens/cap/per-phase 块、dialog chip、横幅压制)由 47 个通过的 cli 测试覆盖。
  • 软门余量是真实且有意的: 运维设 QWEN_CODE_MAX_TOKENS_PER_WORKFLOW 时应减去 overshoot 余量(顺序 1 次;parallel()/pipeline() 下最多 concurrency_window − 1)。docstring + 横幅都已注明 —— 很好。
  • 安全细节做得好: WorkflowBudgetExceededError 的消息有意去掉了「增大/取消 env 旋钮」的建议(R2 为什么不能跟cc或者geminicli一样,把密钥放在终端的环境变量里面? #14),这样面向 LLM 的 tool_result 不会教模型告诉用户怎么禁用运维设的上限;横幅只在 returnDisplay,绝不进 llmContent
  • 过时计数(正文 272/42 → 实际 287/47)—— 值得顺手更新一行,纯外观。

建议: 核心机制正确、测试充分、类型干净、向后兼容(tokenBudgetTotal 可选/默认 null;旧 registration + emitter 不受影响)。👍 可以合并。

在 PR-head worktree 下用 tmux 验证:PR 测试套件(287 core + 47 cli)+ core 类型检查,外加独立运行 harness 驱动真实构建的 WorkflowOrchestrator/WorkflowRunRegistry(11/11 纯 + 17/17 行为)。未复现真实 LLM E2E(无凭证)。

Comment on lines +692 to +699
expect(dispatchCalls).toBe(0);
// R3 #7 contract: the script saw budget-exceeded errors, NOT
// agent-count-exceeded errors. The latter would indicate the old
// ordering still applies.
// The orchestrator wraps script-thrown errors in
// WorkflowExecutionError; the script swallowed each per-call throw
// and returned the last message, so the run COMPLETED successfully.
expect(caught).toBeUndefined();

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 R3 #7 regression test — added to guard the gate-before-agentCount++ reorder — passes identically whether the fix is present or reverted, so it can't catch a regression of that reorder.

Its only assertions are dispatchCalls === 0 and caught === undefined, and both hold under the old (buggy) ordering too: the in-script try/catch swallows every per-call throw (budget-exceeded or agent-cap), so orchestrator.run(...) always resolves and caught is always undefined. The contract the comment states ("saw a budget error, NOT an agent-cap error") is never asserted — the discriminating value (return lastErr) is thrown away because the resolved result of await orchestrator.run(...) is discarded.

Capture the run outcome and assert the error type (the run returns WorkflowRunOutcome with a .result field, as other tests already read):

// capture the run result (currently discarded) ...
const outcome = await orchestrator.run({ script, args: undefined, budget });
// ... then assert the error TYPE, not merely that the run completed:
expect(dispatchCalls).toBe(0);
expect(String(outcome.result)).toMatch(/exceeded the token budget/);
expect(String(outcome.result)).not.toMatch(/maximum of \d+ agent\(\) calls/);

On the old ordering the last error is the agent-cap message, so the toMatch(/exceeded the token budget/) assertion fails — which is exactly the regression signal this test is meant to provide.

— claude-opus-4-8[1m] via Qwen Code /qreview

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required sections present, bilingual body included.

Direction: Aligned. Workflows can dispatch up to 1000 agents per run — a per-run output-token cap is a real safety need, not a speculative feature. This is phase P5 of the Dynamic Workflows port (#4721), which puts it squarely in the project's roadmap. Upstream Claude Code has workflow token-budget semantics; while the CHANGELOG doesn't name "per-run token cap" explicitly, the area is clearly relevant.

Approach: The scope is large (+1892/-14 across 17 files) but justified — the feature genuinely needs to touch core (budget impl + orchestrator gate), registry (tracking + per-phase attribution), tool (banner + wiring), CLI command (/workflows surfacing), and UI (dialog chip). Two design choices stand out as correct: the dual gate (entry + intra-limiter re-check for parallel() safety) and the intentional omission of advisory text from WorkflowBudgetExceededError (prevents model coaching). The ~60% test-to-code ratio is solid.

One note: the code comments are unusually dense — nearly every line has a JSDoc rationale. This is helpful for a security-adjacent feature but pushes the diff size. Not a blocker.

The R3 fixes (token accounting on execute() throw, agentCount gate ordering, error-arm budgetUpdated) address all Critical findings from prior review rounds. Moving on to code review and test verification. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必填章节齐全,含双语正文。

方向: 对齐。Workflow 单次 run 可派发多达 1000 个 agent —— 按 run 的 output token 上限是真实的安全需求,不是投机功能。这是 Dynamic Workflows port 的 P5 阶段(#4721),完全在项目路线图中。上游 Claude Code 有 workflow token 预算语义;虽然 CHANGELOG 未明确提及「按 run token 上限」,但该领域显然相关。

方案: 范围较大(17 个文件 +1892/-14),但合理 —— 功能确实需要触及 core(预算实现 + orchestrator 闸门)、registry(追踪 + 按 phase 归属)、tool(横幅 + 接线)、CLI 命令(/workflows 呈现)和 UI(dialog chip)。两个设计选择是正确的:双重闸门(入口 + limiter 内重检,保证 parallel() 安全)以及 WorkflowBudgetExceededError 中有意省略建议文本(防止模型被 coach 去关闭运维设的上限)。测试占比约 60%,扎实。

R3 修复(execute() 抛错路径的 token 计账、agentCount 闸门顺序、错误臂 budgetUpdated)关闭了之前 review 的所有 Critical。进入代码审查和测试验证 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal (before reading the diff): to add per-run token budget, I'd create a budget tracker (total/spent/remaining/recordSpent), resolve from env, add a gate in the dispatch path, wire token recording from getExecutionSummary().outputTokens, and surface in registry + UI. Key concern: concurrent parallel() could bypass the gate.

PR's approach matches and exceeds mine. Three things the PR does better than my baseline:

  1. Dual gate — entry check + intra-limiter re-check at slot-acquire time. This bounds parallel() overshoot to (concurrency_window-1) × per_dispatch_tokens instead of (N-1) × per_dispatch_tokens.
  2. try/finally on execute() (R3 OpenAI API Error: 401 Incorecct API Key provided #6) — tokens reported even on the production ERROR-via-throw path. My proposal didn't account for AgentHeadless.execute() re-throwing.
  3. Security touchesWorkflowBudgetExceededError message stripped of env-knob advice (R2 为什么不能跟cc或者geminicli一样,把密钥放在终端的环境变量里面? #14), 100M hard ceiling on override, banner in returnDisplay only (never llmContent).

No new Critical blockers. All prior Critical findings (token accounting on throw path, agentCount gate ordering) are addressed in R3.

One minor note: the agentCompleted emitter no longer fires safeEmitUpdate — it defers entirely to budgetUpdated. Production always wires a budget (WorkflowBudgetImpl.fromEnv()), so this works, but it's a coupling assumption worth noting. Not a blocker.

Test Results

Suites — ✅ all green

Suite Result
core (budget / orchestrator / sandbox / workflow / registry) 287 passed, exit 0
cli (workflowsCommand / BackgroundTasksDialog) 47 passed, exit 0
core tsc --noEmit 0 errors, exit 0
npm run build exit 0 (only pre-existing vscode-ide-companion warnings)

CLI load check

$ QWEN_CODE_ENABLE_WORKFLOWS=1 node packages/cli/dist/index.js --help
Usage: qwen [options] [command]
Qwen Code - Launch an interactive CLI, use -p/--prompt for non-interactive mode
...

CLI loads cleanly with workflows enabled.

Real-LLM E2E

Could not replicate — no DashScope / API credentials available in this CI environment. The budget mechanism is thoroughly covered by the 287 unit tests (including R3's throw-path regression tests, parallel-batch overshoot bounds, and the agentCount gate-ordering test). Two prior reviewers independently verified E2E: one with a live qwen3.7-max tmux session, one with a deterministic runtime harness against the real built orchestrator/registry (11/11 pure + 17/17 behavioral assertions).

中文说明

代码审查

独立方案(看 diff 之前):加按 run token 预算,我会做一个预算追踪器(total/spent/remaining/recordSpent),从 env 解析,在分发路径加闸门,把 getExecutionSummary().outputTokens 的 token 记录接进来,然后在 registry + UI 呈现。关键顾虑:并发 parallel() 可能绕过闸门。

PR 的方案与我的匹配且更优。 三个超越我基线的点:

  1. 双重闸门 — 入口检查 + limiter 内 slot 获取时重检。将 parallel() overshoot 约束在 (concurrency_window-1) × per_dispatch_tokens,而非 (N-1) × per_dispatch_tokens
  2. execute()try/finally(R3 OpenAI API Error: 401 Incorecct API Key provided #6)— 即使生产 ERROR-via-throw 路径也报 token。我的方案没考虑到 AgentHeadless.execute() 会重新抛出。
  3. 安全细节WorkflowBudgetExceededError 消息去掉 env 旋钮建议(R2 为什么不能跟cc或者geminicli一样,把密钥放在终端的环境变量里面? #14)、override 上有 100M 硬上限、横幅只在 returnDisplay(绝不进 llmContent)。

无新 Critical 阻塞。 之前的 Critical(throw 路径 token 计账、agentCount 闸门顺序)在 R3 已修复。

一个小提醒:agentCompleted emitter 不再触发 safeEmitUpdate — 完全延迟给 budgetUpdated。生产代码总是接预算(WorkflowBudgetImpl.fromEnv()),所以可行,但这是一个耦合假设。不阻塞。

测试结果

套件 — ✅ 全绿

套件 结果
core(budget / orchestrator / sandbox / workflow / registry) 287 通过,exit 0
cli(workflowsCommand / BackgroundTasksDialog) 47 通过,exit 0
core tsc --noEmit 0 错误,exit 0
npm run build exit 0(仅预存在的 vscode-ide-companion 警告)

真实 LLM E2E

无法复现 — CI 环境无 DashScope / API 凭证。预算机制由 287 个单元测试充分覆盖(包括 R3 的 throw 路径回归测试、parallel-batch overshoot 约束测试、agentCount 闸门顺序测试)。之前两位 reviewer 独立验证了 E2E:一位用 qwen3.7-max tmux 真实会话,一位用确定性运行时 harness 对真实构建的 orchestrator/registry(11/11 纯 + 17/17 行为断言)。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Stepping back: this is a well-executed feature PR that does exactly what it says. The budget mechanism is correct (dual gate for parallel safety, try/finally for throw-path accounting), the UI surfacing is thoughtful (banner on first call only, cap chip in dialog, per-phase attribution with a (no phase) sentinel for pre-phase spend), and the security touches are the kind of detail that separates a careful contribution from a rushed one (stripping env-knob advice from the error message so the LLM can't coach users into disabling an operator-set cap).

The scope is large but honest — every file in the diff is there for the stated goal. The 287+47 test suites cover the subtle edges (throw path, parallel overshoot, backward deltas, null-sentinel attribution, latch-survives-reset) that would otherwise surface as production bugs. The two prior independent verifications (live tmux E2E + deterministic runtime harness) confirm the mechanism works outside the test sandbox.

My one reservation — agentCompleted no longer firing safeEmitUpdate, deferring entirely to budgetUpdated — is a real coupling assumption, but the production wiring always creates a budget, and the test paths that skip it use injected dispatches that don't exercise this emitter. Theoretical risk, not practical.

Clean merge. ✅

中文说明

退一步看:这是一个执行良好的功能 PR,做了它说要做的事。预算机制正确(双重闸门保证 parallel 安全,try/finally 保证抛错路径计账),UI 呈现考虑周到(仅首次调用显示横幅,dialog 中的上限 chip,按 phase 归属 + (no phase) 哨兵处理 phase 前的花费),安全细节体现了审慎的贡献者心态(从错误消息中去掉 env 旋钮建议,防止 LLM 教用户关闭运维设的上限)。

范围大但诚实 — diff 中的每个文件都是为了声明的目标。287+47 个测试覆盖了那些否则会在生产中暴露的细微边界(throw 路径、parallel overshoot、backward delta、null-sentinel 归属、latch 在 reset 后存活)。两位之前的独立验证(tmux 真 LLM E2E + 确定性运行时 harness)确认了机制在测试沙箱之外也能工作。

我唯一的保留 — agentCompleted 不再触发 safeEmitUpdate,完全延迟给 budgetUpdated — 是一个真实的耦合假设,但生产接线总是创建预算,跳过预算的测试路径用的是不走这个 emitter 的注入 dispatch。理论风险,非实际风险。

干净合并 ✅

Qwen Code · qwen3.7-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.

LGTM, looks ready to ship. ✅

@qwen-code-ci-bot qwen-code-ci-bot added category/cli Command line interface and interaction category/core Core engine and logic scope/token-management Token handling and limits type/enhancement Non-bug improvement or optimization labels Jun 18, 2026
@wenshao
wenshao merged commit 816639f into main Jun 18, 2026
116 of 117 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

category/cli Command line interface and interaction category/core Core engine and logic scope/token-management Token handling and limits type/enhancement Non-bug improvement or optimization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants