Skip to content

fix(web-shell): isolate worktree session execution - #8068

Merged
wenshao merged 8 commits into
mainfrom
fix/web-shell-worktree-session-isolation
Jul 30, 2026
Merged

fix(web-shell): isolate worktree session execution#8068
wenshao merged 8 commits into
mainfrom
fix/web-shell-worktree-session-isolation

Conversation

@wenshao

@wenshao wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

This change makes execution inside daemon-managed Web Shell worktree sessions consistently use the session's effective working directory rather than the owning workspace checkout. Direct session shell commands wait for pending directory relocation before running, and local command-based MCP servers without an explicit cwd are bound to the current session directory across legacy, incremental, and pooled discovery paths.

Fresh worktree sessions defer MCP discovery until their trusted relocation into the worktree completes, preventing an MCP process from briefly starting in the base checkout. Subsequent directory changes reconcile MCP connections against the new directory, while explicitly configured MCP working directories and remote or SDK transports retain their existing behavior.

Why it's needed

Multiple worktree sessions can run concurrently under one Web Shell workspace. Direct shell commands previously used the base workspace directory, and implicit stdio MCP processes could inherit or initially start in that same directory. Concurrent sessions could therefore overwrite files in the base checkout or share an MCP transport with the wrong filesystem context even though built-in file tools were operating in separate worktrees.

Reviewer Test Plan

How to verify

Start the daemon from TypeScript source against a temporary Git repository, create two Web Shell worktree sessions under the same workspace, and run direct shell commands, agent shell writes, Git commits, and an implicit-cwd stdio MCP tool concurrently in both sessions. Confirm that each operation reports and modifies only its own worktree, each worktree branch receives only its own commit, the base branch HEAD does not move, and no business files appear in the base checkout. Also confirm from the mock MCP server's startup record that its first process cwd is the corresponding worktree rather than the base checkout.

Targeted automated coverage verifies direct-shell cwd serialization, worktree MCP discovery deferral, implicit versus explicit MCP cwd handling, MCP reconciliation after relocation, pooled discovery fingerprints, ACP-injected stdio configuration, and warning behavior when MCP refresh fails. The affected test files passed with 1,523 tests total; Core and ACP bridge type checks, ESLint, Prettier, and git diff --check also passed. The full CLI type check remains blocked by pre-existing channel module and Ink type errors unrelated to this change.

Evidence (Before & After)

Before: two worktree sessions shared the base workspace cwd for direct session shell execution, and implicit stdio MCP processes could start in the base checkout and overwrite the same file.

After: a real concurrent daemon run from the TypeScript source produced the following observations:

Check Session A Session B
Direct shell cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b
Direct-shell same-name file same-name.txt = A-agent-shell same-name.txt = B-agent-shell
Agent-shell same-name file agent-same.txt = A-agent agent-same.txt = B-agent
Worktree branch worktree-e2e-a worktree-e2e-b
Isolated commit 75d553f5d96a541e91f09aa5fffd694fee685686 e486e1b63007565bea13f8859ff3edc05945a480
First stdio MCP spawn cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b
MCP tool-reported cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b

The base HEAD remained 17a5cbfbeb347a594cfbf9846e525e98e0712513 before and after both commits. Neither same-name.txt nor agent-same.txt existed in the base checkout. Both agent turns completed without a turn error, both sessions closed with HTTP 204, the daemon port was no longer listening after cleanup, and the temporary repository was removed.

Automated verification:

ACP bridge:                462 passed
ACP agent:                 343 passed
Core config + MCP client:  579 passed
MCP client manager:        117 passed
CLI cd command:             22 passed
Total:                    1,523 passed

npm run typecheck passed in packages/core and packages/acp-bridge. ESLint, Prettier, and git diff --check passed for the modified files. Full CLI typecheck was not counted as passing because it remains blocked by pre-existing missing channel modules and Ink type drift unrelated to this diff.

Tested on

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

Environment (optional)

macOS with npm run dev -- serve, daemon-managed Git worktrees, direct session shell enabled, and a local mock stdio MCP server.

Risk & Scope

  • Main risk or tradeoff: Local implicit-cwd MCP servers now receive a session-specific cwd, which intentionally creates distinct pooled transports for sessions in different worktrees and may increase MCP process count compared with incorrectly sharing one base-directory process.
  • Not validated / out of scope: Daemon restart/load worktree restoration, LSP root relocation, Git UI/sidebar cwd ownership, split-pane worktree metadata, and other cwd-derived services such as hooks or extensions are not addressed by this change.
  • Breaking changes / migration notes: No public API or configuration migration. An explicitly configured MCP cwd remains authoritative.

Linked Issues

N/A

中文说明

What this PR does

此改动让 daemon 管理的 Web Shell worktree session 中的执行统一使用 session 的有效工作目录,而不是所属 workspace 的主 checkout。Direct session shell 会等待尚未完成的目录迁移后再执行;未显式配置 cwd 的本地 command MCP server 会在 legacy、incremental 和 pooled discovery 路径中绑定到当前 session 目录。

新建 worktree session 会在可信的 worktree relocation 完成前延迟 MCP discovery,避免 MCP 进程短暂地在主 checkout 中启动。后续目录变更会按新目录重新 reconcile MCP connection;显式配置的 MCP 工作目录以及 remote 或 SDK transport 保持现有语义。

Why it's needed

同一个 Web Shell workspace 下可以并发运行多个 worktree session。此前 direct shell command 使用主 workspace 目录,隐式 stdio MCP 进程也可能继承或首次启动在同一个目录。因此,即使 built-in file tool 已经在不同 worktree 中运行,并发 session 仍可能覆盖主 checkout 中的文件,或者共享带有错误文件系统上下文的 MCP transport。

Reviewer Test Plan

How to verify

使用临时 Git 仓库从 TypeScript 源码启动 daemon,在同一 workspace 下创建两个 Web Shell worktree session,并在两个 session 中并发执行 direct shell、agent shell 文件写入、Git commit 和未显式配置 cwd 的 stdio MCP tool。确认每项操作只报告并修改自己的 worktree,每个 worktree branch 只获得自己的 commit,base branch HEAD 不发生变化,并且主 checkout 中没有出现业务文件。同时检查 mock MCP server 的启动记录,确认进程第一次启动时的 cwd 就是对应 worktree,而不是主 checkout。

针对性自动化覆盖验证了 direct-shell cwd 串行化、worktree MCP discovery 延迟、隐式与显式 MCP cwd 处理、relocation 后的 MCP reconcile、pool discovery fingerprint、ACP 注入的 stdio 配置,以及 MCP refresh 失败时的 warning。受影响测试文件共 1,523 个测试全部通过;Core 和 ACP bridge typecheck、ESLint、Prettier、git diff --check 也通过。CLI 全量 typecheck 仍被与本改动无关的既有 channel module 和 Ink 类型错误阻塞。

Evidence (Before & After)

Before:两个 worktree session 的 direct session shell 共享主 workspace cwd,隐式 stdio MCP 进程可能启动在主 checkout,并覆盖同名文件。

After:从 TypeScript 源码启动 daemon 进行真实并发测试,得到以下实际观测值:

检查项 Session A Session B
Direct shell cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b
Direct shell 同名文件 same-name.txt = A-agent-shell same-name.txt = B-agent-shell
Agent shell 同名文件 agent-same.txt = A-agent agent-same.txt = B-agent
Worktree branch worktree-e2e-a worktree-e2e-b
独立 commit 75d553f5d96a541e91f09aa5fffd694fee685686 e486e1b63007565bea13f8859ff3edc05945a480
Stdio MCP 第一次 spawn cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b
MCP tool 报告的 cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b

两个 commit 前后 base HEAD 都是 17a5cbfbeb347a594cfbf9846e525e98e0712513。主 checkout 中不存在 same-name.txtagent-same.txt。两个 agent turn 都正常完成且没有 turn error;两个 session 均以 HTTP 204 关闭;清理后 daemon 端口不再监听,临时仓库已删除。

自动化验证:

ACP bridge:                462 passed
ACP agent:                 343 passed
Core config + MCP client:  579 passed
MCP client manager:        117 passed
CLI cd command:             22 passed
Total:                    1,523 passed

packages/corepackages/acp-bridgenpm run typecheck 通过;修改文件的 ESLint、Prettier 和 git diff --check 通过。CLI 全量 typecheck 没有计为通过,因为仍被与本 diff 无关的既有 channel module 缺失和 Ink 类型漂移阻塞。

Tested on

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

Environment (optional)

macOS,使用 npm run dev -- serve、daemon 管理的 Git worktree、已启用 direct session shell,以及本地 mock stdio MCP server。

Risk & Scope

  • Main risk or tradeoff:本地隐式 cwd MCP server 现在会获得 session 独立的 cwd,因此不同 worktree 的 session 会有不同的 pooled transport;与之前错误共享主目录进程相比,MCP 进程数量可能增加。
  • Not validated / out of scope:daemon restart/load 的 worktree 恢复、LSP root relocation、Git UI/sidebar cwd ownership、split-pane worktree metadata,以及 hook、extension 等其他 cwd 派生服务不在本次改动范围内。
  • Breaking changes / migration notes:没有公共 API 或配置迁移。显式配置的 MCP cwd 仍具有最高优先级。

Linked Issues

N/A

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

qwen-code-ci-bot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

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

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

@wenshao
wenshao force-pushed the fix/web-shell-worktree-session-isolation branch from 8cf1164 to 2f4ef7c Compare July 30, 2026 00:25
@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: this is an observed bug, not theoretical hardening. The description carries a concrete before/after reproduction — two concurrent worktree sessions whose direct shell commands and implicit stdio MCP processes both land in the base checkout, overwriting the same same-name.txt / agent-same.txt. The after table shows each session confined to its own worktree with the base HEAD unmoved. That is real evidence.

Direction: aligned. Concurrent Web Shell worktree sessions sharing the base workspace cwd is a correctness bug in the daemon's multi-session model — built-in file tools already isolate per worktree, but direct shell and implicit MCP did not. This closes that gap. No CHANGELOG reference needed; the area is core to serve/worktree.

Size: touches core paths (packages/core/src/config, packages/core/src/tools) and spans three packages. Production logic is ~225 lines (bridge.ts 58, acpAgent.ts 28, cdCommand.ts 9, config.ts 47, mcp-client-manager.ts 44, mcp-client.ts 38, bridgeTypes.ts 1); tests are ~581 lines. Well under the 500-line maintainer-awareness threshold — no size escalation.

Approach: the scope feels right, and it matches what I'd propose independently — track a per-session effective cwd and serialize direct shell behind in-flight cd changes; stamp the session cwd onto implicit stdio MCP servers centrally (so it joins the pool fingerprint and a relocation rebinds them); defer MCP discovery for a fresh worktree session until its trusted relocation; reconcile MCP on directory change. Consolidating six inline populateMcpServerCommand calls into one getEffectiveMcpServers() is a nice divergence-prevention win. One question worth a thought (not a blocker): cwdChangeQueue is assigned directly per cd rather than chained off the previous tail the way promptQueue is — fine for the stated case (concurrent sessions, one in-flight cd per session), but concurrent cds on a single session could let a shell read a mid-transition cwd. Two minor notes carried into the code review: a few existing comments in config.ts were shortened during the refreshMcpServers extraction.

Risk: elevated — Stage 1e matched high-risk paths packages/core/src/tools/mcp-client.ts, packages/core/src/tools/mcp-client-manager.ts (mcp-client), and packages/cli/src/acp-integration/acpAgent.ts (acp-integration). Not a gate, but it means the code review keeps every enrichment and the approval leans on real CI evidence plus a named sandboxed lane.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:这是已观测到的 bug,不是理论性加固。描述里给出了具体的 before/after 复现——两个并发 worktree session 的 direct shell 和隐式 stdio MCP 进程都落在主 checkout,覆盖同一个 same-name.txt / agent-same.txt。after 表格显示每个 session 都被限制在自己的 worktree 内,base HEAD 未移动。这是真实证据。

方向:对齐。并发 Web Shell worktree session 共享主 workspace cwd 是 daemon 多 session 模型中的正确性 bug——内置 file tool 已经按 worktree 隔离,但 direct shell 和隐式 MCP 没有。本 PR 补上了这个缺口。

规模:触及核心路径(packages/core/src/configpackages/core/src/tools)并跨三个 package。生产逻辑约 225 行,测试约 581 行,远低于 500 行维护者关注阈值——无需规模升级。

方案:范围合理,与我独立想到的方案一致——为每个 session 跟踪有效 cwd,并把 direct shell 串行化到正在进行的 cd 之后;集中式地把 session cwd 打到隐式 stdio MCP server 上(使其进入 pool fingerprint,relocation 时重新绑定);新建 worktree session 在可信 relocation 完成前延迟 MCP discovery;目录变更时 reconcile MCP。把六处内联的 populateMcpServerCommand 调用合并为一个 getEffectiveMcpServers() 很好地防止了逻辑分叉。一个值得思考的问题(非阻塞):cwdChangeQueue 是按每次 cd 直接赋值,而不是像 promptQueue 那样链在前一个尾巴上——对所述场景(并发 session、每 session 一个在途 cd)没问题,但单 session 上并发 cd 可能让 shell 读到迁移中的 cwd。另有两点小问题留到代码审查:config.ts 中若干既有注释在 refreshMcpServers 抽取时被缩短了。

风险:升级——Stage 1e 命中高风险路径 mcp-client.tsmcp-client-manager.ts(mcp-client)和 acpAgent.ts(acp-integration)。这不是 gate,但意味着代码审查保留全部 enrichment,且审批依赖真实 CI 证据加一条命名的沙箱验证通道。

进入代码审查 🔍

Qwen Code · qwen3.8-max-preview

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

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

E2E Test Report — concurrent worktree session isolation

Result: PASS

Tested the rebased PR branch at 2f4ef7cebe9d1ab0cbf98d5fd532e66e4bf62c30 on macOS by starting the daemon from the current TypeScript source against a temporary Git repository:

QWEN_RUNTIME_DIR=<temp>/runtime QWEN_SERVER_TOKEN=<token> npm run dev -- serve --workspace <temp>/base --hostname 127.0.0.1 --port 43179 --enable-session-shell

The daemon created two web-shell worktree sessions under the same base workspace and ran direct shell commands, agent shell writes, Git commits, and an implicit-cwd stdio MCP tool concurrently.

Session isolation observations

Check Session A Session B
Session ID 4b347a0c-a9d1-4770-85d9-b7f600605486 51ed1a73-7084-4b52-ab40-6159bf97e7ae
Direct shell cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b
Direct-shell file same-name.txt = A-agent-shell same-name.txt = B-agent-shell
Agent-shell file agent-same.txt = A-agent agent-same.txt = B-agent
Branch worktree-e2e-a worktree-e2e-b
Commit 75d553f5d96a541e91f09aa5fffd694fee685686 (A isolated changes) e486e1b63007565bea13f8859ff3edc05945a480 (B isolated changes)
First MCP process cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b
MCP tool-reported cwd /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-a /private/tmp/qwen-wt-e2e.U29woU/base/.qwen/worktrees/e2e-b

The mock MCP configuration did not provide cwd. Its first startup record already contained the corresponding worktree cwd, proving that the process did not first spawn in the base checkout and relocate later.

Base workspace invariants

Base HEAD before: 17a5cbfbeb347a594cfbf9846e525e98e0712513
Base HEAD after:  17a5cbfbeb347a594cfbf9846e525e98e0712513
Base files:       README.md plus daemon-managed .qwen metadata
same-name.txt:    absent
agent-same.txt:   absent

The two worktree refs moved independently while refs/heads/main remained unchanged.

Automated checks

ACP bridge:                462 passed
ACP agent:                 343 passed
Core config + MCP client:  579 passed
MCP client manager:        117 passed
CLI cd command:             22 passed
Total:                    1,523 passed

Additional checks:

  • packages/core: npm run typecheck passed
  • packages/acp-bridge: npm run typecheck passed
  • ESLint on all modified TypeScript files passed
  • Prettier check passed
  • git diff --check passed
  • Independent read-only review reported no blocking finding

Full CLI typecheck is not reported as passing because the branch has pre-existing missing channel module and Ink type errors unrelated to this PR.

Cleanup

  • Both sessions closed with HTTP 204.
  • The daemon received SIGTERM as the intentional test cleanup action; background task UIs mechanically label that long-running server command as failed even though the run completed successfully.
  • The listening port was confirmed closed.
  • The temporary repository and runtime directory were removed.

@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Code review

I wrote my independent proposal from the title + "Why it's needed" before reading the diff: per-session effective cwd with direct shell serialized behind in-flight cd changes, central cwd-stamping on implicit stdio MCP servers so a relocation rebinds the pool, worktree discovery deferral until trusted relocation, and MCP reconcile on directory change. The PR lands essentially that design, and the consolidation of six inline populateMcpServerCommand calls into getEffectiveMcpServers() is exactly the divergence guard I'd want.

No critical blockers. The load-bearing logic reads correct:

  • populateMcpServerCommand now stamps the session cwd only onto implicit stdio servers — the predicate correctly excludes httpUrl/url (remote), tcp, type: 'sdk', and any server with an explicit cwd, and it no longer mutates the input map (covered by the "does not mutate" test). Returning early when cwd === undefined preserves today's behavior for the no-target-dir path.
  • The direct-shell abort race in bridge.ts is sound: cwdChangeQueue is built with .then(() => undefined, () => undefined) so a failed cd never makes the shell throw — it runs in the previous cwd, and an aborted command returns promptly instead of parking on a hung cd. Both paths are tested.
  • relocateWorkingDirectory cleanly extracts the existing reconcile body into refreshMcpServers() and adds the MCP pass (waitForMcpReady + reconcile) after the move, returning mcpRefreshError alongside memoryRefreshError. The extraction is faithful — logic unchanged, callers surfaced.

Two non-blocking observations:

  1. cwdChangeQueue is assigned directly per cd (entry.cwdChangeQueue = cdPromise.then(...)) rather than chained off the previous tail the way promptQueue is. For the stated problem — concurrent sessions, one in-flight cd per session — this is correct, but two overlapping cds on a single session could let a queued shell read a mid-transition effectiveCwd. Worth confirming cds are serialized upstream (ACP extMethod layer) so this can't happen; if they are, no change needed.
  2. A few existing explanatory comments in config.ts were shortened during the refreshMcpServers extraction. They still carry the gist, but AGENTS.md leans toward preserving existing comments — minor, in legitimately refactored code.
sequenceDiagram
    participant P1 as Bridge
    participant P2 as QwenAgent
    participant P3 as Config
    participant P4 as McpClientManager
    P1->>P2: newSession, deferMcpDiscovery true
    P2->>P3: initialize, skipMcpDiscovery true
    Note over P3: no MCP process spawned in base checkout
    P1->>P2: sessionCd after worktree relocation
    P2->>P3: relocateWorkingDirectory, newDir
    P3->>P3: stamp implicit stdio cwd with newDir
    P3->>P4: discoverAllMcpToolsIncremental
    P4-->>P2: mcpRefreshError if reconcile fails
    P2-->>P1: warnings surfaced to caller
Loading
Files changed (8 of 14 shown)
File What changed
packages/acp-bridge/src/bridge.ts Per-session effectiveCwd plus a cwdChangeQueue; direct shell awaits in-flight cd changes (raced against abort) and runs in the effective cwd; worktree sessions carry the defer-MCP meta on newSession
packages/acp-bridge/src/bridgeTypes.ts New WORKTREE_MCP_DEFER_META_KEY constant
packages/cli/src/acp-integration/acpAgent.ts Reads the defer meta to skip boot MCP discovery; surfaces MCP refresh failures as cd warnings; stops hard-coding cwd on ACP stdio servers so relocation can rebind them
packages/cli/src/ui/commands/cdCommand.ts Reports an MCP refresh failure as a warning after a successful move
packages/core/src/config/config.ts relocateWorkingDirectory now reconciles MCP too (waitForMcpReady + refreshMcpServers) and returns mcpRefreshError; reconcile body extracted into refreshMcpServers
packages/core/src/tools/mcp-client-manager.ts New getEffectiveMcpServers single source of truth; six inline populateMcpServerCommand calls routed through it
packages/core/src/tools/mcp-client.ts populateMcpServerCommand takes an optional cwd and stamps it onto implicit stdio servers; no longer mutates the input map
7 test files Coverage for cwd serialization, the abort race, MCP deferral, cwd stamping, reconcile-after-relocate, and the warning paths

Testing

CI signal for the reviewed commit (fetched via the API; I do not run PR code):

Check Conclusion
Test (ubuntu-latest, Node 22.x) success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) success
Post Coverage Comment (ubuntu-latest, 22.x) success
Classify PR success
Test (macos-latest, Node 22.x) skipped
Test (windows-latest, Node 22.x) skipped
Integration Tests (CLI, No Sandbox) skipped

The ubuntu unit suite and the web-shell E2E smoke are green; macOS/Windows tests and the no-sandbox integration suite are skipped (conditional on this trigger), not failed — no red checks, so no log excerpt to quote. The review-pr check still in flight is a pull_request_target bot orchestration job, not PR CI, and both pull_request workflow runs (Qwen Code CI, SDK Java) completed green.

The author's before/after table (two concurrent daemon sessions isolated per worktree, base HEAD unmoved, MCP spawn cwd per worktree) is the author's own manual macOS run — attributed as their claim, not independently re-run here.

Sandboxed verification would settle the remaining gap: @qwen-code /verify — that two concurrent worktree sessions actually spawn their implicit stdio MCP processes in their own worktrees (and the base HEAD stays put) is currently the author's manual observation on one platform; the unit suite pins the cwd-stamping and cd-serialization logic but passes without exercising a real concurrent daemon run, and this PR touches the high-risk mcp-client and acp-integration paths where that gap is most expensive.

中文说明

代码审查:我在读 diff 前先独立写了方案——按 session 跟踪有效 cwd、direct shell 串行化到在途 cd 之后、集中式给隐式 stdio MCP server 打 cwd 以便 relocation 重新绑定 pool、worktree 延迟 discovery、目录变更时 reconcile MCP。PR 基本就是这个设计,且把六处内联 populateMcpServerCommand 合并为 getEffectiveMcpServers() 正是想要的防分叉手段。

无关键阻塞。承重逻辑正确:cwd 打标的谓词正确排除了 remote/tcp/sdk/显式 cwd 且不再原地修改入参;direct shell 的 abort 竞态健全(失败的 cd 不会让 shell 抛错,而是在上一个 cwd 运行,被中止的命令立即返回);relocateWorkingDirectory 干净地把 reconcile 逻辑抽成 refreshMcpServers() 并在移动后补上 MCP 通道。

两点非阻塞观察:(1) cwdChangeQueue 是按每次 cd 直接赋值而非像 promptQueue 那样链式衔接——对所述"并发 session"场景正确,但单 session 上重叠 cd 可能让排队的 shell 读到迁移中的 cwd,建议确认 cd 在上游已串行化;(2) config.ts 中若干既有注释在抽取时被缩短,属轻微问题。

测试:通过 API 读取本 commit 的 CI——ubuntu 单测与 web-shell E2E smoke 通过;macOS/Windows 与无沙箱集成测试为 skipped(该触发下条件性跳过)而非失败,无红色检查。作者的 before/after 并发隔离表是其本人在 macOS 上的手动运行结果,作为作者声明引用,未在此独立复现。沙箱验证可补上剩余缺口:@qwen-code /verify——两个并发 worktree session 是否真的各自在自己的 worktree 里 spawn 隐式 stdio MCP(且 base HEAD 不动),目前只是作者单平台的手动观测;单测固定了 cwd 打标与 cd 串行化逻辑,但并未跑真实并发 daemon,而本 PR 触及高风险的 mcp-client 与 acp-integration 路径。

Qwen Code · qwen3.8-max-preview

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

@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — solid, well-tested fix that matches my independent design and ships green CI; one point off because the headline concurrent-isolation behaviour rests partly on the author's manual macOS run, and the PR sits on the high-risk mcp-client / acp-integration paths where a sandboxed /verify would buy real assurance.

Stepping back: this solves a problem users actually hit — concurrent worktree sessions clobbering the base checkout — and the reproduction is concrete, not hypothetical. The code is straightforward rather than clever: a per-session effective cwd, a promise tail to keep shell from overtaking cd, and a single source of truth for the cwd-stamped server map. Every change in the diff is in service of the stated goal; the only thing approaching scope creep is the shortening of a few pre-existing comments during the refreshMcpServers extraction, which is cosmetic.

My independent proposal and the PR converged, so I'm not approving for lack of a better alternative — I'm approving because the design is the right one and the execution is clean. The two reservations I'd leave for the maintainer are genuine but non-blocking: confirm that single-session cds are serialized upstream so the un-chained cwdChangeQueue can't expose a mid-transition cwd, and (given the high-risk paths) consider a @qwen-code /verify run to independently confirm the concurrent MCP-spawn isolation rather than relying on the one-platform manual table. If I had to maintain this in six months I'd thank the author — the getEffectiveMcpServers consolidation alone removes a real divergence hazard.

Approving, pinned to the reviewed commit. ✅

中文说明

置信度 4/5——扎实、测试充分的修复,与我独立的设计一致,CI 全绿。扣 1 分是因为"并发隔离"这一核心行为部分依赖作者的手动 macOS 运行,且 PR 落在高风险的 mcp-client / acp-integration 路径上,沙箱 /verify 能提供更切实的保证。

回顾:这解决的是用户真实会遇到的问题——并发 worktree session 覆盖主 checkout——复现具体而非假设。代码直白而非炫技:按 session 的有效 cwd、一条防止 shell 超车 cd 的 promise 尾、以及 cwd 打标后 server map 的唯一真源。diff 中每处改动都服务于既定目标;唯一接近范围蔓延的是抽取 refreshMcpServers 时缩短了若干既有注释,属表面问题。

我的独立方案与 PR 收敛,所以不是因为"没有更好方案"才通过——而是因为设计正确、执行干净。留给维护者的两点保留是真实但非阻塞的:确认单 session 的 cd 在上游已串行化,使未链式衔接的 cwdChangeQueue 不会暴露迁移中的 cwd;以及(鉴于高风险路径)考虑跑一次 @qwen-code /verify 独立确认并发 MCP spawn 隔离,而非依赖单平台手动表格。若半年后由我维护,我会感谢作者——单是 getEffectiveMcpServers 的合并就消除了一个真实的分叉隐患。

已批准,固定在被审查的 commit 上。✅

Qwen Code · qwen3.8-max-preview

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

@github-actions

Copy link
Copy Markdown
Contributor

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

中文

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

@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.2% 83.2% 89.31% 82.53%
Core 87.42% 87.42% 89.05% 86.1%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |    83.2 |    82.53 |   89.31 |    83.2 |                   
 src               |   84.45 |    80.93 |   89.13 |   84.45 |                   
  cli.ts           |   94.21 |    83.33 |     100 |   94.21 | ...72-573,583-584 
  gemini.tsx       |   73.89 |    76.49 |    82.6 |   73.89 | ...1183-1187,1308 
  ...ractiveCli.ts |   85.65 |    81.55 |   87.17 |   85.65 | ...2390,2396,2448 
  ...liCommands.ts |   88.34 |     83.6 |      90 |   88.34 | ...63,480,514,635 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   69.77 |    72.54 |   89.81 |   69.77 |                   
  acpAgent.ts      |   69.43 |     72.4 |   89.84 |   69.43 | ...25,11330-11332 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   97.04 |    95.71 |   93.33 |   97.04 |                   
  filesystem.ts    |   97.04 |    95.71 |   93.33 |   97.04 | ...21-122,238-239 
 ...ration/session |   91.56 |    86.62 |    96.5 |   91.56 |                   
  Session.ts       |   91.14 |     85.5 |   96.03 |   91.14 | ...9148,9175-9179 
  ...entTracker.ts |   91.87 |    89.18 |   88.88 |   91.87 | ...33,197,280-289 
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |    93.1 |    90.72 |     100 |    93.1 | 71,82-85,111-121  
  ...y-replayer.ts |   98.53 |    95.52 |     100 |   98.53 | 238-240           
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    86.76 |     100 |   89.76 | ...54-270,326-328 
  tasksSnapshot.ts |    94.3 |     87.5 |     100 |    94.3 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   95.68 |     93.7 |   96.66 |   95.68 |                   
  ...ageEmitter.ts |   95.34 |    94.11 |     100 |   95.34 | 52-59             
  PlanEmitter.ts   |     100 |    83.33 |     100 |     100 | 59                
  base-emitter.ts  |   78.26 |       75 |     100 |   78.26 | 23-24,26-28       
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   99.17 |    97.43 |     100 |   99.17 | 352-353           
 ...ession/rewrite |    91.8 |    89.13 |   94.44 |    91.8 |                   
  LlmRewriter.ts   |    82.4 |     86.2 |     100 |    82.4 | ...,88-89,166-170 
  ...Middleware.ts |   96.96 |    88.09 |     100 |   96.96 | 144,152-154       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/commands      |   89.02 |    73.18 |   64.51 |   89.02 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   55.55 |      100 |       0 |   55.55 | 18-22,30-40       
  extensions.tsx   |   96.77 |      100 |      50 |   96.77 | 39                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   98.03 |      100 |      50 |   98.03 | 62                
  serve.ts         |   86.85 |     67.3 |     100 |   86.85 | ...32-635,649-653 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   86.94 |    87.09 |   89.61 |   86.94 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |      80 |    84.61 |      80 |      80 | 37-40,49-52,63-66 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.87 |    96.35 |     100 |   95.87 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   93.88 |    85.33 |   94.11 |   93.88 | ...1207,1214-1215 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.49 |    96.51 |     100 |   98.49 | 115-116,161       
  ...tact-store.ts |   93.51 |    87.65 |     100 |   93.51 | ...71,288-289,337 
  pairing.ts       |   72.85 |      100 |      50 |   72.85 | 22-28,57-68       
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |    77.5 |    86.95 |      75 |    77.5 | 72-84,93-97       
  runtime.ts       |   81.42 |    87.71 |     100 |   81.42 | ...70-174,234-236 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |   75.05 |    73.17 |   76.92 |   75.05 | ...31,537-540,552 
  ...ure-format.ts |   93.65 |    82.45 |     100 |   93.65 | ...42,48-49,74-75 
  status.ts        |   78.57 |    59.25 |   66.66 |   78.57 | ...36-137,150-161 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.82 |    87.82 |   87.09 |   88.82 |                   
  consent.ts       |   72.53 |       90 |   42.85 |   72.53 | ...86-142,157-163 
  disable.ts       |     100 |       90 |     100 |     100 | 30                
  enable.ts        |     100 |    91.66 |     100 |     100 | 38                
  install.ts       |   82.95 |    81.57 |      75 |   82.95 | ...96-199,202-211 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |     90.9 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |      75 |    55.55 |     100 |      75 | ...27-131,133-137 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...amples/starter |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-64              
 src/commands/mcp  |   90.17 |    84.39 |   83.33 |   90.17 |                   
  add.ts           |    99.3 |    96.07 |     100 |    99.3 | 154-155           
  approve.ts       |   76.19 |     87.5 |   66.66 |   76.19 | ...,89-99,114-124 
  list.ts          |   92.59 |    83.87 |      80 |   92.59 | ...62-164,180-181 
  reconnect.ts     |   78.85 |    66.66 |   85.71 |   78.85 | 42-55,169-191     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |    85.1 |    86.35 |   85.85 |    85.1 |                   
  agent-prompt.ts  |   90.88 |    92.78 |      96 |   90.88 | ...1268,1738-1807 
  capture-local.ts |   68.57 |     90.9 |      75 |   68.57 | 107-111,158-189   
  ...k-coverage.ts |   48.38 |    14.28 |   66.66 |   48.38 | ...21-226,239-249 
  cleanup.ts       |   90.25 |    83.14 |   83.33 |   90.25 | ...77-482,484-485 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   95.85 |    91.25 |   93.75 |   95.85 | ...1439,1467-1489 
  fetch-pr.ts      |   74.02 |    53.57 |      50 |   74.02 | ...98,332,402-407 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  parse-args.ts    |   99.27 |       96 |     100 |   99.27 | 345,417           
  plan-diff.ts     |   64.04 |      100 |   66.66 |   64.04 | 127-163           
  pr-context.ts    |   84.44 |    79.38 |   91.66 |   84.44 | ...29-910,939-941 
  presubmit.ts     |   83.75 |    92.72 |   88.88 |   83.75 | ...77-578,655-685 
  ...ve-anchors.ts |   77.02 |    88.46 |      75 |   77.02 | ...70-175,187-204 
  run.ts           |   81.14 |    86.17 |    90.9 |   81.14 | ...13,429-477,490 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...59-773,775-797 
  submit.ts        |   76.74 |    82.05 |   81.81 |   76.74 | ...03-639,641-642 
  test-efficacy.ts |   87.11 |    83.43 |   93.33 |   87.11 | ...1394,1402-1422 
 ...nds/review/lib |   95.77 |    93.13 |   95.74 |   95.77 |                   
  agent-briefs.ts  |   98.68 |      100 |       0 |   98.68 | 520-521           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  coverage.ts      |   95.47 |    94.25 |   95.45 |   95.47 | ...98,335,433-450 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.01 |     100 |   98.73 | ...41,264,290-291 
  effort.ts        |     100 |      100 |     100 |     100 |                   
  gh.ts            |    85.6 |    88.37 |   71.42 |    85.6 | ...20,257-258,285 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  local-diff.ts    |    84.4 |    88.46 |     100 |    84.4 | ...63-473,475-483 
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |     100 |    85.71 |     100 |     100 | 70                
  prompt-record.ts |   94.73 |    88.23 |     100 |   94.73 | ...28,151-152,156 
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  report.ts        |   94.38 |    93.75 |     100 |   94.38 | 173-177           
  roster.ts        |     100 |    94.23 |     100 |     100 | 143,161,206       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.27 |    93.18 |     100 |   96.27 | ...83,269-270,294 
  workspaces.ts    |   97.76 |     91.2 |     100 |   97.76 | 186-187,212-213   
 ...mands/sessions |   91.56 |    86.95 |   83.33 |   91.56 |                   
  common.ts        |     100 |      100 |     100 |     100 |                   
  list.ts          |   90.96 |    86.66 |   81.81 |   90.96 | 208-219,221-222   
 src/config        |    94.2 |    88.75 |   95.91 |    94.2 |                   
  auth.ts          |   89.35 |    83.56 |     100 |   89.35 | ...97-298,314-315 
  ...eMcpImport.ts |   87.91 |    81.52 |     100 |   87.91 | ...63-371,453-454 
  compile-cache.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   88.33 |    88.34 |   84.84 |   88.33 | ...2394,2396-2404 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.04 |    88.28 |     100 |   83.04 | ...39,253,352-353 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |   94.33 |    89.61 |   94.73 |   94.33 | ...35-639,655-656 
  ...le-watcher.ts |   90.86 |    83.65 |   95.83 |   90.86 | ...23-325,370,418 
  ...resh-state.ts |   90.57 |    97.29 |   93.75 |   90.57 | 137-142,146-152   
  ...ime-reload.ts |     100 |    69.69 |     100 |     100 | ...12-113,122-123 
  hot-reload.ts    |     100 |    89.13 |     100 |     100 | 47,172-178,238    
  keyBindings.ts   |   97.38 |       50 |     100 |   97.38 | 234-237           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.87 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   90.99 |     92.3 |      90 |   90.99 | ...1006,1008-1009 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...ngsWatcher.ts |   95.54 |    88.34 |     100 |   95.54 | ...28,277-278,293 
  ...d-env-keys.ts |     100 |      100 |     100 |     100 |                   
  ...l-settings.ts |     100 |      100 |     100 |     100 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...tedFolders.ts |   93.35 |    94.11 |     100 |   93.35 | ...90-391,427-438 
 ...nfig/migration |   95.23 |    77.77 |   83.33 |   95.23 |                   
  index.ts         |   95.65 |     87.5 |     100 |   95.65 | 117-118           
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.91 |      100 |     100 |   94.91 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |      100 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
  v5-to-v4.ts      |      96 |      100 |     100 |      96 | 94-95,99          
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |    71.8 |    70.31 |   66.66 |    71.8 |                   
  ...tputBridge.ts |   71.95 |    70.96 |   68.42 |   71.95 | ...08-409,417-420 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   85.98 |    81.92 |   89.65 |   85.98 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languages.ts     |   93.07 |     92.3 |   85.71 |   93.07 | ...35,164-169,184 
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |      80 |    76.31 |   81.35 |      80 |                   
  session.ts       |   84.08 |    75.27 |   93.61 |   84.08 | ...1007,1016-1026 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...24-625,628-629 
 ...active/control |   76.11 |    89.09 |      80 |   76.11 |                   
  ...rolContext.ts |    6.45 |        0 |       0 |    6.45 | 56-95             
  ...Dispatcher.ts |   91.79 |    92.45 |   88.88 |   91.79 | ...49-367,387,390 
  ...rolService.ts |     7.4 |        0 |       0 |     7.4 | 46-185            
 ...ol/controllers |   39.78 |    63.24 |   47.22 |   39.78 |                   
  ...Controller.ts |   39.49 |      100 |      80 |   39.49 | 88-92,127-210     
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   49.11 |    62.96 |   54.54 |   49.11 | ...63-568,570-575 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |   37.92 |    60.71 |   46.66 |   37.92 | ...41-653,662-691 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.07 |    94.05 |   95.23 |   98.07 |                   
  ...putAdapter.ts |   97.98 |     93.2 |   98.07 |   97.98 | ...1415,1431-1432 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 84-85,125-126     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   87.31 |    75.32 |   88.23 |   87.31 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.01 |       76 |   93.33 |   88.01 | ...49-350,361-364 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |   87.25 |    83.34 |   91.06 |   87.25 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |    93.4 |    92.95 |     100 |    93.4 | ...19-320,323-325 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    97.87 |     100 |     100 | 638               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...livery-ipc.ts |     100 |     90.9 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  ...op-mcp-ipc.ts |   81.06 |    73.68 |   94.11 |   81.06 | ...37-242,267,289 
  ...nt-service.ts |   93.89 |    86.61 |     100 |   93.89 | ...66-468,475,477 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   85.85 |    91.78 |   95.83 |   85.85 | ...94-206,366-369 
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   87.27 |     85.2 |     100 |   87.27 | ...10,816-820,838 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   92.41 |    84.44 |    97.1 |   92.41 | ...1460,1514-1518 
  ...e-grouping.ts |     100 |    94.11 |     100 |     100 | 69,132            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |   92.04 |    77.77 |     100 |   92.04 | ...36-445,470,508 
  daemon-logger.ts |    82.2 |    77.26 |   91.76 |    82.2 | ...1720,1747-1753 
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.37 |    90.06 |     100 |   98.37 | ...1041,1043-1044 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |    91.3 |       80 |     100 |    91.3 | ...24-127,205-212 
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  ...h-settings.ts |   94.41 |    88.75 |     100 |   94.41 | ...24,702,718,728 
  fast-path.ts     |   90.33 |    80.23 |   95.45 |   90.33 | ...83-492,558-559 
  ...ration-sse.ts |   42.55 |    33.33 |     100 |   42.55 | 23-24,30,33-56    
  health-query.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-143             
  ...e-observer.ts |   89.89 |    83.24 |      96 |   89.89 | ...11-512,541-543 
  ...back-binds.ts |     100 |    88.88 |     100 |     100 | 32                
  ...-workspace.ts |    90.9 |    85.71 |     100 |    90.9 | ...27-128,139-140 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |     100 |    86.95 |     100 |     100 | 36,66,92          
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.77 |    88.42 |     100 |   92.77 | ...93-295,307-309 
  ...qwen-serve.ts |   82.64 |    79.24 |   74.06 |   82.64 | ...6725,6730-6731 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   94.19 |     87.5 |     100 |   94.19 | ...26,530-531,571 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |    93.5 |    93.54 |   72.97 |    93.5 | ...2088,2109-2113 
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    95.23 |     100 |     100 | 12                
  ...-admission.ts |   98.71 |    89.65 |     100 |   98.71 | 68                
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |    93.3 |    76.57 |     100 |    93.3 | ...13,816,829-831 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   91.07 |    86.66 |     100 |   91.07 | ...79-182,216-219 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.58 |       79 |     100 |   98.58 | 106,134,174,177   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   93.89 |     87.5 |     100 |   93.89 | ...18-519,525-526 
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...e-remember.ts |   98.14 |    88.92 |     100 |   98.14 | ...31,335-340,381 
  ...te-runtime.ts |   83.98 |    90.19 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
  ...lls-status.ts |     100 |    92.85 |     100 |     100 | 127               
  ...reconciler.ts |    91.6 |     83.9 |     100 |    91.6 | ...70-272,305-306 
 ...serve/acp-http |      77 |    78.26 |   93.19 |      77 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.62 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   71.44 |    73.89 |   95.34 |   71.44 | ...4733,4781-4787 
  index.ts         |   81.81 |    79.72 |   90.56 |   81.81 | ...2279,2349-2350 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   85.73 |    73.17 |    97.5 |   85.73 |                   
  ...r-emulator.ts |   88.57 |    63.63 |     100 |   88.57 | ...72-175,194-195 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |       0 |        0 |       0 |       0 |                   
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-119             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
 src/serve/fs      |    86.4 |    80.69 |     100 |    86.4 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 204               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...x-registry.ts |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.64 |     73.8 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.42 |    89.18 |     100 |   90.42 | 161-169           
  text-cursor.ts   |   88.23 |       90 |     100 |   88.23 | 74-77,92-95       
  ...ile-system.ts |   86.17 |    79.47 |     100 |   86.17 | ...2506,2516-2517 
 src/serve/routes  |   85.54 |    79.47 |   95.46 |   85.54 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...nel-notify.ts |   85.22 |       88 |     100 |   85.22 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.45 |    83.33 |     100 |   85.45 | 98-105            
  goals.ts         |   98.92 |     90.9 |     100 |   98.92 | 146               
  health-demo.ts   |   94.73 |     86.2 |     100 |   94.73 | 62-66,154         
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.12 |    82.73 |   92.59 |   87.12 | ...1263,1306-1307 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   85.19 |    81.58 |   95.08 |   85.19 | ...4433,4435-4436 
  sse-events.ts    |   84.45 |     87.5 |   77.77 |   84.45 | ...36,453-456,485 
  usage-stats.ts   |     100 |    95.45 |     100 |     100 | 118               
  ...space-auth.ts |   85.55 |    75.64 |     100 |   85.55 | ...21-326,331,345 
  ...el-control.ts |   86.26 |    78.94 |     100 |   86.26 | ...17-318,339-347 
  ...management.ts |   90.19 |    77.68 |     100 |   90.19 | ...47-448,467-468 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.09 |       79 |      90 |   83.09 | ...1032,1038,1041 
  ...extensions.ts |   87.23 |    72.76 |   94.11 |   87.23 | ...1826,1871-1872 
  ...-file-read.ts |      91 |    80.91 |     100 |      91 | ...20-621,624-625 
  ...file-write.ts |   84.44 |    64.51 |     100 |   84.44 | ...73-275,355-357 
  ...t-branches.ts |   75.43 |    66.66 |     100 |   75.43 | ...13-618,627-634 
  ...e-git-diff.ts |   97.32 |    90.56 |     100 |   97.32 | 161-162,189-191   
  ...ce-git-log.ts |     100 |    93.18 |     100 |     100 | 52,77,188         
  workspace-git.ts |   77.08 |    89.65 |     100 |   77.08 | 97-118            
  ...github-prs.ts |   88.26 |    63.46 |     100 |   88.26 | ...38-239,264-265 
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...management.ts |   88.15 |    85.19 |     100 |   88.15 | ...1537,1557-1562 
  ...cp-control.ts |    73.2 |    67.54 |   85.71 |    73.2 | ...27-633,644-645 
  ...ace-models.ts |   95.53 |    89.74 |     100 |   95.53 | ...52-157,296-297 
  ...ermissions.ts |    77.9 |    72.41 |     100 |    77.9 | ...69-277,298-316 
  ...e-settings.ts |   74.81 |    70.31 |     100 |   74.81 | ...47-658,664-665 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |   69.87 |    78.12 |     100 |   69.87 | ...59-284,290-324 
  ...ace-status.ts |   82.94 |     74.5 |     100 |   82.94 | ...84-486,490-491 
  ...pace-tools.ts |   75.94 |    69.69 |   66.66 |   75.94 | ...59-164,193-194 
  ...pace-trust.ts |   78.42 |    64.78 |      80 |   78.42 | ...31-336,344-345 
  ...pace-voice.ts |   91.33 |    80.92 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   90.69 |    89.17 |   96.55 |   90.69 |                   
  access-log.ts    |   98.68 |     97.1 |     100 |   98.68 | 115,186           
  ...er-helpers.ts |   63.82 |    77.96 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    81.81 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.29 |       75 |     100 |   97.29 | 17                
  ...r-response.ts |   85.66 |    76.83 |     100 |   85.66 | ...02,719,782-791 
  fs-factory.ts    |     100 |    92.59 |     100 |     100 | 34,42,103,159     
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.11 |    95.14 |     100 |   95.11 | ...65-167,422-427 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |   94.81 |    90.32 |     100 |   94.81 | 175-181           
  ...on-archive.ts |   89.55 |    87.78 |   97.14 |   89.55 | ...32-836,888-889 
  ...ion-export.ts |     100 |    94.44 |     100 |     100 | 64                
  session-list.ts  |   93.55 |    91.01 |     100 |   93.55 | ...79,681-687,827 
  telemetry.ts     |   99.01 |    97.45 |     100 |   99.01 | ...19,633,775-777 
 src/serve/voice   |   83.35 |    92.22 |   90.47 |   83.35 |                   
  ...ice-config.ts |   84.61 |       30 |     100 |   84.61 | 90-99,103-104     
  voice-ws.ts      |   77.16 |    94.73 |   83.33 |   77.16 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.21 |     100 |     100 | 176               
 ...kspace-service |   89.11 |    86.15 |   90.69 |   89.11 |                   
  index.ts         |   88.66 |    85.77 |   89.47 |   88.66 | ...1286-1290,1293 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.23 |    88.48 |   97.82 |   92.23 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 104-117           
  ...killLoader.ts |   97.14 |    87.87 |     100 |   97.14 | 140,151-152       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   79.55 |    88.29 |   83.33 |   79.55 | ...48,178,245-246 
  ...mandLoader.ts |   97.36 |    92.68 |     100 |   97.36 | 153,160-161       
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.23 |    96.72 |     100 |   98.23 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  prompt-stash.ts  |   96.66 |    92.85 |     100 |   96.66 | 34-35             
  ...tree-lease.ts |   88.29 |    86.48 |     100 |   88.29 | ...91-196,229-230 
  ...low-loader.ts |     100 |    96.15 |     100 |     100 | 88                
  setup-github.ts  |    90.8 |    80.95 |     100 |    90.8 | ...49-450,457-458 
  ...-args-file.ts |   93.54 |    90.47 |    87.5 |   93.54 | 201-203,217-223   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.71 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |   90.37 |    87.87 |     100 |   90.37 | ...80,287,352-357 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   90.46 |    82.19 |      96 |   90.46 | ...66-668,671-673 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |    86.29 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.24 |   94.73 |   88.28 | ...1352,1356-1363 
  ...tGenerator.ts |   98.24 |    85.71 |     100 |   98.24 | 47                
  ...teRenderer.ts |     100 |      100 |     100 |     100 |                   
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |   93.26 |       75 |   83.33 |   93.26 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   72.11 |    75.58 |   64.63 |   72.11 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   73.26 |    72.45 |   67.85 |   73.26 | ...4122,4164-4174 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |    30.3 |      100 |       0 |    30.3 | 26-76             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   66.97 |    65.71 |   33.33 |   66.97 | ...77,292,323-328 
  ...inePresets.ts |   96.27 |    83.87 |     100 |   96.27 | ...97,402,410-412 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   58.53 |    66.18 |   51.06 |   58.53 |                   
  AuthDialog.tsx   |   59.01 |     42.1 |   16.66 |   59.01 | ...25,332-354,358 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.21 |    70.73 |   57.69 |   60.21 | ...90,794,803,806 
  useAuth.ts       |    94.6 |    73.52 |     100 |    94.6 | ...21-222,241-247 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |    81.4 |    82.99 |    89.4 |    81.4 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |    93.1 |    95.23 |     100 |    93.1 | 77-82             
  arenaCommand.ts  |   63.89 |    65.71 |   65.21 |   63.89 | ...01-606,691-699 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    81.25 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |    92.3 |    82.75 |     100 |    92.3 | ...,94-99,178,187 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...24-125,133-142 
  ...essCommand.ts |   67.95 |    55.88 |      75 |   67.95 | ...86-187,201-204 
  ...astCommand.ts |   84.17 |       75 |     100 |   84.17 | ...,91-97,125-130 
  ...ig-command.ts |   93.12 |    88.42 |     100 |   93.12 | ...07-315,321-323 
  ...extCommand.ts |   68.28 |    70.14 |   84.61 |   68.28 | ...66-599,610-611 
  copyCommand.ts   |    98.7 |    96.29 |     100 |    98.7 | 66-67,172,272,323 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |    87.87 |     100 |     100 | ...63,231-232,245 
  ...ryCommand.tsx |   81.64 |    87.67 |    90.9 |   81.64 | ...73-278,325-332 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   65.37 |    81.88 |   94.11 |   65.37 | ...85-535,538-672 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...rt-command.ts |   82.97 |    78.57 |     100 |   82.97 | 47-52,67-70,91-96 
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   52.31 |    56.25 |   69.23 |   52.31 | ...09,277-329,390 
  forgetCommand.ts |     100 |       90 |     100 |     100 | 59                
  forkCommand.ts   |     100 |    94.11 |     100 |     100 | 96,147            
  goalCommand.ts   |   91.13 |    83.72 |      90 |   91.13 | ...81-184,196-199 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...oryCommand.ts |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.13 |    65.71 |   85.71 |   81.13 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  ...figCommand.ts |   52.83 |    81.25 |      70 |   52.83 | ...74-319,321-330 
  initCommand.ts   |   91.86 |       80 |     100 |   91.86 | 48,83-88          
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   93.45 |    89.06 |     100 |   93.45 | ...68-169,196-206 
  learn-command.ts |     100 |      100 |     100 |     100 |                   
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   86.27 |    83.01 |     100 |   86.27 | ...22-935,969-974 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...ns-command.ts |   98.83 |    81.81 |     100 |   98.83 | 100               
  ...berCommand.ts |     100 |     87.5 |     100 |     100 | 46                
  renameCommand.ts |   89.06 |    88.37 |     100 |   89.06 | ...72-176,202-209 
  ...oreCommand.ts |    90.9 |    86.04 |     100 |    90.9 | ...41-146,176-177 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.43 |      100 |      50 |    6.43 | 31-330            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   91.82 |    78.87 |   66.66 |   91.82 | ...59-160,169-174 
 src/ui/components |   70.64 |    78.44 |   76.29 |   70.64 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  ...ateScreen.tsx |   97.29 |     87.5 |   66.66 |   97.29 | 49                
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |    88.7 |       75 |     100 |    88.7 | 36,38-43,45       
  ...odeDialog.tsx |   87.24 |    72.22 |   33.33 |   87.24 | ...85,233-238,245 
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   95.65 |    66.66 |     100 |   95.65 | 27,52             
  ...TextInput.tsx |   88.65 |    90.41 |     100 |   88.65 | ...84-286,300-302 
  Composer.tsx     |   94.49 |    66.66 |     100 |   94.49 | ...-72,84,139,153 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  CronPill.tsx     |     100 |    93.75 |     100 |     100 | 19                
  ...ification.tsx |      84 |       60 |     100 |      84 | 23-24,40-42       
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |       0 |        0 |       0 |       0 | 1-597             
  DiffDialog.tsx   |    53.5 |     37.5 |   69.23 |    53.5 | ...32-737,747-760 
  ...ngsDialog.tsx |       0 |        0 |       0 |       0 | 1-195             
  EffortDialog.tsx |   97.36 |      100 |     100 |   97.36 | 55-56             
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   75.11 |     61.4 |      50 |   75.11 | ...48-253,271-275 
  ...ngSpinner.tsx |   68.42 |    85.71 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   83.33 |    76.92 |     100 |   83.33 | 24-30             
  Header.tsx       |   98.65 |    94.73 |     100 |   98.65 | 173,175           
  Help.tsx         |   98.33 |       90 |     100 |   98.33 | ...25,382,448-449 
  ...emDisplay.tsx |   78.51 |     65.3 |     100 |   78.51 | ...99,502,505-511 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   83.08 |    81.73 |      80 |   83.08 | ...2197,2223,2297 
  ...Shortcuts.tsx |   20.65 |      100 |       0 |   20.65 | ...7,50-52,68-126 
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   95.82 |    92.53 |      50 |   95.82 | ...97,440-444,447 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   83.41 |    71.65 |     100 |   83.41 | ...69,971,976-992 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |       0 |        0 |       0 |       0 | 1-56              
  ...onsDialog.tsx |       0 |        0 |       0 |       0 | 1-1004            
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |       0 |        0 |       0 |       0 | 1-39              
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   93.58 |    83.78 |     100 |   93.58 | ...,70-71,195-197 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.49 |    73.89 |   69.23 |   71.49 | ...1244,1250-1251 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |       0 |        0 |       0 |       0 | 1-40              
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-172             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   92.97 |    83.87 |     100 |   92.97 | ...43,246,273-275 
  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             
  ...criptView.tsx |   98.27 |    84.21 |     100 |   98.27 | 45,53             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |   53.72 |    70.87 |   42.85 |   53.72 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   64.78 |    29.41 |   33.33 |   64.78 | ...51,269,277-279 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    42.3 |    68.69 |   73.68 |    42.3 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |       0 |        0 |       0 |       0 | 1-166             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |    82.2 |    81.36 |    90.9 |    82.2 |                   
  ...sksDialog.tsx |   77.53 |     76.9 |   80.76 |   77.53 | ...1781,1803-1809 
  ...TasksPill.tsx |   67.03 |     86.2 |     100 |   67.03 | ...02-122,130-138 
  ...gentPanel.tsx |   97.08 |    86.31 |     100 |   97.08 | 132,442-446,520   
  agent-forest.ts  |    99.2 |    93.93 |     100 |    99.2 | 258               
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
  ...e-overlay.tsx |    88.2 |    76.47 |     100 |    88.2 | ...36-138,140-142 
 ...nts/extensions |   84.32 |    76.78 |   83.33 |   84.32 |                   
  ...gerDialog.tsx |   82.15 |    76.08 |     100 |   82.15 | ...91-198,258,260 
  TabBar.tsx       |   97.29 |    88.88 |     100 |   97.29 | 33                
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   46.26 |       85 |   58.82 |   46.26 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |       0 |        0 |       0 |       0 | 1-145             
  ...nListStep.tsx |   75.26 |    88.37 |   66.66 |   75.26 | ...53,174,203-209 
  ...electStep.tsx |       0 |        0 |       0 |       0 | 1-83              
  ...nfirmStep.tsx |   16.32 |      100 |       0 |   16.32 | 28-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
 ...xtensions/tabs |   71.92 |    68.14 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.28 |   83.33 |   75.49 | ...77,782-783,820 
  SourcesTab.tsx   |   71.67 |    70.47 |   77.77 |   71.67 | ...28,547,621-633 
 ...tensions/views |   50.97 |    52.38 |   20.83 |   50.97 |                   
  ...tionsView.tsx |   73.75 |    56.36 |   66.66 |   73.75 | ...30,353,369-374 
  ...tionsView.tsx |   43.45 |    44.82 |    6.66 |   43.45 | ...98-405,408-420 
  ...etailView.tsx |    9.56 |      100 |       0 |    9.56 | 40-67,70-158      
 ...mponents/hooks |   86.99 |    81.37 |   91.89 |   86.99 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.04 |    61.53 |   70.58 |   40.04 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   89.97 |    86.16 |      87 |   89.97 |                   
  ...ionDialog.tsx |   89.23 |    84.27 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   96.71 |    97.77 |   91.66 |   96.71 | 223-233           
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   76.52 |     42.1 |   66.66 |   76.52 | ...00,102,125,156 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   89.75 |     79.1 |     100 |   89.75 | ...33-635,642-644 
  ...upMessage.tsx |   98.32 |    95.16 |     100 |   98.32 | 184-187,414       
  ToolMessage.tsx  |   92.49 |    84.92 |   93.33 |   92.49 | ...61-966,993-995 
 ...ponents/shared |   85.76 |    82.09 |   94.05 |   85.76 |                   
  ...ctionList.tsx |     100 |      100 |      75 |     100 |                   
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  ...rBoundary.tsx |     100 |      100 |     100 |     100 |                   
  MaxSizedBox.tsx  |   84.71 |    86.86 |      90 |   84.71 | ...67-568,685-686 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...ontroller.tsx |     100 |    83.33 |     100 |     100 | 73,93-95          
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   81.48 |    84.84 |     100 |   81.48 | 46-66,73-76       
  StaticRender.tsx |   72.72 |      100 |     100 |   72.72 | 31-33             
  TextInput.tsx    |    80.8 |    67.24 |      80 |    80.8 | ...36-240,252-258 
  ...ontroller.tsx |     100 |    81.81 |     100 |     100 | 59-62             
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   88.51 |    85.11 |   81.81 |   88.51 | ...51-779,792,887 
  text-buffer.ts   |   85.98 |    81.81 |   97.91 |   85.98 | ...2664,2762-2763 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |       0 |        0 |       0 |       0 |                   
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-681             
 ...ents/subagents |       0 |        0 |       0 |       0 |                   
  constants.ts     |       0 |        0 |       0 |       0 | 1-71              
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |       0 |        0 |       0 |       0 | 1-190             
  types.ts         |       0 |        0 |       0 |       0 | 1-125             
  utils.ts         |       0 |        0 |       0 |       0 | 1-102             
 ...bagents/create |       0 |        0 |       0 |       0 |                   
  ...ionWizard.tsx |       0 |        0 |       0 |       0 | 1-299             
  ...rSelector.tsx |       0 |        0 |       0 |       0 | 1-85              
  ...onSummary.tsx |       0 |        0 |       0 |       0 | 1-331             
  ...tionInput.tsx |       0 |        0 |       0 |       0 | 1-177             
  ...dSelector.tsx |       0 |        0 |       0 |       0 | 1-63              
  ...nSelector.tsx |       0 |        0 |       0 |       0 | 1-58              
  ...EntryStep.tsx |       0 |        0 |       0 |       0 | 1-78              
  ToolSelector.tsx |       0 |        0 |       0 |       0 | 1-253             
 ...bagents/manage |   14.14 |    53.19 |    37.5 |   14.14 |                   
  ...ctionStep.tsx |       0 |        0 |       0 |       0 | 1-103             
  ...eleteStep.tsx |       0 |        0 |       0 |       0 | 1-62              
  ...tEditStep.tsx |       0 |        0 |       0 |       0 | 1-124             
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |       0 |        0 |       0 |       0 | 1-73              
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-341             
 ...mponents/views |   69.81 |    72.64 |   61.11 |   69.81 |                   
  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 |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   84.11 |    81.79 |    86.3 |   84.11 |                   
  ...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 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   85.92 |    85.15 |     100 |   85.92 | ...1607-1609,1615 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   80.77 |       80 |    92.3 |   80.77 | ...31-434,443-446 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...edContext.tsx |     100 |      100 |      50 |     100 |                   
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 155-156           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 234-235           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
  ...rtContext.tsx |     100 |      100 |     100 |     100 |                   
 src/ui/daemon     |   88.35 |    73.51 |   95.45 |   88.35 |                   
  ...ui-adapter.ts |   88.35 |    73.51 |   95.45 |   88.35 | ...74,792-793,879 
 src/ui/editors    |       0 |        0 |       0 |       0 |                   
  ...ngsManager.ts |       0 |        0 |       0 |       0 | 1-67              
 src/ui/hooks      |   84.95 |    82.54 |   89.57 |   84.95 |                   
  ...dProcessor.ts |   83.95 |    83.95 |     100 |   83.95 | ...39-871,918-919 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...86-287,292-293 
  ...dProcessor.ts |   85.21 |     66.4 |   81.81 |   85.21 | ...1407,1428-1432 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.ts |     100 |      100 |     100 |     100 |                   
  ...oice-input.ts |   92.36 |    81.95 |   66.66 |   92.36 | ...00,502-503,658 
  ...ke-repaint.ts |     100 |      100 |     100 |     100 |                   
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      42 |       75 |     100 |      42 | 42-44,53-59,62-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   86.44 |    88.48 |     100 |   86.44 | ...14-515,525-541 
  ...ifications.ts |   87.82 |    96.77 |     100 |   87.82 | 138-152           
  ...tIndicator.ts |   88.28 |    81.08 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.73 |    76.59 |     100 |   94.73 | 162-166,255,261   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   94.85 |    80.76 |     100 |   94.85 | ...54,229,292-295 
  ...ompletion.tsx |   97.09 |    87.09 |     100 |   97.09 | ...23-324,334-335 
  ...dMigration.ts |    92.1 |    88.88 |     100 |    92.1 | 42-44             
  useCompletion.ts |   96.29 |    90.56 |     100 |   96.29 | ...17-218,222-223 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   78.26 |       50 |     100 |   78.26 | ...2,75-79,96-104 
  ...eteCommand.ts |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...ialogClose.ts |   36.11 |       10 |     100 |   36.11 | ...89-195,202-207 
  useDiffData.ts   |       0 |        0 |       0 |       0 | 1-87              
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.72 |    92.98 |     100 |   93.72 | ...87-291,314-320 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |    63.9 |    76.47 |   66.66 |    63.9 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |    93.33 |     100 |     100 | 62                
  ...ggestions.tsx |   96.47 |    78.94 |     100 |   96.47 | 121,155-156       
  ...miniStream.ts |   85.66 |    81.38 |   96.15 |   85.66 | ...3943,4111-4119 
  ...BranchName.ts |     100 |    94.44 |     100 |     100 | 54                
  ...oryManager.ts |   98.01 |    98.36 |     100 |   98.01 | 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 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   63.15 |       80 |      50 |   63.15 | 42-52,64-67       
  ...cpApproval.ts |   93.12 |    86.11 |     100 |   93.12 | ...24-127,139-140 
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |   83.14 |    78.57 |     100 |   83.14 | 54-63,74-79       
  ...ssageQueue.ts |     100 |     97.5 |     100 |     100 | 99                
  ...delCommand.ts |     100 |       95 |     100 |     100 | 53                
  ...ouseEvents.ts |   94.38 |    97.36 |   83.33 |   94.38 | 77-81             
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derUpdates.ts |    87.4 |    78.78 |     100 |    87.4 | ...71,321-333,381 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   88.95 |    86.95 |     100 |   88.95 | ...37-439,471-481 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   94.67 |    74.28 |     100 |   94.67 | ...19,174,233-238 
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.22 |     100 |   97.12 | ...92-193,247-250 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |    97.29 |     100 |     100 | 82                
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   93.28 |    80.95 |     100 |   93.28 | ...96,153-154,164 
  ...oryCommand.ts |   85.48 |    58.33 |     100 |   85.48 | 22-28,40,71       
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.85 |    85.13 |   94.73 |   82.85 | ...78-680,688-724 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   97.13 |    93.33 |     100 |   97.13 | ...78-382,478-485 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   67.34 |    58.82 |   66.66 |   67.34 | 52-53,61-68,79-85 
  ...rminalSize.ts |     100 |      100 |     100 |     100 |                   
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   97.59 |    94.73 |     100 |   97.59 | 17-18             
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |    90.47 |     100 |     100 | 112,134           
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    91.2 |    89.47 |     100 |    91.2 |                   
  ...AppLayout.tsx |    90.9 |     87.5 |     100 |    90.9 | 60-62,110-115,151 
  ...AppLayout.tsx |   91.66 |    92.85 |     100 |   91.66 | 75-80             
 src/ui/models     |   80.72 |       80 |   71.42 |   80.72 |                   
  ...ableModels.ts |   80.72 |       80 |   71.42 |   80.72 | ...,61-71,125-127 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 src/ui/selection  |   86.47 |    79.88 |   96.66 |   86.47 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   92.72 |       90 |     100 |   92.72 | 37-38,67-68       
  ...tion-state.ts |   85.71 |      100 |   88.88 |   85.71 | 51-58             
  ...ction-text.ts |   92.85 |    92.45 |     100 |   92.85 | 30-34,114-115     
  ...selection.tsx |   80.31 |    59.64 |     100 |   80.31 | ...13-314,330-331 
 src/ui/state      |      95 |    81.81 |     100 |      95 |                   
  extensions.ts    |      95 |    81.81 |     100 |      95 | 69-70,89          
 src/ui/themes     |    98.5 |    73.17 |     100 |    98.5 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |   99.23 |    97.05 |     100 |   99.23 | 277-278           
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   88.68 |    84.52 |     100 |   88.68 | ...83-392,397-398 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |    86.6 |       85 |    95.3 |    86.6 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   79.84 |     75.6 |     100 |   79.84 | ...66,270,328-329 
  ...wnDisplay.tsx |   92.87 |    93.46 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.38 |    81.91 |   95.23 |   92.38 | ...43-746,799-804 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |    96.7 |     87.5 |     100 |    96.7 | 170-177,278       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   52.52 |    73.25 |   91.66 |   52.52 | ...23,626-635,638 
  commandUtils.ts  |   96.17 |    88.88 |     100 |   96.17 | ...77,179-180,323 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   73.84 |    73.91 |     100 |   73.84 | ...34,36-40,42-46 
  formatters.ts    |    95.4 |    98.38 |     100 |    95.4 | 123-126           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |       95 |     100 |     100 | 44,103            
  historyUtils.ts  |      96 |    97.05 |     100 |      96 | 102-105           
  inline-math.ts   |   98.48 |    95.23 |     100 |   98.48 | 129-130           
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   69.47 |       75 |   66.66 |   69.47 | ...24-129,157-158 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  list-mouse.ts    |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |       95 |     100 |     100 | 81                
  ...nUtilities.ts |   98.72 |    94.36 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.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         |   92.85 |    74.19 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   90.43 |    78.33 |     100 |   90.43 | ...59,244,248-249 
  ...red-height.ts |   98.38 |     97.1 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   79.32 |    77.37 |     100 |   79.32 | ...32-554,685-686 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...evel-label.ts |   77.77 |    66.66 |     100 |   77.77 | 18,22-24          
  ...are-cursor.ts |   89.47 |    85.71 |     100 |   89.47 | 39-44             
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  suggestions.ts   |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   95.97 |    94.06 |   94.44 |   95.97 | ...29-330,490-491 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   90.42 |    92.85 |     100 |   90.42 | ...06-207,240-241 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |    92.75 |     100 |     100 | 227-239,331       
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |    59.89 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    65.81 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    50.68 |     100 |   80.42 | ...59-364,376-378 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...ort/formatters |   52.92 |    47.22 |   71.42 |   52.92 |                   
  html.ts          |   84.61 |       50 |     100 |   84.61 | ...53,57-58,62-63 
  json.ts          |     100 |      100 |     100 |     100 |                   
  jsonl.ts         |   82.45 |     37.5 |     100 |   82.45 | ...48,50-51,65-66 
  markdown.ts      |   36.32 |    47.05 |      50 |   36.32 | ...16-219,233-295 
 src/ui/voice      |   80.94 |    72.69 |   80.55 |   80.94 |                   
  ...d-recorder.ts |     6.2 |      100 |       0 |     6.2 | ...33-159,162-163 
  ...o-recorder.ts |   84.61 |    93.33 |   57.14 |   84.61 | ...16-117,131-136 
  ...me-session.ts |   89.72 |    65.33 |   93.75 |   89.72 | ...99,305,316-319 
  sox-recorder.ts  |    92.7 |    71.87 |     100 |    92.7 | ...34-135,153-154 
  ...ailability.ts |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |     100 |      100 |     100 |     100 |                   
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  ...e-recorder.ts |   88.29 |    67.74 |   81.81 |   88.29 | ...,98-99,112,115 
  voice-refine.ts  |     100 |    93.33 |     100 |     100 | 92                
  ...ream-retry.ts |   86.79 |    68.42 |     100 |   86.79 | 16-18,48-49,59-60 
  ...am-session.ts |   88.02 |    66.66 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |   81.37 |    87.04 |   92.49 |   81.37 |                   
  ...p-profiler.ts |   98.39 |    90.56 |     100 |   98.39 | 141,185,235       
  acpModelUtils.ts |   97.36 |    95.19 |     100 |   97.36 | ...09-210,214-215 
  apiPreconnect.ts |   96.74 |    94.59 |     100 |   96.74 | 167-170           
  ...ol-call-id.ts |   84.61 |       60 |     100 |   84.61 | 26-27,37-38       
  ...ng-failure.ts |     100 |       95 |     100 |     100 | 72                
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  ...-api-error.ts |     100 |    96.42 |     100 |     100 | 14                
  cleanup.ts       |   84.05 |    94.11 |      80 |   84.05 | 80,111-121        
  commands.ts      |   97.45 |    96.66 |     100 |   97.45 | 153-155           
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.73 |    73.23 |   88.88 |   70.73 | ...27,430-431,438 
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...re-runtime.ts |     100 |      100 |     100 |     100 |                   
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.64 |     100 |   97.56 | 69-70,304-305     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |   92.85 |    86.66 |     100 |   92.85 | ...13-116,164-167 
  ...AutoUpdate.ts |    93.1 |       94 |      90 |    93.1 | 103,108,179-190   
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.68 |    94.28 |     100 |   97.68 | ...59,376-377,422 
  jsonc-editor.ts  |   93.18 |    92.72 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.05 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   89.05 |    76.38 |     100 |   89.05 | ...86,302-303,340 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   94.25 |    91.17 |     100 |   94.25 | ...30,436,439-443 
  ...iveHelpers.ts |   95.13 |    91.79 |     100 |   95.13 | ...53-454,552,565 
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  ...uggestions.ts |   74.38 |    69.56 |     100 |   74.38 | ...92-103,105-116 
  processUtils.ts  |    92.3 |       80 |     100 |    92.3 | 45-46             
  readStdin.ts     |   93.67 |    94.11 |   85.71 |   93.67 | 79-83             
  relaunch.ts      |   95.87 |    89.28 |     100 |   95.87 | 103-105,131       
  resolvePath.ts   |     100 |      100 |     100 |     100 |                   
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox-path.ts  |     100 |      100 |     100 |     100 |                   
  sandbox.ts       |   45.67 |    56.93 |   76.92 |   45.67 | ...1034,1046-1069 
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.ts |     100 |      100 |     100 |     100 |                   
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.35 |    89.57 |      90 |   82.35 | ...25-743,750-758 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   39.81 |    77.44 |   62.16 |   39.81 | ...1193,1196-1215 
  ...upProfiler.ts |   98.47 |    94.66 |     100 |   98.47 | 132-133,308       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |     87.5 |     100 |     100 | 23                
  systemInfo.ts    |   95.12 |    90.27 |     100 |   95.12 | ...54-255,260-264 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  ...alSequence.ts |     100 |    97.61 |     100 |     100 | 60                
  ...iffPreview.ts |   76.47 |       25 |     100 |   76.47 | 13,17,23-24       
  ...e-relaunch.ts |   89.61 |    86.66 |      50 |   89.61 | 56-61,83-84       
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   87.75 |       75 |     100 |   87.75 | 47-48,53-54,57-58 
  version.ts       |     100 |    66.66 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |   95.45 |    93.33 |     100 |   95.45 | 54-55             
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   91.63 |    91.02 |      95 |   91.63 |                   
  cleanup.ts       |   95.77 |    95.83 |     100 |   95.77 | 70-72             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   91.91 |    90.47 |    87.5 |   91.91 | 58-62,73,131-135  
  throttledOnce.ts |   86.66 |     86.2 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   87.42 |     86.1 |   89.05 |   87.42 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   90.24 |    84.12 |   95.16 |   90.24 |                   
  ...transcript.ts |   87.63 |    83.52 |     100 |   87.63 | ...79,587,593-597 
  ...ent-resume.ts |   85.52 |    77.55 |   83.33 |   85.52 | ...1779-1783,1786 
  ...ound-tasks.ts |   96.15 |     90.1 |   98.76 |   96.15 | ...1732,1752-1755 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   95.65 |    89.41 |     100 |   95.65 | ...12-413,485-489 
  ...w-snapshot.ts |   91.86 |       75 |     100 |   91.86 | ...54,178,185-187 
 src/agents/arena  |   76.32 |    67.71 |   78.94 |   76.32 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.11 |    64.51 |   78.57 |   75.11 | ...1887,1893-1894 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   78.09 |    85.23 |   76.28 |   78.09 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    90.9 |    85.36 |   93.33 |    90.9 | ...70,672,674-675 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   90.37 |    85.82 |   87.44 |   90.37 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   85.05 |    76.73 |   77.77 |   85.05 | ...2287,2333-2335 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    89.41 |   83.33 |   93.49 | ...96-497,500-501 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.34 |      100 |    92.3 |   98.34 | 81-82             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...ow-journal.ts |   91.76 |    75.86 |     100 |   91.76 | ...38-139,179-181 
  ...chestrator.ts |   91.79 |    87.79 |   82.35 |   91.79 | ...1774,1823-1826 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...ow-sandbox.ts |   96.87 |    94.51 |     100 |   96.87 | ...24-325,330-331 
  ...flow-saved.ts |   96.51 |    94.36 |     100 |   96.51 | 134-135,234-237   
  ...flow-stall.ts |    97.9 |    83.33 |     100 |    97.9 | 138-139,236       
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   81.81 |    83.99 |    87.5 |   81.81 |                   
  TeamManager.ts   |   72.02 |    79.41 |   79.24 |   72.02 | ...1632,1655-1656 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   94.76 |    86.36 |   92.85 |   94.76 | 86-87,348-354     
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   88.85 |    82.56 |   96.29 |   88.85 | ...-990,1034-1035 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    94.26 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    84.21 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.08 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   84.64 |    86.91 |   75.05 |   84.64 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   83.91 |    86.59 |   73.38 |   83.91 | ...8099,8103-8104 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.39 |    91.66 |   88.23 |   94.39 | ...45-446,449-450 
 ...nfirmation-bus |   98.27 |    97.14 |     100 |   98.27 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   91.79 |    87.98 |   93.08 |   91.79 |                   
  baseLlmClient.ts |   88.28 |    82.48 |   81.81 |   88.28 | ...47,660,666-668 
  client.ts        |   91.92 |    87.39 |   91.56 |   91.92 | ...3915,4011-4012 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...65-466,511-517 
  ...lScheduler.ts |   90.01 |    85.74 |      96 |   90.01 | ...5604,5632-5643 
  geminiChat.ts    |   92.42 |    89.27 |      96 |   92.42 | ...4429,4477-4478 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |       96 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  ...ream-error.ts |     100 |      100 |     100 |     100 |                   
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...lay-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...dispatcher.ts |     100 |      100 |     100 |     100 |                   
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   93.54 |    83.33 |      50 |   93.54 | 47-48             
  ...on-helpers.ts |   93.49 |    78.57 |     100 |   93.49 | ...10-211,228-229 
  ...issionFlow.ts |   98.97 |    96.96 |     100 |   98.97 | 107               
  ...try-policy.ts |     100 |      100 |     100 |     100 |                   
  ...ell-policy.ts |   95.19 |    89.47 |     100 |   95.19 | ...44-245,290-291 
  prompts.ts       |   93.57 |    91.42 |   83.33 |   93.57 | ...1187,1390-1391 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |   96.89 |    80.88 |   88.23 |   96.89 | ...10,117-118,123 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |     92.1 |     100 |     100 | 87,122-139        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...allIdUtils.ts |   98.41 |    93.47 |     100 |   98.41 | 36,45             
  ...okTriggers.ts |   99.45 |    92.43 |     100 |   99.45 | 182,193           
  ...terruption.ts |     100 |     92.3 |     100 |     100 | 86,104            
  turn.ts          |   98.52 |    91.66 |     100 |   98.52 | ...14,642-643,690 
 ...ntentGenerator |   96.24 |    87.19 |   95.38 |   96.24 |                   
  ...tGenerator.ts |   97.09 |    86.94 |   94.44 |   97.09 | ...1329,1358,1369 
  converter.ts     |   96.16 |    87.32 |     100 |   96.16 | ...,984,1139-1141 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   88.78 |    72.36 |   89.47 |   88.78 |                   
  ...tGenerator.ts |   87.18 |    71.83 |   88.88 |   87.18 | ...58-364,382-383 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   95.21 |    86.46 |    92.3 |   95.21 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   95.12 |     85.4 |   91.89 |   95.12 | ...1169-1170,1198 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.65 |    90.23 |   95.23 |   91.65 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   91.15 |    89.32 |   96.87 |   91.15 | ...1914,2083-2098 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   60.31 |       75 |      50 |   60.31 | ...71,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   96.63 |    90.94 |     100 |   96.63 | ...1100,1108,1203 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.73 |    89.76 |   98.27 |   96.73 |                   
  dashscope.ts     |   97.48 |    91.91 |      95 |   97.48 | ...85-386,528-529 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.16 |    96.96 |     100 |   99.16 | 198               
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
  zai.ts           |   92.13 |    82.14 |     100 |   92.13 | ...,39-40,135-137 
 src/extension     |    86.2 |    83.21 |   92.33 |    86.2 |                   
  ...ive-safety.ts |     100 |      100 |     100 |     100 |                   
  ...-converter.ts |   78.32 |    71.83 |     100 |   78.32 | ...1122,1168-1169 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |   80.39 |     87.5 |     100 |   80.39 | 50-59             
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   90.82 |    86.14 |   97.82 |   90.82 | ...1215-1221,1265 
  ...ionManager.ts |   81.06 |    78.78 |   81.52 |   81.06 | ...2705,2727-2728 
  ...references.ts |     100 |     90.9 |     100 |     100 | ...05,129,197,200 
  ...onSettings.ts |    92.3 |     94.4 |     100 |    92.3 | ...98-501,570-571 
  ...-converter.ts |    75.9 |    84.61 |   85.71 |    75.9 | ...98,202,214-248 
  github.ts        |   88.58 |    82.13 |     100 |   88.58 | ...62,952-953,963 
  http-client.ts   |   84.61 |       80 |     100 |   84.61 | 20-21             
  i18n.ts          |   78.26 |       96 |      50 |   78.26 | 104-110,116-123   
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   88.39 |    83.11 |     100 |   88.39 | ...08,494,507-508 
  ...ork-policy.ts |   89.72 |       90 |     100 |   89.72 | ...36,148-154,156 
  npm.ts           |   89.02 |    81.81 |     100 |   89.02 | ...86-688,695-700 
  override.ts      |   94.11 |    93.33 |     100 |   94.11 | 63-64,81-82       
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  ...ceRegistry.ts |   94.01 |    83.14 |     100 |   94.01 | ...38-344,365-366 
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.95 |    83.78 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |    80.61 |   89.47 |   85.77 | ...02-205,260-261 
 src/followup      |   77.48 |    79.84 |    90.9 |   77.48 |                   
  followupState.ts |   98.44 |    95.74 |     100 |   98.44 | 236-237           
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   96.29 |    88.88 |     100 |   96.29 | 78,108,122        
  speculation.ts   |   65.58 |    62.63 |   71.42 |   65.58 | ...21-622,629-630 
  ...onToolGate.ts |     100 |    96.55 |     100 |     100 | 97                
  ...nGenerator.ts |   72.03 |    81.15 |   83.33 |   72.03 | ...68-219,331-333 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   94.17 |    88.82 |   95.93 |   94.17 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  goal-evidence.ts |   87.59 |     85.1 |   95.65 |   87.59 | ...12-613,636-639 
  ...projection.ts |   89.41 |    72.22 |   66.66 |   89.41 | ...28,131,135-137 
  ...ersistence.ts |   87.73 |    84.84 |      80 |   87.73 | ...-94,97,101-106 
  goal-protocol.ts |    91.3 |       90 |     100 |    91.3 | 107-108           
  goal-reducer.ts  |   92.21 |    85.48 |     100 |   92.21 | ...67-368,381,436 
  goal-runtime.ts  |   99.01 |    93.44 |     100 |   99.01 | ...83-684,707-708 
  goal-tools.ts    |   98.32 |    93.18 |   95.23 |   98.32 | ...48-149,256-257 
  ...rn-context.ts |     100 |      100 |     100 |     100 |                   
  goal-verifier.ts |   92.46 |    92.85 |     100 |   92.46 | ...67-170,183-185 
  goal-wire.ts     |       0 |        0 |       0 |       0 | 1-27              
  goalHook.ts      |   96.91 |    92.42 |     100 |   96.91 | 115-120,221-222   
  goalJudge.ts     |   95.84 |    87.09 |     100 |   95.84 | ...55-356,448-449 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   88.05 |    86.37 |   88.54 |   88.05 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  context-usage.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.57 |    91.48 |     100 |   96.57 | ...20-321,402,404 
  ...entHandler.ts |   95.46 |       84 |   94.59 |   95.46 | ...1015-1016,1026 
  hookPlanner.ts   |    87.5 |    85.36 |   86.66 |    87.5 | ...21-225,232-243 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.65 |    72.34 |   66.66 |   62.65 | ...70-771,780-781 
  hookSystem.ts    |   87.55 |      100 |   70.21 |   87.55 | ...45-746,752-753 
  ...HookRunner.ts |   79.06 |    66.66 |      80 |   79.06 | ...33-434,452-456 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   94.19 |    84.37 |   81.81 |   94.19 | ...76-384,458-459 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   94.87 |    88.88 |     100 |   94.87 | ...84,325,327-329 
  ssrfGuard.ts     |   86.45 |    89.13 |     100 |   86.45 | ...85,289-295,301 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.24 |    96.12 |   88.88 |   94.24 | ...42-543,628-632 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
  ...it-context.ts |     100 |      100 |     100 |     100 |                   
 src/ide           |   76.98 |    85.03 |   79.03 |   76.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   69.16 |    84.65 |   68.29 |   69.16 | ...1068,1097-1105 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   58.96 |    70.57 |   66.14 |   58.96 |                   
  ...nfigLoader.ts |   80.55 |       72 |   95.45 |   80.55 | ...02-504,508-514 
  ...ionFactory.ts |   42.81 |    73.07 |      50 |   42.81 | ...76-427,433-450 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   75.73 |     80.1 |   79.66 |   75.73 | ...1346,1352-1382 
  ...eLspClient.ts |   32.78 |       80 |   16.66 |   32.78 | ...89-293,299-300 
  ...LspService.ts |      60 |    73.36 |   78.26 |      60 | ...1575,1635-1645 
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |    82.3 |    77.81 |   78.33 |    82.3 |                   
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   79.31 |    58.06 |     100 |   79.31 | ...26-933,940-942 
  ...en-storage.ts |   98.78 |    97.95 |     100 |   98.78 | 106-107           
  oauth-utils.ts   |   73.61 |    85.48 |    92.3 |   73.61 | ...46-366,392-421 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   82.12 |    88.19 |   89.28 |   82.12 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   87.08 |    87.03 |   95.23 |   87.08 | ...00-201,214-215 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   87.17 |    82.76 |   90.29 |   87.17 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.11 |    95.72 |   96.29 |   97.11 | ...85-287,361-362 
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    81.81 |     100 |     100 | 126,136           
  entries.ts       |   75.59 |    84.84 |   83.33 |   75.59 | ...56-157,172-180 
  extract.ts       |   91.48 |    75.75 |     100 |   91.48 | ...99,118-121,189 
  ...entPlanner.ts |   91.51 |    76.19 |     100 |   91.51 | ...04,113-116,290 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |   81.83 |       75 |   83.33 |   81.83 | ...51,474,478-507 
  indexer.ts       |   94.14 |       84 |     100 |   94.14 | ...32-233,334,337 
  ...kill-agent.ts |   97.94 |    89.36 |     100 |   97.94 | 82-83,179-180     
  manager.ts       |    78.4 |    82.29 |   77.77 |    78.4 | ...1482,1495-1497 
  ...ent-config.ts |   82.27 |    77.92 |   83.33 |   82.27 | ...66,285,292-298 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   94.73 |    95.94 |     100 |   94.73 | ...35-336,357-358 
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    87.03 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  refresh.ts       |   89.85 |    82.92 |     100 |   89.85 | ...54-155,162-163 
  ...ceSelector.ts |    93.1 |    81.81 |     100 |    93.1 | ...25,127-128,136 
  remember.ts      |   98.89 |    89.79 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    77.41 |     100 |   93.12 | ...08-109,154,157 
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   71.68 |    65.51 |   68.75 |   71.68 | ...90-394,397,403 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |    81.81 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |     79.1 |   81.81 |   81.21 | ...63-277,291-296 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.54 |    88.64 |   91.13 |   92.54 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   97.77 |    91.83 |     100 |   97.77 | 155,161,171       
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |       44 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.13 |     100 |     100 | 177,260           
  modelsConfig.ts  |   89.36 |    86.93 |   88.09 |   89.36 | ...1404,1433-1434 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/output        |     100 |      100 |     100 |     100 |                   
  ...-formatter.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/permissions   |   83.58 |    91.02 |   70.71 |   83.58 |                   
  autoMode.ts      |   97.65 |    93.13 |     100 |   97.65 | ...79-586,632,709 
  ...transcript.ts |      98 |    84.61 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  ...e-commands.ts |   86.77 |     73.8 |     100 |   86.77 | 131-141,210-214   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   86.54 |    89.63 |      80 |   86.54 | ...1096,1202-1206 
  rule-parser.ts   |   94.18 |    91.89 |     100 |   94.18 | ...1345,1379-1381 
  ...-semantics.ts |   70.36 |    91.02 |   46.66 |   70.36 | ...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 | 220               
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/providers     |   83.71 |     78.5 |   81.25 |   83.71 |                   
  all-providers.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   93.11 |     84.5 |     100 |   93.11 | ...56-257,330-331 
  ...der-config.ts |   75.85 |    73.84 |   78.26 |   75.85 | ...73-474,502-503 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.82 |    91.66 |   63.63 |   97.82 |                   
  ...oding-plan.ts |   87.34 |      100 |       0 |   87.34 | 82-84,87-89,91-94 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.05 |    81.25 |      75 |   97.05 | 118-119           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  grok.ts          |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  requesty.ts      |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |   85.41 |    78.76 |   95.89 |   85.41 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.79 |    73.75 |   90.62 |   82.79 | ...1205-1221,1251 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   89.39 |     84.5 |   96.78 |   89.39 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.68 |    85.71 |     100 |   97.68 | ...96,119,490-491 
  ...ionService.ts |   96.71 |    95.79 |     100 |   96.71 | ...83,699,832-840 
  ...ingService.ts |   90.91 |    84.17 |   95.45 |   90.91 | ...2058,2085-2086 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.05 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.17 |    90.45 |      98 |   94.17 | ...1333,1736-1737 
  cronTasksFile.ts |   96.31 |    91.81 |     100 |   96.31 | ...11,336-337,483 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   91.78 |    81.81 |   94.11 |   91.78 | ...37,463-470,517 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    73.7 |    68.49 |   95.83 |    73.7 | ...2196,2225-2226 
  ...on-service.ts |   87.38 |       72 |     100 |   87.38 | ...01-305,343-344 
  ...references.ts |   98.39 |    88.76 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.22 |    97.34 |     100 |   98.22 | ...75-676,723-724 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.52 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |    97.3 |    91.22 |     100 |    97.3 | ...53-454,611-612 
  ...ttachments.ts |   97.74 |     90.8 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   90.95 |    78.75 |     100 |   90.95 | ...78,963-964,992 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |   98.38 |    93.75 |   88.88 |   98.38 | 63-64             
  ...ipt-reader.ts |   94.51 |    89.14 |      98 |   94.51 | ...1102-1103,1167 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   79.58 |    74.13 |   95.58 |   79.58 | ...1913,1917-1929 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.94 |    83.69 |   97.14 |   88.94 | ...2450,2520-2540 
  sessionTitle.ts  |   94.19 |    73.21 |     100 |   94.19 | ...43-246,277-278 
  ...ionService.ts |   84.35 |    78.37 |   97.14 |   84.35 | ...2472,2478-2483 
  ...pInhibitor.ts |   97.42 |    92.77 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    88.23 |     100 |     100 | 118-119           
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...rd-service.ts |     100 |    88.37 |     100 |     100 | ...29,145-146,241 
  ...oryService.ts |   90.72 |    84.07 |     100 |   90.72 | ...06-509,561-562 
  ...reeCleanup.ts |   14.42 |      100 |   33.33 |   14.42 | 58-186            
  ...ionService.ts |   87.98 |    86.84 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |   99.41 |    96.55 |     100 |   99.41 |                   
  microcompact.ts  |   99.41 |    96.55 |     100 |   99.41 | 244-245,677       
 ...s/visionBridge |   98.81 |    92.12 |     100 |   98.81 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   88.52 |     87.7 |   90.47 |   88.52 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   84.07 |    83.67 |   83.33 |   84.07 | ...1233,1240-1244 
  skill-paths.ts   |   89.65 |    86.95 |     100 |   89.65 | ...11-112,117-118 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |       98 |     100 |   97.91 | 277-278           
 ...ataviz/scripts |   80.06 |    95.23 |   88.23 |   80.06 |                   
  ...te_palette.js |   80.06 |    95.23 |   88.23 |   80.06 | 261-296,306-328   
 ...s/bundled/loop |   97.48 |    95.77 |     100 |   97.48 |                   
  ...omous-loop.ts |     100 |      100 |     100 |     100 |                   
  ...-task-file.ts |   94.85 |     92.4 |     100 |   94.85 | ...56,367,375-376 
  ...k-resolver.ts |     100 |      100 |     100 |     100 |                   
 src/subagents     |   87.63 |    88.64 |   96.55 |   87.63 |                   
  ...ter-schema.ts |     100 |    98.07 |     100 |     100 | 99                
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   84.25 |    85.31 |   94.87 |   84.25 | ...1566,1643-1644 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   80.91 |    83.37 |   84.44 |   80.91 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.07 |    80.95 |     100 |   99.07 | 183,197           
  ...on-tracing.ts |   76.31 |    74.62 |   73.68 |   76.31 | ...80,387-389,405 
  ...attributes.ts |   95.15 |    87.27 |     100 |   95.15 | ...97-198,216-217 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |     100 |    90.47 |     100 |     100 | 49,76             
  ...-exporters.ts |   65.78 |    83.33 |   55.55 |   65.78 | ...04-105,108-109 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |       99 |     100 |     100 | 99                
  ...ai-request.ts |   87.52 |    92.79 |   83.78 |   87.52 | ...55-561,564-570 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.09 |    95.61 |      95 |   99.09 | 141,365-366       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |    56.1 |    71.15 |   64.15 |    56.1 | ...1376,1393-1413 
  metrics.ts       |   78.44 |    79.62 |   79.66 |   78.44 | ...1079,1082-1093 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   91.06 |    87.15 |   68.75 |   91.06 | ...32,478-479,495 
  sdk.ts           |   79.22 |    89.18 |   63.63 |   79.22 | ...57-161,199-221 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.83 |    90.05 |   96.77 |   90.83 | ...1666,1697-1700 
  ...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         |   82.35 |    87.23 |   86.04 |   82.35 | ...1361,1365-1372 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.11 |     80.7 |      70 |   74.11 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.11 |    80.53 |   69.49 |   74.11 | ...1118,1156-1157 
 src/test-utils    |      94 |    98.24 |   78.94 |      94 |                   
  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     |   92.57 |      100 |   75.75 |   92.57 | ...63,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   85.94 |    84.73 |   88.32 |   85.94 |                   
  ...erQuestion.ts |   89.71 |    80.76 |   91.66 |   89.71 | ...66-367,374-375 
  ...-registrar.ts |    77.7 |    66.66 |   66.66 |    77.7 | ...72-277,292-294 
  ...ub-session.ts |   89.67 |     91.3 |   81.81 |   89.67 | ...03-304,315-322 
  cron-create.ts   |   90.64 |    92.85 |   72.72 |   90.64 | ...,73-74,223-231 
  cron-delete.ts   |   97.56 |      100 |   83.33 |   97.56 | 31-32             
  cron-list.ts     |   98.23 |    95.34 |    87.5 |   98.23 | 57-58             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |    82.7 |    86.77 |   81.25 |    82.7 | ...43-744,863-913 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |      85 |     82.6 |    87.5 |      85 | ...28-133,161-175 
  exit-worktree.ts |   83.29 |    83.65 |   94.44 |   83.29 | ...14-515,537-538 
  exitPlanMode.ts  |      95 |    85.29 |     100 |      95 | ...21-325,344,378 
  ...permission.ts |     100 |      100 |     100 |     100 |                   
  glob.ts          |   96.33 |     88.5 |     100 |   96.33 | ...24-225,373,376 
  grep.ts          |   90.73 |    86.61 |   85.71 |   90.73 | ...76-677,727-728 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  image-gen.ts     |   91.66 |    77.41 |    90.9 |   91.66 | ...13-214,221-222 
  list-agents.ts   |   94.02 |    82.35 |   83.33 |   94.02 | 31-32,47-48       
  loop-wakeup.ts   |   99.27 |    92.85 |     100 |   99.27 | 45                
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.71 |     59.5 |   90.32 |   72.71 | ...1212,1214-1215 
  ...nt-manager.ts |   81.49 |     80.1 |   85.71 |   81.49 | ...3217,3219-3220 
  mcp-client.ts    |   79.87 |    85.58 |   89.47 |   79.87 | ...2259,2263-2266 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   77.56 |    84.11 |   77.14 |   77.56 | ...1291,1299-1300 
  ...ool-events.ts |       8 |      100 |       0 |       8 | 132-158           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 175-176           
  ...ce-content.ts |   96.55 |    91.17 |     100 |   96.55 | 80-82             
  mcp-retry.ts     |   97.67 |    95.65 |     100 |   97.67 | 131-132           
  mcp-status.ts    |     100 |      100 |     100 |     100 |                   
  mcp-tool.ts      |    97.2 |    93.47 |     100 |    97.2 | ...00-801,856-857 
  ...sport-pool.ts |   83.49 |    80.15 |   84.61 |   83.49 | ...1409,1416-1420 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |     100 |      100 |     100 |     100 |                   
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 101,108           
  monitor.ts       |   91.74 |    84.28 |   88.46 |   91.74 | ...93,606,804-809 
  notebook-edit.ts |   85.55 |    77.39 |   81.25 |   85.55 | ...86-902,948-949 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   82.57 |    90.24 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   95.49 |    88.52 |   86.66 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |   91.18 |    86.71 |    87.5 |   91.18 | ...26-427,441-453 
  ripGrep.ts       |    94.6 |    87.26 |   95.23 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   81.13 |    89.74 |    62.5 |   81.13 | ...80-286,363-371 
  ...n-mcp-view.ts |   93.57 |     92.3 |      90 |   93.57 | 122-130           
  shell.ts         |   78.78 |    84.06 |   91.91 |   78.78 | ...5019,5082-5083 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   91.06 |    93.33 |   89.47 |   91.06 | ...71,475,520-542 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |    94.4 |    93.33 |   81.81 |    94.4 | 45-49,63-64,95    
  task-list.ts     |   73.38 |    77.77 |   83.33 |   73.38 | ...02,105,109-116 
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  task-update.ts   |   82.89 |    83.92 |    92.3 |   82.89 | ...14-422,454-465 
  team-create.ts   |   97.22 |    85.71 |   83.33 |   97.22 | 48-49,129-130     
  team-delete.ts   |   86.74 |    83.33 |   83.33 |   86.74 | 37-38,42-48,72-73 
  ...n-approval.ts |   92.14 |    96.77 |   77.77 |   92.14 | 38-39,42-43,93-99 
  todoWrite.ts     |   94.36 |    84.61 |   92.85 |   94.36 | ...10-415,437-438 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.57 |    79.59 |    82.6 |   78.57 | ...89-990,998-999 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   92.74 |    91.52 |    91.3 |   92.74 | ...63-564,580-586 
  ...reapproved.ts |   99.27 |    94.11 |     100 |   99.27 | 170               
  web-fetch.ts     |   96.05 |    90.54 |   96.77 |   96.05 | ...85-786,800-801 
  web-search.ts    |   90.53 |    83.57 |      80 |   90.53 | ...1007,1065-1068 
  write-file.ts    |    86.7 |    84.92 |   88.88 |    86.7 | ...24-827,864-899 
  zoom-image.ts    |   95.76 |    93.75 |      90 |   95.76 | 54-59,203-204     
 src/tools/agent   |   86.08 |    85.96 |   87.73 |   86.08 |                   
  agent.ts         |   85.37 |    85.71 |   86.31 |   85.37 | ...4219,4241-4251 
  fork-subagent.ts |   99.32 |       90 |     100 |   99.32 | 81                
 ...tools/artifact |   95.78 |    92.51 |   88.63 |   95.78 |                   
  artifact-tool.ts |   91.46 |    88.46 |   71.42 |   91.46 | ...13-314,322-325 
  ...-publisher.ts |     100 |    85.71 |     100 |     100 | 32                
  ...-publisher.ts |   96.74 |    97.72 |    87.5 |   96.74 | 29-30,156-157     
  html.ts          |     100 |    96.77 |     100 |     100 | 122               
  ...-publisher.ts |     100 |       80 |     100 |     100 | 30                
  oss-publisher.ts |    98.1 |    91.48 |     100 |    98.1 | 43-45             
  publisher.ts     |     100 |      100 |     100 |     100 |                   
 ...s/computer-use |   90.21 |    82.17 |   78.08 |   90.21 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   80.11 |       90 |   77.77 |   80.11 | ...97,242-243,274 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    96.3 |    85.71 |     100 |    96.3 | 75-76,184,252-258 
 ...tools/workflow |   87.46 |    79.41 |   85.71 |   87.46 |                   
  workflow.ts      |   87.46 |    79.41 |   85.71 |   87.46 | ...51-652,664-667 
 src/utils         |   92.81 |    89.71 |   96.82 |   92.81 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.94 |    92.47 |     100 |   94.94 | ...43-544,651-655 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.45 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...ncyLimiter.ts |   94.64 |    95.23 |     100 |   94.64 | 64-66             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.81 |    93.95 |      95 |   95.81 | ...91-492,504-517 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   82.62 |    94.32 |    61.9 |   82.62 | ...62-378,382-388 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  fileUtils.ts     |   94.96 |    93.47 |   96.15 |   94.96 | ...1865,1890-1891 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.39 |    94.28 |     100 |   94.39 | ...29-132,343-348 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  git-branches.ts  |    91.6 |    84.21 |    92.3 |    91.6 | ...90,405-410,570 
  gitDiff.ts       |   95.19 |    81.36 |     100 |   95.19 | ...1073,1419-1420 
  gitDirect.ts     |   98.84 |    94.28 |     100 |   98.84 | 234,318           
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |   78.02 |    81.25 |   85.71 |   78.02 | ...22-123,147-198 
  github-prs.ts    |   95.74 |    82.27 |     100 |   95.74 | 216,314-322       
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  image-view.ts    |   95.12 |    93.33 |     100 |   95.12 | ...68-172,240-244 
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   95.27 |    93.25 |     100 |   95.27 | ...16-317,359-362 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   94.01 |       90 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.21 |     100 |   98.96 | 153               
  ...kerChecker.ts |    90.9 |    91.66 |     100 |    90.9 | 73-79             
  notebook.ts      |   94.57 |    89.91 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   91.66 |    89.74 |     100 |   91.66 | ...26-228,251-256 
  osc8.ts          |   54.26 |    64.86 |   83.33 |   54.26 | ...72-195,197-257 
  partUtils.ts     |     100 |    98.64 |     100 |     100 | 211               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.95 |    92.79 |     100 |   93.95 | ...78-479,481-483 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   71.15 |       86 |     100 |   71.15 | ...-90,96-101,147 
  ...noreParser.ts |   92.63 |    91.66 |     100 |   92.63 | ...77-178,197-198 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |   97.29 |    86.93 |     100 |   97.29 | ...59-660,735-736 
  readManyFiles.ts |   96.29 |    87.23 |     100 |   96.29 | 225,276,286-290   
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...67,558-559,577 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.02 |     100 |   97.63 | ...17,251-252,278 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   90.04 |    93.43 |   95.45 |   90.04 | ...55-565,598-599 
  ...sDiscovery.ts |   97.46 |    93.05 |     100 |   97.46 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   84.87 |    86.61 |   96.29 |   84.87 | ...71,696,725-734 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |    97.5 |    89.74 |     100 |    97.5 | 162-163           
  safe-mode.ts     |     100 |      100 |     100 |     100 |                   
  safeJsonParse.ts |     100 |      100 |     100 |     100 |                   
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...-child-env.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   98.03 |    97.75 |     100 |   98.03 | 100,102-103       
  ...aValidator.ts |   92.09 |    83.65 |   90.47 |   92.09 | ...60,882-883,896 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  sedEditParser.ts |   91.78 |    92.18 |     100 |   91.78 | ...66-569,645-646 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   95.98 |    83.96 |     100 |   95.98 | ...70,386,466,485 
  ...-pager-env.ts |     100 |      100 |     100 |     100 |                   
  ...fety-rules.ts |     100 |     89.7 |     100 |     100 | ...01,304,309-311 
  shell-utils.ts   |   86.07 |    88.36 |     100 |   86.07 | ...2269,2276-2280 
  ...lAstParser.ts |   98.16 |    91.91 |     100 |   98.16 | ...1244-1246,1256 
  ...ContextEnv.ts |     100 |       92 |     100 |     100 | 50-52             
  ...nlyChecker.ts |   96.33 |    96.57 |     100 |   96.33 | ...83-284,292-293 
  sideQuery.ts     |   86.82 |    86.66 |     100 |   86.82 | ...79-185,187-193 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...e-encoding.ts |   85.96 |    76.47 |     100 |   85.96 | 58-61,64-65,78-79 
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  textUtils.ts     |      65 |      100 |      75 |      65 | 56-75             
  thoughtUtils.ts  |     100 |    95.65 |     100 |     100 | 99                
  ...-converter.ts |   95.23 |    85.71 |     100 |   95.23 | 36-37             
  ...name-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-finalizer.ts |   97.66 |     90.9 |     100 |   97.66 | 165-166,168-172   
  tool-utils.ts    |    95.2 |    93.61 |     100 |    95.2 | ...58-159,162-163 
  ...ultCleanup.ts |   54.62 |    57.14 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.11 |    96.22 |     100 |   96.11 | ...22-327,329-334 
  ...pt-records.ts |   85.85 |    83.63 |     100 |   85.85 | ...90-394,424-439 
  truncation.ts    |   90.56 |    90.43 |     100 |   90.56 | ...35-443,480-486 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   95.81 |    89.39 |     100 |   95.81 | ...74-275,299-301 
  xml.ts           |    97.8 |    87.69 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    77.27 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.68 |    80.38 |   94.69 |   83.68 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.47 |    76.22 |      95 |   82.47 | ...1525,1559-1560 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  ignore.ts        |     100 |    97.36 |     100 |     100 | 187               
  result-cache.ts  |     100 |    93.75 |     100 |     100 | 49                
 ...uest-tokenizer |   69.76 |    75.47 |   85.29 |   69.76 |                   
  ...eTokenizer.ts |   65.72 |    74.02 |    92.3 |   65.72 | ...65-466,479-533 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |   76.92 |      100 |   33.33 |   76.92 | 46-49,56-57       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

CI failure diagnosed and fixed in 13acfdf1d2. The failed Ubuntu job had three stale exact-equality assertions: one CLI --mcp-config test and two Core safe-mode MCP tests expected the raw command config, while this PR intentionally makes getMcpServers() return the session-effective config with cwd. Updated those expectations to assert cwd: config.getTargetDir(). Core regression files now pass: 495/495; ESLint, Prettier, Core typecheck, and git diff --check pass. The CLI test cannot be run locally in this checkout because the existing @qwen-code/channel-github / channel-gitlab workspace packages are absent, but the prior CI run executed it and its only failure was the corrected cwd assertion. A new CI run is in progress.

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

@qwen-code-dev-bot

qwen-code-dev-bot commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

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

中文说明

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — no action needed

No code changes were made this round. The feedback newer than the last evaluation contains no actionable items:

  • Reviews: none.
  • Inline comments: none.
  • Failed checks: none.
  • Still-red checks: none.

The two issue-level comments are informational only:

  1. E2E Test Report from @wenshao — result PASS. Concurrent worktree sessions were verified to be fully isolated (distinct cwds, branches, commits, and MCP process cwds), with base-workspace invariants preserved and 1,523 automated checks passing.
  2. CI failure note from @wenshao — the previously failing Ubuntu job was already diagnosed and fixed in commit 13acfdf1d (current HEAD), which updated three stale exact-equality assertions to expect the session-effective config with cwd. Core regression files pass 495/495; ESLint, Prettier, Core typecheck, and git diff --check pass. The noted CLI typecheck errors are pre-existing missing-channel-module / Ink type issues unrelated to this PR.

Nothing requires a response or a code change. The PR stands as-is.

中文说明

Autofix 审查轮次 —— 无需处理

本轮未做任何代码改动。自上次评估以来的新反馈中没有任何可处理的项目:

  • Reviews(审查): 无。
  • Inline comments(行内评论): 无。
  • Failed checks(失败的检查): 无。
  • Still-red checks(持续失败的检查): 无。

两条 issue 级别的评论仅为信息性内容:

  1. @wenshaoE2E 测试报告 —— 结果为 PASS(通过)。已验证并发的 worktree 会话完全隔离(各自独立的 cwd、分支、提交以及 MCP 进程 cwd),基础工作区的不变量得到保持,且 1,523 项自动化检查全部通过。
  2. @wenshaoCI 失败说明 —— 之前失败的 Ubuntu 任务已在提交 13acfdf1d(当前 HEAD)中诊断并修复,该提交将三处过时的精确相等断言更新为期望带有 cwd 的会话生效配置。Core 回归文件通过 495/495;ESLint、Prettier、Core typecheck 以及 git diff --check 均通过。所提到的 CLI typecheck 错误是既有的、与本 PR 无关的缺失 channel 模块 / Ink 类型问题。

无需任何回复或代码改动。PR 保持现状。

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


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

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline.

中文说明

已审查。 建议见行内评论。

— qwen3.7-max via Qwen Code /review

Comment thread packages/acp-bridge/src/bridge.ts

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

中文说明

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

— qwen3.8-max-preview via Qwen Code /review

Comment thread packages/acp-bridge/src/bridge.ts Outdated
Comment thread packages/acp-bridge/src/bridge.ts Outdated
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Review feedback addressed

[rc:3679387279] packages/acp-bridge/src/bridge.ts[Suggestion] Missing test for shell execution after a failed cwd change

Decision: Implemented (test added; TODO comment declined).

Changes: Added a new test executes direct shell in previous cwd when a pending cd fails in packages/acp-bridge/src/bridge.test.ts. The test:

  1. Sets up a session with workspace WS_A.
  2. Starts a changeSessionCwd to WS_B backed by a deferred promise.
  3. Issues a shell command while the cd is still pending.
  4. Rejects the deferred (simulating a cd failure).
  5. Asserts the changeSessionCwd call rejects.
  6. Asserts the shell command still executes in the previous effectiveCwd (WS_A), confirming the () => undefined error handler on cwdChangeQueue correctly swallows the failure and the shell path falls back to the last-known-good directory.

The suggested // TODO comment was not added — the test itself closes the coverage gap, and AGENTS.md's comment policy defaults to none.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • vitest packages/acp-bridge src/bridge.test.ts -t "executeShellCommand permission policy" — 7 passed (including the new test)
中文说明

已处理的审查反馈

[rc:3679387279] packages/acp-bridge/src/bridge.ts[建议] cwd 变更失败后的 shell 执行缺少测试

决定: 已实现(添加了测试;拒绝了 TODO 注释)。

变更:packages/acp-bridge/src/bridge.test.ts 中新增测试 executes direct shell in previous cwd when a pending cd fails。该测试:

  1. 创建一个工作目录为 WS_A 的会话。
  2. 通过一个 deferred promise 发起从 WS_AWS_BchangeSessionCwd 操作。
  3. 在 cd 尚未完成时发起一个 shell 命令。
  4. 拒绝该 deferred(模拟 cd 失败)。
  5. 断言 changeSessionCwd 调用被拒绝。
  6. 断言 shell 命令仍在之前的 effectiveCwdWS_A)中执行,确认 cwdChangeQueue 上的 () => undefined 错误处理器正确吞掉了失败,shell 路径回退到最后一个已知正确的目录。

未添加建议中的 // TODO 注释——测试本身已弥补了覆盖率缺口,且 AGENTS.md 的注释策略默认为不添加注释。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • vitest packages/acp-bridge src/bridge.test.ts -t "executeShellCommand permission policy" — 7 个通过(包含新测试)

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

中文说明

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

— qwen3.8-max-preview via Qwen Code /review

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Review feedback addressed

Both inline findings from the automated reviewer are addressed in code.

[rc:3679531702] Shell command could park forever on a hung cwd change — FIXED

executeShellCommand awaited entry.cwdChangeQueue without racing it against
the caller's abort signal. If a changeSessionCwd extMethod never settles
(agent crash / deadlock / partitioned ACP channel), the queue never resolves,
every subsequent shell command for the session parks on the await forever,
and the signal?.aborted check below it is unreachable. Before this PR shell
commands read the cwd synchronously and were immune to a hanging cd; this PR
newly coupled them to the cd extMethod's liveness.

Fix: race the cwd queue against the abort signal, then return the aborted
sentinel when the signal is aborted. When no signal is supplied the racing
promise never settles, so behavior is unchanged for that path.

[rc:3679531697] No test covered the abort-after-cwd-wait path — FIXED

Added returns an aborted direct shell without waiting for a hung cwd change.
It starts changeSessionCwd on a deferred promise, calls executeShellCommand
with an AbortSignal, aborts while the cd is still pending, and asserts the
result is { exitCode: null, output: '', aborted: true } with the shell spy
never called — crucially before the cd settles, which also proves the race
fix above. Verified load-bearing: with the race reverted the test times out
(parks on the hung queue), exactly the reported bug.

Conflict notes

--conflict false; no merge performed.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check (touched files) — passed
  • vitest run src/bridge.test.ts (packages/acp-bridge, touched) — 464 passed
  • vitest run -t "direct shell" — 6 passed (includes the new test)
  • Load-bearing check: reverted the race fix, vitest run -t "hung cwd change" timed out (bug reproduced); restored the fix, test passes
  • Integration tests after npm run bundle — not run: the touched behavior (executeShellCommand cwd-queue racing) is fully exercised by the unit harness above and is not only reachable through the bundled CLI/integration harness
  • Settings schema — not regenerated: no settings source changed
中文说明

已处理的审查反馈

自动化审查者的两条行内发现均已在代码中处理。

[rc:3679531702] shell 命令可能永远卡在一个挂起的 cwd 切换上 — 已修复

executeShellCommandawait entry.cwdChangeQueue 时没有与调用方的中止
signal 做竞争。如果某个 changeSessionCwd extMethod 永远不 settle
(agent 崩溃 / 死锁 / ACP 通道断开),该队列永远不会 resolve,该 session
后续所有 shell 命令都会永远卡在这个 await 上,下方的 signal?.aborted
检查变得不可达。本次改动之前,shell 命令同步读取 cwd,对一个挂起的 cd 免疫;
本次改动让它们新近耦合到 cd extMethod 的存活状态。

修复:让 cwd 队列与中止 signal 做竞争,当 signal 已中止时返回 aborted 哨兵值。
当未提供 signal 时,参与竞争的 promise 永远不会 settle,因此该路径的行为不变。

[rc:3679531697] 没有测试覆盖「等待 cwd 切换后被中止」这条路径 — 已修复

新增测试 returns an aborted direct shell without waiting for a hung cwd change
它用一个 deferred promise 启动 changeSessionCwd,带 AbortSignal 调用
executeShellCommand,在 cd 仍挂起时中止,并断言结果为
{ exitCode: null, output: '', aborted: true } 且 shell spy 从未被调用——
关键在于这一切发生在 cd settle 之前,从而同时证明了上面的竞争修复。
已验证该测试是承重的:将竞争修复回退后,该测试超时(卡在挂起的队列上),
正是所报告的 bug;恢复修复后测试通过。

冲突说明

--conflict false;未执行合并。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx prettier --check(改动文件)— 通过
  • vitest run src/bridge.test.ts(packages/acp-bridge,已改动)— 464 通过
  • vitest run -t "direct shell" — 6 通过(包含新增测试)
  • 承重性检查:回退竞争修复后,vitest run -t "hung cwd change" 超时(复现 bug);恢复修复后测试通过
  • npm run bundle 之后的集成测试 — 未运行:改动的行为(executeShellCommand
    的 cwd 队列竞争)已由上面的单元测试套件完整覆盖,并非只能通过打包后的 CLI /
    集成套件触达
  • settings schema — 未重新生成:没有改动任何 settings 源

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

— qwen3.8-max-preview via Qwen Code /review

Comment thread packages/core/src/tools/mcp-client-manager.ts Outdated
Comment thread packages/core/src/config/config.ts
Extract McpClientManager.getEffectiveMcpServers() as the single source of truth for the populateMcpServerCommand recipe, replacing six duplicated call sites that this PR otherwise had to edit in lockstep. Also cover relocateWorkingDirectory's combined memory + MCP refresh failure path so both errors stay surfaced.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — PR #8068

Both inline suggestions from the automated reviewer were addressed in code. No
conflict resolution was needed (--conflict false).

Feedback points

  • [rc:3680593346] Suggestion — duplicated populateMcpServerCommand recipe
    (mcp-client-manager.ts): Implemented.
    Extracted a private
    McpClientManager.getEffectiveMcpServers() helper that returns
    populateMcpServerCommand(this.cliConfig.getMcpServers() || {}, this.cliConfig.getMcpServerCommand(), this.cliConfig.getTargetDir()) and
    replaced all six duplicated call sites (discoverAllMcpTools,
    discoverMcpToolsForServer, discoverMcpToolsForServerInternal,
    discoverAllMcpToolsViaPool, discoverAllMcpToolsIncremental,
    readResource) with it. This is the single source of truth for the
    server-resolution recipe, so a future change (a new argument or a different
    fallback) can no longer diverge silently across code paths. The refactor is
    behavior-preserving — every site already used this.cliConfig identically —
    and nets a ~24-line reduction.

  • [rc:3680593350] Suggestion — untested combined-error return path
    (config.ts relocateWorkingDirectory): Implemented.
    Added
    relocateWorkingDirectory should report both memory and MCP refresh failures after moving to packages/core/src/config/config.test.ts. It rejects both
    loadServerHierarchicalMemory and discoverAllMcpToolsIncremental and
    asserts that the result carries both memoryRefreshError and
    mcpRefreshError, locking in the unconditional-both-refreshes behavior this
    PR introduced against a future early-return regression. It mirrors the two
    existing isolated-failure tests.

Conflict notes

None — the branch was not in conflict with origin/main.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint (full: eslint . --ext .ts,.tsx && eslint integration-tests) — passed
  • npx vitest run src/config/config.test.ts src/tools/mcp-client-manager.test.ts (packages/core, touched) — 589 passed (472 config + 117 manager)
  • npx vitest run src/config/config.test.ts -t "both memory and MCP refresh failures" (new test in isolation) — 1 passed

Integration tests after npm run bundle were not run this round: the changes
are a behavior-preserving refactor (covered by the 117 existing manager tests
and 472 config tests) plus a unit test addition, so no behavior exercised only
through the bundled CLI/integration harness was altered.

中文说明

Autofix 审查轮次 — PR #8068

自动审查器提出的两条内联建议均已在代码中处理。无需解决冲突(--conflict false)。

反馈要点

  • [rc:3680593346] 建议 — populateMcpServerCommand 配方重复(mcp-client-manager.ts):已实现。 提取了私有辅助方法 McpClientManager.getEffectiveMcpServers(),返回 populateMcpServerCommand(this.cliConfig.getMcpServers() || {}, this.cliConfig.getMcpServerCommand(), this.cliConfig.getTargetDir()),并替换了全部六个重复调用点(discoverAllMcpToolsdiscoverMcpToolsForServerdiscoverMcpToolsForServerInternaldiscoverAllMcpToolsViaPooldiscoverAllMcpToolsIncrementalreadResource)。这是服务器解析配方的唯一真实来源,因此未来的改动(新增参数或不同的回退逻辑)不会再在各代码路径之间悄无声息地产生分歧。该重构保持行为不变——每个调用点原本就以完全相同的方式使用 this.cliConfig——并净减少约 24 行代码。

  • [rc:3680593350] 建议 — 未测试的组合错误返回路径(config.ts 的 relocateWorkingDirectory):已实现。packages/core/src/config/config.test.ts 中新增测试 relocateWorkingDirectory should report both memory and MCP refresh failures after moving。它同时让 loadServerHierarchicalMemorydiscoverAllMcpToolsIncremental 拒绝(reject),并断言返回结果同时包含 memoryRefreshErrormcpRefreshError,从而将本 PR 引入的“无条件执行两项刷新”行为固定下来,防止未来重新引入提前返回(early-return)的回归。该测试与现有两个孤立失败测试保持一致。

冲突说明

无——该分支与 origin/main 没有冲突。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint(完整:eslint . --ext .ts,.tsx && eslint integration-tests)— 通过
  • npx vitest run src/config/config.test.ts src/tools/mcp-client-manager.test.ts(packages/core,受影响)— 589 通过(config 472 + manager 117)
  • npx vitest run src/config/config.test.ts -t "both memory and MCP refresh failures"(新测试单独运行)— 1 通过

本轮未在 npm run bundle 之后运行集成测试:本次改动是一次保持行为不变的重构(已由现有 117 个 manager 测试和 472 个 config 测试覆盖)外加一个单元测试的新增,因此没有改动任何仅通过打包后的 CLI / 集成测试框架才能验证的行为。

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

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


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

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Review: fix(web-shell): isolate worktree session execution (#8068)

Static review of 1643a6c9a..82b2e4b49 (15 files, +692/−59). Tests were not executed — this checkout has no node_modules — so everything below is from reading the code.

What it does

Three coupled changes:

  1. BridgeSessionEntry gains effectiveCwd + cwdChangeQueue. Direct session shell commands now wait for a pending changeSessionCwd and run in the session's effective cwd instead of workspaceCwd, with the wait raced against the caller's abort signal.
  2. ConfiggetMcpServers() stamps cwd: this.targetDir onto command-based servers that have no explicit cwd; relocateWorkingDirectory() now reconciles MCP connections against the new dir and reports mcpRefreshError.
  3. ACP — worktree sessions carry qwen.session.deferMcpDiscovery so newSession passes skipMcpDiscovery: true, deferring the first MCP spawn until the trusted relocation lands.

The design is sound and the load-bearing detail is right: cwd is already part of the pool fingerprint (mcp-pool-key.ts:132), so a relocation genuinely releases and re-acquires stdio entries rather than silently keeping the old process. Deliberately leaving getSettingsMcpServers() unstamped (asserted in config.test.ts) avoids leaking a machine-specific path into the settings layer. Test coverage is unusually thorough for the size of the change.

Findings

1. Per-agent MCP servers bypass the new cwd binding — subagent-manager.ts:1011-1021

When a subagent spec declares frontmatter mcpServers, the manager replaces the method wholesale:

const merged = { ...sessionServers, ...(config.mcpServers as Record<string, MCPServerConfig>) };
subagentContext.getMcpServers = () => merged;

The frontmatter entries never pass through Config.getMcpServers(), so an implicit-cwd stdio agent server still inherits the daemon process cwd — the exact bug this PR fixes. The map is also frozen at build time, so a later relocation won't rebind even the session servers inside that subagent context. Worth stamping in the merge (or extracting the stamping into a small exported helper both sides call).

2. Stamping makes a stale targetDir fatal for every stdio server — config.ts:5071-5082 + mcp-client.ts:2211

createTransport hard-throws when cwd is set but missing:

if (mcpServerConfig.cwd && !existsSync(mcpServerConfig.cwd)) {
  throw new Error(`MCP server '${name}': configured cwd does not exist: ${...}`);
}

Before this PR, implicit servers had cwd === undefined and simply inherited the process cwd, so a vanished directory was invisible to them. Now every stdio server carries targetDir. If the worktree is removed while a session is still alive (external git worktree remove, or a rollback path), the next reconcile fails all local servers with a message blaming a cwd the user never configured. Consider falling back to undefined when targetDir no longer exists, or wording the error so implicit binding is distinguishable.

3. /cd now blocks on a full MCP restart — config.ts:4582-4588

await this.waitForMcpReady();
await this.refreshMcpServers();

Because cwd is in the fingerprint, this releases and re-acquires every stdio/websocket entry, and waitForMcpReady() additionally parks on the initial background discovery if the user cds early in a session. Worst case is the 30s stdio discovery timeout, and on the daemon path the new cwdChangeQueue propagates that stall to direct shell commands as well. Both are correctness-motivated, but the latency is a real behavior change for the ordinary non-worktree /cd. Worth either bounding it with withTimeout or making the reconcile fire-and-forget (the mcp-client-update stream already carries per-server outcomes) — and either way, a comment recording the trade-off.

4. A failed deferred discovery is silent for worktree sessions — session.ts:1717

With skipMcpDiscovery: true, the relocation's refreshMcpServers() is the session's only discovery attempt. A failure becomes mcpRefreshError → a warnings[] entry on the sessionCd result — but the worktree create path discards the changeSessionCwd return value entirely, so the client sees a healthy 200 for a session with zero MCP tools. Only a daemon stderr line records it. Surfacing those warnings in the POST /session response (or retrying on first prompt) would close the gap. The transactional rollback on cdErr is good and unaffected.

5. Stdio predicate diverges from mcpTransportOfconfig.ts:5074-5078

The new check is command !== undefined && !httpUrl && !url && type !== 'sdk', but mcpTransportOf (mcp-client-manager.ts:259) tests tcp before command. A config with both tcp and command is websocket there and gets a cwd stamp here — perturbing its pool fingerprint for no reason. Adding server.tcp === undefined matches the canonical classifier. (A shared helper is blocked by the config.tsmcp-client-manager.ts import cycle, which is presumably why it was hand-rolled — a comment saying so would help.)

6. One discovery path still bypasses getEffectiveMcpServers()mcp-client-manager.ts:688

getMcpClientAccounting() calls cliConfig.getMcpServers() directly, so the mcpServerCommand-derived mcp server is classified unknown in the GET /workspace/mcp accounting snapshot. Pre-existing, but this PR is the natural place to fix it given the "single source of truth so the recipe cannot diverge" framing on the new helper.

7. effectiveCwd is not restored on session restore — bridge.ts:3893

It is initialized to workspaceCwd and only ever advanced by changeSessionCwd (bridge.ts:6410). Restored entries (bridge.ts:4541, 5322) reset it to the workspace key. The load/resume path re-cds worktree sessions (session.ts:2052) but skips that when hasActivePrompt, and a plain session that had cd'd loses its shell cwd silently after a daemon restart. Same shape as the old workspaceCwd behavior, so not a regression — flagging because the field now drives where shell commands actually run.

Nits

  • bridge.ts:7794-7803 — when cwdChangeQueue wins the race, the abort listener stays attached ({ once: true } doesn't help; the event never fires). Harmless per-request today; an inner AbortController or a finally removal keeps it clean if a signal is ever reused.
  • bridge.ts:7798 — the race unblocks only on caller abort, and both production call sites (dispatch.ts:2790, session.ts:4275) bind that signal to client disconnect. A patient client on a hung sessionCd still parks forever. changeSessionCwd itself already uses withTimeout(..., max(initTimeoutMs, 30_000)) — reusing it here would make the guard complete rather than best-effort.
  • acpAgent.ts:4363-4372undefined, undefined positional filler to reach the 7th parameter. An options object at this call site would age better.
  • acpAgent.test.tsexpect(localConfig._args[3]).toBeUndefined() is redundant after the preceding toEqual(['node', ['server.js'], {}]).

Security

No new exposure. The sessionCd containment / allowedRoots checks and the symlink-realpath validation are untouched, the stamped cwd is always server-derived (this.targetDir, never client input), and the settings layer stays unstamped so nothing machine-specific is persisted.

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Independent local verification — Linux, real daemon, before/after builds

I rebuilt this PR from source and drove the real bundled qwen serve daemon on Linux (the OS the PR marks ⚠️), running every scenario twice: once on the PR base 1643a6c9ae and once on the PR head 1b4aefc819.

Verdict: the fix is real and reproduces end-to-end — the before arm loses data exactly as described. But the getMcpServers() cwd injection has side effects outside the worktree path: one of them silently disables approved MCP servers. I also validated a candidate fix that keeps every isolation guarantee and removes that regression.

Core claim (worktree isolation) confirmed on Linux, before/after
Targeted unit tests ✅ 1,865 passed
Blocking finding 🔴 1 — MCP approval binding broken by the effective-config cwd
Non-blocking findings 🟡 2 — worktree session creation now waits on MCP connect; per-command abort-listener growth

1. Setup

worktree  /root/wt/wt8068-pr  @ 1b4aefc819   (base arm: git checkout 1643a6c9ae -- <the 15 PR files>)
build     npm run build (core, acp-bridge, cli) && npm run bundle  ->  dist/cli.js
daemon    node dist/cli.js serve --workspace <tmp>/base --hostname 127.0.0.1 --port <p> --enable-session-shell
          isolated HOME, QWEN_RUNTIME_DIR, QWEN_SERVER_TOKEN; no model traffic is needed for any scenario
workspace tmp git repo; .qwen/settings.json declares one stdio MCP server WITHOUT `cwd`
          (a Node script that appends {pid, cwd} to a log on every process start)
driver    POST /session {cwd, worktree:{slug}}  x2, then POST /session/:id/shell on both, concurrently

2. Confirmed: the fix works

worktree isolation before/after

Check (2 concurrent worktree sessions, one workspace) BEFORE 1643a6c9ae AFTER 1b4aefc819
Session A direct-shell cwd <repo> 🔴 <repo>/.qwen/worktrees/e2e-a
Session B direct-shell cwd <repo> 🔴 <repo>/.qwen/worktrees/e2e-b
<repo>/same-name.txt (base checkout) 'B-shell'A's write destroyed 🔴 absent ✅
worktrees/e2e-a/same-name.txt absent 🔴 'A-shell'
worktrees/e2e-b/same-name.txt absent 🔴 'B-shell'
git commit from each session both hit main; base HEAD moved 🔴 worktree-e2e-a / worktree-e2e-b
Base HEAD 2d5720240ac730 🔴 unchanged ✅
Implicit-cwd stdio MCP processes 1 shared, cwd = <repo>, refs=2 🔴 2, cwd = each worktree ✅

The MCP evidence is the process's own startup record, so it proves the first spawn already happened in the worktree — the deferral works, there is no start-in-base-then-relocate window. Both sessions closed 204; base checkout left with only README.md, .gitignore, .qwen/.

3. 🔴 Blocking — the effective-config cwd breaks MCP approval binding

mcpApprovals.json binds a decision to hashMcpServerConfig(config), and cwd is a behavioral field (not in NON_BEHAVIORAL_FIELDS, packages/core/src/mcp/configHash.ts:16). After this PR the two sides of that contract hash different objects:

  • raw settings entry — qwen mcp approve/list and, critically, the discovery gate getPendingGatedMcpServers(mcpServers, cwd) in packages/cli/src/config/config.ts:2036, which decides whether a gated server is allowed to spawn at all;
  • effective config — the daemon/ACP surfaces, which read config.getMcpServers() (packages/cli/src/acp-integration/acpAgent.ts:5220 status, :8290 approve) and therefore now see cwd: this.targetDir injected at packages/core/src/config/config.ts:5071-5081.

Measured against a real daemon, with a workspace-settings stdio server the user had already approved:

mcp approval regression

Step BEFORE 1643a6c9ae AFTER 1b4aefc819
1. qwen mcp approve cwdprobe stores hash 37637fa790db… stores hash 37637fa790db…
2. daemon boots a session — server really spawns and connects GET /workspace/mcp → approved ✅ approvalState: "pending", status: "warning" 🔴
3. operator clicks Approve in the Web Shell hash unchanged hash rewritten to 3803e8b53e46… (cwd-bound) 🔴
4. qwen mcp list Disconnected (i.e. approved) Pending approval 🔴
5. restart daemon, boot a new session new MCP process spawned ✅ no process spawned — server silently gated off 🔴

Two distinct user-visible failures:

  1. False "Needs approval". McpManagerPage.tsx:171 renders mcp.status.needsApproval for any approvalState === 'pending', so every approved project-/workspace-scoped stdio server shows as needing approval in the Web Shell even while it is connected and serving tools. Everyone who already has such a server approved sees this on upgrade — the stored hash was computed before cwd existed.
  2. Approving makes it worse. Clicking Approve rebinds the stored decision to the cwd-decorated config. The gate still hashes the raw entry, so on the next daemon start isMcpServerPendingApproval() is true and discoverAllMcpToolsIncremental skips the server before any spawn. Step 5 above is that: 0 new processes, entrySummary: null. A worktree session makes it worse still — the injected cwd differs per worktree, so no single stored hash can ever match all of them.

Only scope: 'project' (.mcp.json) and scope: 'workspace' (.qwen/settings.json) servers are gated (isGatedMcpScope), so user-scope and --mcp-config servers are unaffected.

Candidate fix (validated locally)

Keep getMcpServers() an identity-stable view of configuration and bind the implicit cwd one layer down, at the transport-config seam that every spawn path already goes through — populateMcpServerCommand(servers, cmd, cwd), which this PR already threads getTargetDir() into at all six mcp-client-manager.ts call sites plus discoverMcpTools:

--- a/packages/core/src/config/config.ts
   getMcpServers(): Record<string, MCPServerConfig> | undefined {
     ...
-    return Object.fromEntries(
-      Object.entries(mcpServers).map(([name, server]) => [ ...cwd injection... ]),
-    );
+    return mcpServers;
   }

--- a/packages/core/src/tools/mcp-client.ts
   export function populateMcpServerCommand(mcpServers, mcpServerCommand, cwd?) {
     if (mcpServerCommand) { ... }
-    return mcpServers;
+    if (cwd === undefined) return mcpServers;
+    return Object.fromEntries(
+      Object.entries(mcpServers).map(([name, server]) => [
+        name,
+        server.command !== undefined && server.httpUrl === undefined &&
+        server.url === undefined && server.type !== 'sdk' && server.cwd === undefined
+          ? { ...server, cwd } : server,
+      ]),
+    );
   }

candidate fix

Rebuilt and re-run through the same two harnesses: worktree isolation is unchanged (2 MCP processes, one per worktree; per-session direct-shell cwd; base checkout untouched; base HEAD unchanged) and the approval regression is gone (every row of the table above matches the BEFORE column). It also stops populateMcpServerCommand from mutating the caller's live map, which is what lets the synthesized --mcp-server-command entry leak into config state today.

Cost: 5 existing assertions encode "getMcpServers() returns cwd" and would move down a layer — core/src/config/config.test.ts (2: binds command MCP servers without an explicit cwd…, relocateWorkingDirectory should reconcile…), core/src/config/config.safe-mode.test.ts (2), cli/src/config/config.test.ts (1: should parse inline JSON with mcpServers wrapper). Everything else stays green (717/721 core, 314/315 cli with the patch applied, and the 4+1 failures are exactly those assertions).

4. 🟡 Worktree session creation is now serialized behind MCP connect

relocateWorkingDirectory() gained await this.waitForMcpReady(); await this.refreshMcpServers(); (config.ts:4582-4588), and POST /session {worktree} awaits bridge.changeSessionCwd(...) before it answers (routes/session.ts:1717). Session creation therefore now blocks on the MCP handshake. Measured with a mock stdio server that stalls its initialize reply by 25 s:

POST /session BEFORE 1643a6c9ae AFTER 1b4aefc819
plain session (no worktree) 658 ms 663 ms
worktree session 801 ms 25,865 ms

worktree create latency

The default MCP timeout is 10 minutes (MCP_DEFAULT_TIMEOUT_MSEC) while the cd deadline is max(initTimeoutMs, 30_000) (bridge.ts:6441), and the create route treats a cd failure as fatal: it kills the session, removes the worktree and its branch, and returns 500 worktree_relocate_failed. So one slow or wedged MCP server can now stop worktree sessions from being created at all. Making the relocation-time MCP reconcile fire-and-forget (it already reports through mcpRefreshError, which is only a warning) would decouple them.

5. 🟡 Nit — one retained abort listener per direct shell command

The new race in executeShellCommand (bridge.ts:7794-7803) registers signal.addEventListener('abort', …, {once: true}) and never removes it when the cwd queue wins. The REST route builds a fresh AbortController per request, but the ACP path passes the long-lived per-session binding.abort.signal (serve/acp-http/dispatch.ts:2793), so listeners accumulate for the session's lifetime — measured 300 retained listeners after 300 commands. A finally { signal?.removeEventListener('abort', onAbort); } closes it.

6. Observed, but not caused by this PR

  • The first of two concurrent POST /session/:id/shell calls on a freshly created session sometimes returns exitCode: 0 with an empty output (session B in every arm). Reproduces identically on the base build; sequential calls always return the correct output.
  • Daemon restart. createSessionEntry seeds effectiveCwd: workspaceCwd and only changeSessionCwd ever updates it; the restore path (bridge.ts:4375 restoreSession) never re-issues a cd. So a restored worktree session's direct shell falls back to the base checkout — matching the PR's own "Not validated / out of scope" note. Code-read only, not exercised here.

7. Targeted unit tests at 1b4aefc819 — 1,865 passed

packages/acp-bridge  src/bridge.test.ts                    464 passed
packages/core        src/config/config.test.ts             471 passed
                     src/config/config.safe-mode.test.ts    24 passed
                     src/tools/mcp-client.test.ts          109 passed
                     src/tools/mcp-client-manager.test.ts  117 passed
packages/cli         src/acp-integration/acpAgent.test.ts  343 passed
                     src/config/config.test.ts             315 passed
                     src/ui/commands/cdCommand.test.ts      22 passed

Recommendation

The isolation fix itself is solid and I'd merge it. I'd hold on §3 first: it silently stops an approved MCP server from starting, it is triggered by the most natural user action (clicking Approve), and it reaches beyond worktrees to every daemon workspace with a gated stdio server. §4 and §5 are follow-ups.

中文版

独立本地验证 —— Linux、真实 daemon、before/after 双构建

我从源码重新构建了本 PR,并在 Linux(PR 中标记为 ⚠️ 的系统)上驱动真实的 bundled qwen serve daemon,每个场景都跑两遍:一遍在 PR base 1643a6c9ae,一遍在 PR head 1b4aefc819

结论: 修复是真实有效的,并且端到端复现了——before 分支确实会按 PR 描述的方式丢数据。但 getMcpServers() 注入 cwd 的做法在 worktree 路径之外产生了副作用,其中一个会静默地让已批准的 MCP server 不再启动。我还验证了一个候选修复:它保留全部隔离保证,同时消除该回归。

核心结论(worktree 隔离) Linux 上 before/after 确认
针对性单元测试 ✅ 1,865 通过
阻塞性问题 🔴 1 个 —— effective config 的 cwd 破坏了 MCP 审批绑定
非阻塞问题 🟡 2 个 —— worktree session 创建被 MCP 连接串行化;每条 shell 命令泄漏一个 abort listener

1. 环境

worktree  /root/wt/wt8068-pr  @ 1b4aefc819   (base 分支: git checkout 1643a6c9ae -- <PR 的 15 个文件>)
构建      npm run build (core, acp-bridge, cli) && npm run bundle  ->  dist/cli.js
daemon    node dist/cli.js serve --workspace <tmp>/base --hostname 127.0.0.1 --port <p> --enable-session-shell
          隔离的 HOME、QWEN_RUNTIME_DIR、QWEN_SERVER_TOKEN;所有场景都不需要真实模型流量
workspace 临时 git 仓库;.qwen/settings.json 声明一个**没有** `cwd` 的 stdio MCP server
          (一个 Node 脚本,每次进程启动都把 {pid, cwd} 追加写入日志)
驱动      POST /session {cwd, worktree:{slug}} x2,然后在两个 session 上并发 POST /session/:id/shell

2. 已确认:修复有效

(截图见上方英文部分。)

检查项(同一 workspace 下 2 个并发 worktree session) BEFORE 1643a6c9ae AFTER 1b4aefc819
Session A direct-shell cwd <repo> 🔴 <repo>/.qwen/worktrees/e2e-a
Session B direct-shell cwd <repo> 🔴 <repo>/.qwen/worktrees/e2e-b
<repo>/same-name.txt(主 checkout) 'B-shell' —— A 的写入被覆盖 🔴 不存在 ✅
worktrees/e2e-a/same-name.txt 不存在 🔴 'A-shell'
worktrees/e2e-b/same-name.txt 不存在 🔴 'B-shell'
两个 session 各自 git commit 都提交到 mainbase HEAD 发生移动 🔴 分别落在 worktree-e2e-a / worktree-e2e-b
Base HEAD 2d5720240ac730 🔴 未变 ✅
隐式 cwd 的 stdio MCP 进程 1 个共享进程,cwd = <repo>,refs=2 🔴 2 个,cwd 各为对应 worktree ✅

MCP 证据取自进程自身的启动记录,因此可以证明第一次 spawn 就已经在 worktree 中——延迟 discovery 生效,不存在"先在主 checkout 启动再迁移"的窗口。两个 session 均以 204 关闭;主 checkout 最终只剩 README.md.gitignore.qwen/

3. 🔴 阻塞项 —— effective config 的 cwd 破坏了 MCP 审批绑定

mcpApprovals.json 把用户决定绑定到 hashMcpServerConfig(config),而 cwd 属于行为性字段(不在 NON_BEHAVIORAL_FIELDS 中,packages/core/src/mcp/configHash.ts:16)。本 PR 之后,这份契约的两端开始对不同的对象求哈希:

  • raw settings 条目 —— qwen mcp approve/list,以及关键的 discovery gate getPendingGatedMcpServers(mcpServers, cwd)packages/cli/src/config/config.ts:2036),它决定一个受管控的 server 是否允许启动;
  • effective config —— daemon/ACP 侧使用 config.getMcpServers()packages/cli/src/acp-integration/acpAgent.ts:5220 状态、:8290 审批),因此现在会看到 packages/core/src/config/config.ts:5071-5081 注入的 cwd: this.targetDir

针对一个用户已经批准过的 workspace-settings stdio server,在真实 daemon 上实测:

步骤 BEFORE 1643a6c9ae AFTER 1b4aefc819
1. qwen mcp approve cwdprobe 存入 hash 37637fa790db… 存入 hash 37637fa790db…
2. daemon 启动 session —— server 确实 spawn 并连接成功 GET /workspace/mcp → 已批准 ✅ approvalState: "pending"status: "warning" 🔴
3. 操作者在 Web Shell 点击 Approve hash 不变 hash 被改写3803e8b53e46…(绑定了 cwd)🔴
4. qwen mcp list Disconnected(即已批准) Pending approval 🔴
5. 重启 daemon 并新建 session 有新的 MCP 进程 spawn ✅ 没有任何进程 spawn —— server 被静默拦截 🔴

两个用户可见的故障:

  1. 虚假的"需要批准"。 McpManagerPage.tsx:171 只要 approvalState === 'pending' 就渲染 mcp.status.needsApproval,因此每个已批准的 project/workspace scope stdio server 即便正在连接并提供 tool,也会在 Web Shell 里显示为待批准。所有已经批准过此类 server 的用户在升级后都会看到——因为存量 hash 是在还没有 cwd 的时候算出来的。
  2. 点了 Approve 反而更糟。 点击 Approve 会把存储的决定重新绑定到带 cwd 的 config 上。而 gate 仍然对 raw 条目求哈希,于是下次 daemon 启动时 isMcpServerPendingApproval() 为真,discoverAllMcpToolsIncremental 会在任何 spawn 之前跳过该 server。上表第 5 步就是这个结果:0 个新进程,entrySummary: null。worktree session 只会更糟——注入的 cwd 每个 worktree 都不同,任何单一 hash 都不可能同时匹配。

只有 scope: 'project'.mcp.json)和 scope: 'workspace'.qwen/settings.json)会被 gate(isGatedMcpScope),user scope 与 --mcp-config 不受影响。

候选修复(已在本地验证)

getMcpServers() 保持为配置的稳定视图,把隐式 cwd 的绑定下沉一层,放到所有 spawn 路径都必经的 transport-config 接缝 —— populateMcpServerCommand(servers, cmd, cwd)。本 PR 已经把 getTargetDir() 传到了 mcp-client-manager.ts 的全部 6 个调用点以及 discoverMcpTools

--- a/packages/core/src/config/config.ts
   getMcpServers(): Record<string, MCPServerConfig> | undefined {
     ...
-    return Object.fromEntries(
-      Object.entries(mcpServers).map(([name, server]) => [ ...cwd 注入... ]),
-    );
+    return mcpServers;
   }

--- a/packages/core/src/tools/mcp-client.ts
   export function populateMcpServerCommand(mcpServers, mcpServerCommand, cwd?) {
     if (mcpServerCommand) { ... }
-    return mcpServers;
+    if (cwd === undefined) return mcpServers;
+    return Object.fromEntries(
+      Object.entries(mcpServers).map(([name, server]) => [
+        name,
+        server.command !== undefined && server.httpUrl === undefined &&
+        server.url === undefined && server.type !== 'sdk' && server.cwd === undefined
+          ? { ...server, cwd } : server,
+      ]),
+    );
   }

重新构建后跑同样两套 harness:worktree 隔离完全不变(2 个 MCP 进程各在自己的 worktree;每个 session 独立的 direct-shell cwd;主 checkout 未被写入;base HEAD 未移动),审批回归消失(上表每一行都与 BEFORE 列一致)。它同时还避免了 populateMcpServerCommand 直接修改调用方的活配置 map —— 那正是目前 --mcp-server-command 合成条目会渗入 config 状态的原因。

代价:有 5 处断言写死了"getMcpServers() 应返回 cwd",需要下移一层 —— core/src/config/config.test.ts(2 处:binds command MCP servers without an explicit cwd…relocateWorkingDirectory should reconcile…)、core/src/config/config.safe-mode.test.ts(2 处)、cli/src/config/config.test.ts(1 处:should parse inline JSON with mcpServers wrapper)。其余全部保持通过(打上补丁后 core 717/721、cli 314/315,失败的正好就是这 4+1 条断言)。

4. 🟡 worktree session 创建现在被 MCP 连接串行化

relocateWorkingDirectory() 新增了 await this.waitForMcpReady(); await this.refreshMcpServers();config.ts:4582-4588),而 POST /session {worktree} 在返回前会 await bridge.changeSessionCwd(...)routes/session.ts:1717)。于是创建 session 现在会阻塞在 MCP 握手上。用一个把 initialize 响应拖延 25 秒的 mock stdio server 实测:

POST /session BEFORE 1643a6c9ae AFTER 1b4aefc819
普通 session(无 worktree) 658 ms 663 ms
worktree session 801 ms 25,865 ms

MCP 默认超时是 10 分钟(MCP_DEFAULT_TIMEOUT_MSEC),而 cd 的截止时间是 max(initTimeoutMs, 30_000)bridge.ts:6441);创建路由把 cd 失败视为致命错误:kill session、删除 worktree 及其分支,返回 500 worktree_relocate_failed。也就是说,一个慢的或卡死的 MCP server 现在可以让 worktree session 完全建不起来。把 relocation 时的 MCP reconcile 改成 fire-and-forget(它本来就只通过 mcpRefreshError 报 warning)即可解耦。

5. 🟡 小问题 —— 每条 direct shell 命令残留一个 abort listener

executeShellCommand 新增的竞速(bridge.ts:7794-7803)注册了 signal.addEventListener('abort', …, {once: true}),但在 cwd 队列先完成时不会移除。REST 路由每个请求都新建 AbortController,但 ACP 路径传入的是长生命周期的 per-session binding.abort.signalserve/acp-http/dispatch.ts:2793),因此 listener 会在 session 生命周期内不断累积 —— 实测 300 条命令后残留 300 个 listener。加一句 finally { signal?.removeEventListener('abort', onAbort); } 即可。

6. 观察到,但并非本 PR 引入

  • 在刚创建的 session 上并发发起两条 POST /session/:id/shell 时,第一条有时返回 exitCode: 0output 为空(每个分支里的 session B 都是如此)。base 构建上同样复现;顺序调用则始终返回正确输出。
  • daemon 重启。 createSessionEntryeffectiveCwd 初始化为 workspaceCwd,且只有 changeSessionCwd 会更新它;restore 路径(bridge.ts:4375 restoreSession)从不重新发起 cd。因此被恢复的 worktree session 的 direct shell 会退回主 checkout —— 这与 PR 自己"Not validated / out of scope"中的说明一致。此项仅为代码阅读结论,未实际驱动验证。

7. 1b4aefc819 上的针对性单元测试 —— 1,865 通过

packages/acp-bridge  src/bridge.test.ts                    464 passed
packages/core        src/config/config.test.ts             471 passed
                     src/config/config.safe-mode.test.ts    24 passed
                     src/tools/mcp-client.test.ts          109 passed
                     src/tools/mcp-client-manager.test.ts  117 passed
packages/cli         src/acp-integration/acpAgent.test.ts  343 passed
                     src/config/config.test.ts             315 passed
                     src/ui/commands/cdCommand.test.ts      22 passed

建议

隔离修复本身很扎实,值得合入。但建议先处理第 3 节:它会静默地让已批准的 MCP server 不再启动,触发条件是最自然的用户操作(点击 Approve),而且影响范围超出 worktree,波及每一个配置了受管控 stdio server 的 daemon workspace。第 4、5 节可作为后续跟进。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Review feedback dispositions

Addressed the one correctness bug in the new cwd-stamping predicate plus a
redundant-test nit; declined the rest with recorded reasons. No base conflict
(--conflict false), so no merge was performed.

Implemented

Finding 5 — stdio predicate diverges from mcpTransportOf (config.ts).
Fixed. Added server.tcp === undefined to the implicit-cwd stamping predicate
so a config carrying both tcp and command is left to the websocket path
(matching mcpTransportOf's tcp-before-command order) instead of receiving
a cwd stamp that perturbs its pool fingerprint for no reason. Added a comment
recording the order match and the config.tsmcp-client-manager.ts import
cycle that blocks a shared helper. Extended the stamping unit test with a
tcp + command server asserting no cwd is stamped.

Nit — redundant expect (acpAgent.test.ts). Removed
expect(localConfig._args[3]).toBeUndefined(); the preceding
toEqual(['node', ['server.js'], {}]) already enforces the exact 3-element
shape, so the index-3 check adds nothing.

Declined (with reasons)

Finding 1 — per-agent (frontmatter) MCP servers bypass the cwd binding.
Out of scope. Subagent frontmatter mcpServers are a separate feature this PR
does not touch; the suggested fixes are a refactor (extract a shared stamping
helper) or widening stamping into the subagent manager. Worth a follow-up issue
rather than expanding this already-large PR.

Finding 2 — stamping makes a stale targetDir fatal for every stdio server.
Declined. The fail-fast throw is the honest behavior: if the worktree is removed
mid-session, falling back to undefined would silently run servers in the
daemon process cwd — reintroducing the exact wrong-cwd bug this PR fixes.
Distinguishing implicit vs explicit cwd in the error message would require
carrying provenance for a cosmetic gain in an edge case.

Finding 3 — /cd blocks on a full MCP restart. Declined. As the review
notes, this is correctness-motivated: because cwd is part of the pool
fingerprint, the reconcile must release and re-acquire entries, and bounding it
with a timeout or making it fire-and-forget would weaken the relocation
guarantee the PR depends on.

Finding 4 — a failed deferred discovery is silent for worktree sessions.
Declined (follow-up). Surfacing mcpRefreshError warnings in the
POST /session response changes the API response contract — scope expansion
better handled in a dedicated PR.

Finding 6 — getMcpClientAccounting() bypasses getEffectiveMcpServers().
Declined. Pre-existing and cosmetic (one mcpServerCommand-derived server
classified unknown in the accounting snapshot); unrelated to cwd isolation.
Kept out to keep this PR focused; suitable follow-up.

Finding 7 — effectiveCwd not restored on session restore. Declined. The
review confirms this is not a regression (same shape as the prior
workspaceCwd behavior); out of scope for this fix.

Nit — abort listener stays attached after the cwd-queue wins the race
(bridge.ts).
Declined. The signal is per-request and discarded after the
request, so the listener is bounded by request lifetime and harmless (reviewer
concurs). Adding a finally removal is defense for a case that cannot
accumulate.

Nit — race unblocks only on caller abort; reuse withTimeout (bridge.ts).
Declined. cwdChangeQueue deliberately waits for the actual cd, not the
caller-facing timeout, so the shell command runs in the correct cwd. A timeout
that lets the race proceed would run the command in the stale effectiveCwd
the exact bug being fixed. Both production call sites bind the signal to client
disconnect, which covers the realistic hang case.

Nit — undefined, undefined positional filler (acpAgent.ts). Declined.
Converting to an options object touches the function signature — a refactor not
worth the diff growth here.

Changes

  • packages/core/src/config/config.ts — add tcp === undefined to the
    stamping predicate plus an explanatory comment.
  • packages/core/src/config/config.test.ts — cover a tcp + command server
    (no cwd stamped).
  • packages/cli/src/acp-integration/acpAgent.test.ts — drop the redundant
    assertion.

Verification

  • npx vitest run src/config/config.test.ts -t "binds command MCP servers"
    (core) — 1 passed
  • npx vitest run src/acp-integration/acpAgent.test.ts -t "MCP SSE/HTTP support"
    (cli) — 210 passed
  • npx vitest run src/config/config.test.ts src/tools/mcp-client-manager.test.ts src/tools/mcp-client.test.ts
    (core) — 698 passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npm run build — passed
  • npx prettier --check (3 changed files) — passed

No settings-schema source changed, so generate:settings-schema was not
required. The touched behavior is covered by unit tests, not the bundled CLI, so
no integration run was needed.

中文说明

评审反馈处理

修复了新 cwd 标记谓词中唯一的一个正确性 bug,以及一个冗余测试的小问题;其余各项均记录了理由后予以拒绝。无 base 冲突(--conflict false),因此未执行合并。

已实现

Finding 5 — stdio 谓词与 mcpTransportOf 不一致(config.ts)。
已修复。在隐式 cwd 标记谓词中增加了 server.tcp === undefined,使得同时带有 tcpcommand 的配置仍走 websocket 路径(与 mcpTransportOftcp 优先于 command 的顺序一致),而不会被打上 cwd 标记、无谓地扰动其连接池指纹。同时增加了一条评论,记录该顺序一致性,以及阻止抽取共享 helper 的 config.tsmcp-client-manager.ts 循环导入。并在标记单测中补充了一个 tcp + command 服务器用例,断言其不会被打上 cwd。

小问题 — 冗余的 expect(acpAgent.test.ts)。 删除了
expect(localConfig._args[3]).toBeUndefined();前面的
toEqual(['node', ['server.js'], {}]) 已经强制了精确的三元素结构,因此对索引 3 的检查毫无作用。

已拒绝(附理由)

Finding 1 — 每个 agent(frontmatter)的 MCP 服务器绕过了 cwd 绑定。
超出范围。子 agent 的 frontmatter mcpServers 是本 PR 未涉及的独立功能;建议的修复方案要么是重构(抽取共享的标记 helper),要么是把标记逻辑扩展进子 agent 管理器。更适合用一个后续 issue 处理,而不是扩大这个本已较大的 PR。

Finding 2 — 标记使得过期的 targetDir 对每个 stdio 服务器都致命。
拒绝。快速失败的抛错是诚实的行为:如果 worktree 在会话进行中被删除,回退到 undefined 会让服务器静默地在守护进程的 cwd 中运行——恰好重新引入本 PR 要修复的“错误 cwd”bug。在错误信息中区分隐式与显式 cwd,需要为一个边缘场景中的表面收益而携带来源信息。

Finding 3 — /cd 现在会阻塞在完整的 MCP 重启上。 拒绝。正如评审所指出的,这是出于正确性考虑:由于 cwd 是连接池指纹的一部分,reconcile 必须释放并重新获取条目,用超时限制它或改成 fire-and-forget 都会削弱本 PR 所依赖的重定位保证。

Finding 4 — worktree 会话中延迟发现失败时是静默的。 拒绝(建议后续处理)。在 POST /session 响应中暴露 mcpRefreshError 警告会改变 API 响应契约——属于范围扩张,更适合在专门的 PR 中处理。

Finding 6 — getMcpClientAccounting() 绕过了 getEffectiveMcpServers()
拒绝。这是既有问题,且只是表面问题(某个由 mcpServerCommand 派生的服务器在统计快照中被归类为 unknown);与 cwd 隔离无关。为保持本 PR 聚焦而未纳入;适合作为后续处理。

Finding 7 — 会话恢复时 effectiveCwd 未被还原。 拒绝。评审已确认这不是回归(与之前 workspaceCwd 的行为形态相同);超出本次修复范围。

小问题 — cwd 队列赢得竞争后 abort 监听器仍然挂着(bridge.ts)。
拒绝。该 signal 是每请求一次的,请求结束后即被丢弃,因此监听器的生命周期以请求为界、无害(评审也认同)。增加 finally 移除是为一个不会累积的情况做防御。

小问题 — 竞争只在调用方 abort 时解除;复用 withTimeoutbridge.ts)。
拒绝。cwdChangeQueue 刻意等待实际的 cd,而非面向调用方的超时,这样 shell 命令才能在正确的 cwd 中运行。如果用一个超时让竞争提前继续,命令就会在过期的 effectiveCwd 中运行——正是要修复的 bug。两个生产调用点都把 signal 绑定到客户端断开,这已覆盖了真实的挂起场景。

小问题 — undefined, undefined 位置参数占位(acpAgent.ts)。 拒绝。改成 options 对象会触及函数签名——属于不值得在此增加 diff 的重构。

变更内容

  • packages/core/src/config/config.ts — 在标记谓词中加入 tcp === undefined,并补充说明性注释。
  • packages/core/src/config/config.test.ts — 覆盖 tcp + command 服务器(不打 cwd)。
  • packages/cli/src/acp-integration/acpAgent.test.ts — 删除冗余断言。

验证

  • npx vitest run src/config/config.test.ts -t "binds command MCP servers"(core)— 1 通过
  • npx vitest run src/acp-integration/acpAgent.test.ts -t "MCP SSE/HTTP support"(cli)— 210 通过
  • npx vitest run src/config/config.test.ts src/tools/mcp-client-manager.test.ts src/tools/mcp-client.test.ts(core)— 698 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npm run build — 通过
  • npx prettier --check(3 个改动文件)— 通过

未改动任何 settings-schema 源文件,因此不需要 generate:settings-schema。所触及的行为由单元测试覆盖,而非打包后的 CLI,因此无需运行集成测试。

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

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


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

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

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

中文说明

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

— qwen3.8-max-preview via Qwen Code /review

Comment thread packages/core/src/config/config.ts Outdated
Comment on lines +5077 to +5089
return Object.fromEntries(
Object.entries(mcpServers).map(([name, server]) => [
name,
server.command !== undefined &&
server.httpUrl === undefined &&
server.url === undefined &&
server.tcp === undefined &&
server.type !== 'sdk' &&
server.cwd === undefined
? { ...server, cwd: this.targetDir }
: server,
]),
);

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.

[Critical] Injecting cwd: this.targetDir into getMcpServers() breaks the MCP approval hash contract. cwd is a behavioral field in hashMcpServerConfig (it is not in NON_BEHAVIORAL_FIELDS in configHash.ts), but the boot-time discovery gate getPendingGatedMcpServers (cli/src/config/config.ts) and qwen mcp approve hash the raw config, while the ACP status/approve paths (acpAgent.ts) hash the cwd-decorated config returned here. The two hashes never match. — Failure scenario: an already-approved project-/workspace-scoped stdio server shows approvalState: 'pending' ("Needs approval") in the Web Shell even while it is connected and serving tools; if the operator clicks Approve, a cwd-bound hash is persisted, and on the next daemon boot the gate (which hashes the raw config) no longer matches, so discoverAllMcpToolsIncremental skips the server before any spawn — silently gating it off. For worktree sessions the injected cwd differs per worktree, so no single stored hash can ever match all of them. Verified by probe: raw config hash aae5909… vs cwd-decorated 14b4b95… → mismatch; also reproduced against a real daemon in the PR thread (comment 5129580948).

Fix (spans two files, so not a one-click suggestion): keep getMcpServers() an identity-stable view of configuration and bind the implicit cwd one layer down, at the transport-config seam every spawn path already goes through — populateMcpServerCommand in mcp-client.ts, which this PR already threads getTargetDir() into. That is, return the merged map unchanged here and stamp cwd (same stdio predicate, fresh object) inside populateMcpServerCommand when a cwd argument is supplied.

中文说明

[Critical]getMcpServers() 中注入 cwd: this.targetDir 破坏了 MCP 审批哈希契约。cwdhashMcpServerConfig 中的行为性字段(不在 configHash.tsNON_BEHAVIORAL_FIELDS 中),但启动期的 discovery gate getPendingGatedMcpServerscli/src/config/config.ts)和 qwen mcp approve原始配置求哈希,而 ACP 的状态/审批路径(acpAgent.ts)对这里返回的、带 cwd 的配置求哈希。两端哈希永远不一致。— 故障场景:一个已批准的 project/workspace scope stdio server,即便已连接并正常提供 tool,也会在 Web Shell 中显示 approvalState: 'pending'("需要批准");若操作者点击 Approve,会持久化一个绑定 cwd 的哈希,下次 daemon 启动时 gate(对原始配置求哈希)不再匹配,于是 discoverAllMcpToolsIncremental 在任何 spawn 之前跳过该 server——静默将其拦截。对 worktree session,注入的 cwd 每个 worktree 都不同,任何单一存储哈希都不可能同时匹配。已通过 probe 验证:原始配置哈希 aae5909… 与带 cwd 的 14b4b95… 不一致;PR 讨论区(评论 5129580948)也在真实 daemon 上复现了该问题。

修复(跨两个文件,故不用一键 suggestion):让 getMcpServers() 保持配置的稳定视图,把隐式 cwd 的绑定下沉一层,放到所有 spawn 路径都必经的 transport-config 接缝——mcp-client.tspopulateMcpServerCommand(本 PR 已经把 getTargetDir() 传入其中)。即此处直接返回合并后的 map,而在 populateMcpServerCommand 收到 cwd 参数时(用相同的 stdio 谓词、构造新对象)打上 cwd

— qwen3.8-max-preview via Qwen Code /review

Comment thread packages/acp-bridge/src/bridge.ts Outdated
Comment on lines +7799 to +7802
new Promise<void>((resolve) => {
if (signal?.aborted) return resolve();
signal?.addEventListener('abort', () => resolve(), { once: true });
}),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The anonymous abort listener added inside this Promise.race is never removed when cwdChangeQueue wins the race (the normal path). The finally block below removes only the separate named onSignalAbort, not this closure, and { once: true } auto-removes a listener only after it fires. — Concrete cost: the ACP session/shell path passes a long-lived per-session signal (serve/acp-http/dispatch.ts), so each completed direct shell command leaks one dead abort listener on that signal for the session's lifetime (measured 300 retained listeners after 300 commands). Fix: hoist the listener to a named reference (e.g. onCwdQueueAbort) and remove it in the existing finally (signal?.removeEventListener('abort', onCwdQueueAbort)), mirroring the onSignalAbort pattern.

中文说明

[Suggestion] 在这个 Promise.race 内部添加的匿名 abort 监听器,在 cwdChangeQueue 赢得竞争(正常路径)时永远不会被移除。下方的 finally 块只移除了另一个具名的 onSignalAbort,并不会移除这个闭包;而 { once: true } 只在监听器触发后才自动移除。— 具体代价:ACP 的 session/shell 路径传入的是长生命周期的 per-session signal(serve/acp-http/dispatch.ts),因此每条完成的 direct shell 命令都会在该 signal 上泄漏一个失效的 abort 监听器,持续整个 session 生命周期(实测 300 条命令后残留 300 个监听器)。修复:把监听器提升为具名引用(如 onCwdQueueAbort),并在已有的 finally 中移除它(signal?.removeEventListener('abort', onCwdQueueAbort)),与 onSignalAbort 的写法保持一致。

— qwen3.8-max-preview via Qwen Code /review

getMcpServers() injected cwd into the effective config, which changed
the hash used for MCP approval binding (hashMcpServerConfig). This
caused approved project/workspace-scoped stdio servers to show as
pending approval, and re-approving silently gated them off on the next
daemon start.

Move the cwd stamping down to populateMcpServerCommand — the
transport-config seam every spawn path already goes through — so
getMcpServers() stays an identity-stable view of configuration and the
approval hash contract holds. Also make populateMcpServerCommand
non-mutating (spread instead of in-place assignment).

Additionally, clean up the abort listener registered during the
direct-shell cwd-queue race so it does not accumulate on the
long-lived per-session signal (ACP path).
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Round summary

Addressed the blocking finding and one non-blocking nit from @wenshao's independent verification report. Deferred one non-blocking finding per the reviewer's explicit recommendation.

§3 🔴 Blocking — MCP approval binding broken by effective-config cwd → Fixed

Decision: Required — correctness bug. getMcpServers() injected cwd into the effective config, which changed the hash computed by hashMcpServerConfig. Since mcpApprovals.json binds decisions to that hash, approved project/workspace-scoped stdio servers showed as "pending approval" and re-approving silently gated them off on the next daemon start.

Changes:

  • packages/core/src/config/config.ts — reverted getMcpServers() to return the raw merged map without cwd stamping, keeping it an identity-stable view of configuration.
  • packages/core/src/tools/mcp-client.ts — moved the cwd stamping into populateMcpServerCommand(), the transport-config seam every spawn path already goes through. The predicate mirrors mcpTransportOf's order (tcp before command). Also made the function non-mutating (spread instead of in-place mcpServers['mcp'] = …), which stops the synthetic --mcp-server-command entry from leaking into the caller's live map.
  • Updated 5 test assertions that encoded "getMcpServers() returns cwd" (core/config.test.ts ×2, core/config.safe-mode.test.ts ×2, cli/config.test.ts ×1) and added 3 new tests in core/tools/mcp-client.test.ts covering the stamping predicate, the no-cwd early return, and non-mutation.

This matches the candidate fix validated by @wenshao: worktree isolation is preserved (cwd stamping still happens at spawn time via getEffectiveMcpServers() and discoverMcpTools, both of which already pass getTargetDir()), and the approval hash contract holds because getMcpServers() no longer decorates the config.

§5 🟡 Abort listener leak → Fixed

Decision: Optional nit — small, valuable, in scope.

Changes:

  • packages/acp-bridge/src/bridge.ts — extracted the abort handler into a stable onAbort reference and added finally { signal?.removeEventListener('abort', onAbort); } so the listener is removed when the cwd queue wins the race. Previously the anonymous () => resolve() listener accumulated on the long-lived per-session binding.abort.signal (ACP path) for every shell command.

§4 🟡 Worktree session creation serialized behind MCP connect → Deferred

Decision: Deferred — the reviewer explicitly recommends this as a follow-up ("§4 and §5 are follow-ups"). Making the relocation-time MCP reconcile fire-and-forget changes the error-reporting semantics (mcpRefreshError is currently returned synchronously and tested), and the right async-error-surface design deserves a separate change. The current behavior is safe (MCP timeout is bounded, and the error is reported as a warning), just slow when an MCP server stalls its initialize reply.

§6 Observed, not caused by this PR → No action

Both items (concurrent shell empty output, daemon restart cwd restore) reproduce on the base build and are out of scope.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • vitest packages/core (config.test.ts, config.safe-mode.test.ts, mcp-client.test.ts, mcp-client-manager.test.ts) — 725 passed
  • vitest packages/acp-bridge (bridge.test.ts) — 464 passed
  • vitest packages/cli (config.test.ts, acpAgent.test.ts, cdCommand.test.ts) — 674 passed, 6 failed (pre-existing: 4 sandbox-image-resolution failures + 1 sandbox-session-ID failure + 1 home-dir permission failure; all reproduce on the base branch without this change)
中文说明

本轮总结

处理了 @wenshao 独立验证报告中的阻塞性问题和一个小问题。按评审者明确建议,推迟了一项非阻塞问题。

§3 🔴 阻塞项 —— effective config 的 cwd 破坏 MCP 审批绑定 → 已修复

决定: 必须修复 —— 正确性 bug。getMcpServers() 向 effective config 注入了 cwd,导致 hashMcpServerConfig 计算的哈希值发生变化。由于 mcpApprovals.json 将用户决定绑定到该哈希,已批准的 project/workspace scope stdio server 会显示为"待批准",而重新批准会在下次 daemon 启动时静默拦截该 server。

变更:

  • packages/core/src/config/config.ts —— 将 getMcpServers() 恢复为返回原始合并 map,不再注入 cwd,保持其作为配置的稳定视图。
  • packages/core/src/tools/mcp-client.ts —— 将 cwd 注入下沉到 populateMcpServerCommand(),即所有 spawn 路径必经的 transport-config 接缝。判定条件与 mcpTransportOf 的顺序一致(tcp 优先于 command)。同时将函数改为非变更式(使用 spread 而非原地赋值 mcpServers['mcp'] = …),避免合成的 --mcp-server-command 条目渗入调用方的活配置 map。
  • 更新了 5 处写死"getMcpServers() 应返回 cwd"的断言(core/config.test.ts ×2、core/config.safe-mode.test.ts ×2、cli/config.test.ts ×1),并在 core/tools/mcp-client.test.ts 新增 3 个测试,覆盖注入判定、无 cwd 提前返回、以及非变更式行为。

@wenshao 验证过的候选修复一致:worktree 隔离不受影响(cwd 注入仍在 spawn 时通过 getEffectiveMcpServers()discoverMcpTools 发生,两者都已传入 getTargetDir()),审批哈希契约得以保持,因为 getMcpServers() 不再修饰配置。

§5 🟡 abort listener 泄漏 → 已修复

决定: 可选小问题 —— 改动小、有价值、在范围内。

变更:

  • packages/acp-bridge/src/bridge.ts —— 将 abort 处理函数提取为稳定的 onAbort 引用,并添加 finally { signal?.removeEventListener('abort', onAbort); },确保 cwd 队列先完成时移除 listener。此前匿名的 () => resolve() listener 会在 ACP 路径的长生命周期 per-session binding.abort.signal 上不断累积。

§4 🟡 worktree session 创建被 MCP 连接串行化 → 推迟

决定: 推迟 —— 评审者明确建议作为后续跟进("§4 and §5 are follow-ups")。将 relocation 时的 MCP reconcile 改为 fire-and-forget 会改变错误报告语义(mcpRefreshError 目前是同步返回的,且有测试覆盖),异步错误表面的设计值得单独处理。当前行为是安全的(MCP 超时有上限,错误以 warning 形式报告),只是在 MCP server 拖延 initialize 响应时较慢。

§6 观察到但非本 PR 引入 → 不处理

两项(并发 shell 空输出、daemon 重启 cwd 恢复)均在 base 构建上复现,不在本 PR 范围内。

验证

  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • vitest packages/core(config.test.ts、config.safe-mode.test.ts、mcp-client.test.ts、mcp-client-manager.test.ts)—— 725 通过
  • vitest packages/acp-bridge(bridge.test.ts)—— 464 通过
  • vitest packages/cli(config.test.ts、acpAgent.test.ts、cdCommand.test.ts)—— 674 通过,6 失败(均为已有问题:4 个 sandbox-image-resolution 失败 + 1 个 sandbox-session-ID 失败 + 1 个 home 目录权限失败;在本变更之前的 base 分支上同样复现)

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

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Round summary — no changes needed

Both inline findings were already resolved by the HEAD commit 356ab6c20 ("fix(core): move MCP cwd stamping to populateMcpServerCommand (#8068)"), which landed after the review was generated.

[rc:3682390409] Critical — MCP approval hash contract broken by cwd in getMcpServers()

Already fixed. Commit 356ab6c20 moved the cwd stamping out of getMcpServers() and into populateMcpServerCommand — the transport-config seam every spawn path goes through. getMcpServers() now returns the merged config map unchanged, so the approval hash computed by the boot-time discovery gate and qwen mcp approve matches the hash used at runtime. Verified: getMcpServers() in config.ts (line ~5046) contains no cwd injection; populateMcpServerCommand in mcp-client.ts (line ~1187) accepts an optional cwd parameter and stamps it onto implicit stdio servers with the same predicate as mcpTransportOf.

[rc:3682390416] Suggestion — abort listener leak in direct-shell cwd-queue race

Already fixed. The same commit 356ab6c20 hoisted the anonymous abort listener to a named onAbort reference (bridge.ts line ~7798) and removes it in the finally block (signal?.removeEventListener('abort', onAbort), line ~7809), mirroring the onSignalAbort pattern. No listener accumulates on the long-lived per-session signal.

Review-level CHANGES_REQUESTED — integration tests not run

The review noted that "Integration Tests (CLI, No Sandbox)" were skipped in CI and not run locally. This is a CI scheduling/skipping issue, not a code defect. All unit tests for the touched packages pass (see verification below). The workflow's independent CI remains the final gate for integration test coverage.

Verification (read-only — no code changes this round)

  • vitest packages/core src/tools/mcp-client.test.ts — 112 passed
  • vitest packages/core src/config/config.test.ts — 472 passed
  • vitest packages/core src/tools/mcp-client-manager.test.ts + config.safe-mode.test.ts — 141 passed
  • vitest packages/acp-bridge src/bridge.test.ts — 464 passed
  • vitest packages/cli src/acp-integration/acpAgent.test.ts — 343 passed
  • vitest packages/cli src/ui/commands/cdCommand.test.ts — 21 passed, 1 failed (pre-existing sandbox EACCES on mkdtemp '/home/runner/...'; reproduces identically on origin/main)
中文说明

轮次总结 — 无需改动

两个行内发现均已由 HEAD 提交 356ab6c20("fix(core): move MCP cwd stamping to populateMcpServerCommand (#8068)")解决,该提交在评审生成之后才入库。

[rc:3682390409] Critical — getMcpServers() 中注入 cwd 破坏 MCP 审批哈希契约

已修复。 提交 356ab6c20cwd 的注入从 getMcpServers() 下沉到 populateMcpServerCommand——所有 spawn 路径都必经的 transport-config 接缝。getMcpServers() 现在原样返回合并后的配置 map,因此启动期 discovery gate 和 qwen mcp approve 计算的审批哈希与运行时使用的哈希一致。已验证:config.ts(约第 5046 行)中的 getMcpServers() 不含任何 cwd 注入;mcp-client.ts(约第 1187 行)中的 populateMcpServerCommand 接受可选的 cwd 参数,并使用与 mcpTransportOf 相同的谓词将其标记到隐式 stdio server 上。

[rc:3682390416] Suggestion — direct-shell cwd 队列竞争中的 abort 监听器泄漏

已修复。 同一提交 356ab6c20 将匿名 abort 监听器提升为具名引用 onAbort(bridge.ts 约第 7798 行),并在 finally 块中移除(signal?.removeEventListener('abort', onAbort),约第 7809 行),与 onSignalAbort 的写法保持一致。长生命周期的 per-session signal 上不会再累积监听器。

评审级 CHANGES_REQUESTED — 集成测试未运行

评审指出 "Integration Tests (CLI, No Sandbox)" 在 CI 中被跳过且未在本地运行。这是 CI 调度/跳过问题,不是代码缺陷。所有涉及包的单元测试均通过(见下方验证)。工作流的独立 CI 仍是集成测试覆盖的最终门禁。

验证(只读 — 本轮无代码改动)

  • vitest packages/core src/tools/mcp-client.test.ts — 112 通过
  • vitest packages/core src/config/config.test.ts — 472 通过
  • vitest packages/core src/tools/mcp-client-manager.test.ts + config.safe-mode.test.ts — 141 通过
  • vitest packages/acp-bridge src/bridge.test.ts — 464 通过
  • vitest packages/cli src/acp-integration/acpAgent.test.ts — 343 通过
  • vitest packages/cli src/ui/commands/cdCommand.test.ts — 21 通过,1 失败(预存的沙箱 EACCES 错误,mkdtemp '/home/runner/...' 权限不足;在 origin/main 上同样复现)

Deferred non-Critical feedback

Critical-only mode is active after 5 change-producing rounds: the automated reviewer's non-Critical suggestions below are deferred and stay open for human follow-up — do not modify code, resolve threads, or reply on their behalf. Maintainer feedback defers only once its author has already had 2 regular feedback batches addressed in this window's Critical-only tail — an account can host an automated reviewer loop, so the brake keys on measured regeneration, not identity; authors at their budget, if any, are named below. (A maintainer can lift the mode itself: @qwen-code /retry starts a fresh counting window.)

中文说明

完成 5 个产生改动的轮次后进入仅处理 Critical 的模式:以上为自动评审的非 Critical 建议,予以延后、保持开放并留待人工跟进——不要为其修改代码、解决线程或代为回复。维护者的反馈仅在其本人于本窗口 Critical-only 阶段已被处理 2 批常规反馈之后才会被延后——账号可能挂着自动评审循环,因此刹车依据实测的再生频度而非身份;达到预算的作者(如有)在下方点名。(如需解除该模式,评论 @qwen-code /retry 即可开启新的计数窗口。)

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

中文说明

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

— qwen3.8-max-preview via Qwen Code /review

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

No action taken

This round contains no actionable feedback:

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

The only content is deferred non-Critical feedback from the automated reviewer, which is in Critical-only mode and explicitly excluded from action.

No code changes were made.

中文说明

未采取任何操作

本轮没有可处理的反馈:

  • 评审:无
  • 行内评论:无
  • Issue 级别评论:无
  • 失败的检查:无
  • 持续失败的检查:无

唯一的内容是来自自动评审器的已延后非 Critical 反馈,当前处于仅处理 Critical 的模式,明确排除在操作范围之外。

未做任何代码更改。

Deferred non-Critical feedback

Critical-only mode is active after 5 change-producing rounds: the automated reviewer's non-Critical suggestions below are deferred and stay open for human follow-up — do not modify code, resolve threads, or reply on their behalf. Maintainer feedback defers only once its author has already had 2 regular feedback batches addressed in this window's Critical-only tail — an account can host an automated reviewer loop, so the brake keys on measured regeneration, not identity; authors at their budget, if any, are named below. (A maintainer can lift the mode itself: @qwen-code /retry starts a fresh counting window.)

中文说明

完成 5 个产生改动的轮次后进入仅处理 Critical 的模式:以上为自动评审的非 Critical 建议,予以延后、保持开放并留待人工跟进——不要为其修改代码、解决线程或代为回复。维护者的反馈仅在其本人于本窗口 Critical-only 阶段已被处理 2 批常规反馈之后才会被延后——账号可能挂着自动评审循环,因此刹车依据实测的再生频度而非身份;达到预算的作者(如有)在下方点名。(如需解除该模式,评论 @qwen-code /retry 即可开启新的计数窗口。)

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


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

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Local runtime validation (Linux) — the fix works, but it adds a blocking regression

I rebuilt both sides of this PR from source and drove a real qwen serve daemon on Linux (the row this PR marks ⚠️), plus the real TUI. Everything the PR claims about worktree isolation reproduces. I also found one regression that I think should be fixed before merge.

Arms — both built into real dist artifacts (node_modules link farm, no npm install), daemon driven from packages/cli/dist/index.js:

arm commit
BEFORE 1643a6c9ae (PR parent)
AFTER 356ab6c203 (PR head)

1. The isolation fix reproduces on Linux ✅

Two concurrent Web Shell worktree sessions under one daemon workspace; direct session shell, agent-side shell writes, git commits, and an implicit-cwd stdio MCP server, all driven over the real REST API.

isolation

The BEFORE arm reproduces the bug exactly as described, and slightly worse than the PR body states — both sessions' direct shells ran in the base checkout, so session A's same-name.txt was silently overwritten by session B's, and the single implicit-cwd MCP process was shared by both sessions from the base directory. On the AFTER arm every write, commit and MCP process stays in its own worktree, base HEAD does not move, and no session files land in the base checkout.

The MCP evidence is process-level: the mock stdio server records its OS pid and process.cwd() on startup. BEFORE = 1 process in <ws>; AFTER = 2 processes, one per worktree, with no transient spawn in the base checkout (the deferMcpDiscovery handoff works).

2. Both stated invariants hold ✅

Probed with two MCP servers configured simultaneously — one implicit-cwd, one with an explicit cwd:

BEFORE AFTER
explicit cwd server 1 process, pinned to the configured dir 1 process, still pinned (worktree session included)
2 plain sessions in the same dir share 1 implicit-cwd process still share 1
implicit-cwd process count 1 2 (one per distinct directory, not per session)

So the process-count tradeoff in "Risk & Scope" is bounded by distinct directories, not by session count — worth stating that way in the description.

3. Tests pass and have teeth ✅

All seven changed test files, on Linux / Node 22.22.2:

acp-bridge  src/bridge.test.ts                                          464 passed
core        config.test.ts, config.safe-mode.test.ts,
            mcp-client.test.ts, mcp-client-manager.test.ts              725 passed
cli         acpAgent.test.ts, cdCommand.test.ts                         365 passed
                                                                      ─────────────
                                                                     1554 passed, 0 failed

I then neutered each production hunk one at a time and re-ran the PR's own suites. 11/11 mutants killed — no hunk is untested:

# mutation result
M1 direct shell reads entry.workspaceCwd again killed
M2 drop the cwdChangeQueue wait before direct shell killed
M3 stop tagging worktree newSession with the defer flag killed
M4 shouldDeferMcpDiscovery always false killed
M5 drop the mcpRefreshError warning in acpAgent killed
M6 drop the mcpRefreshError warning in cdCommand killed
M7 relocateWorkingDirectory skips refreshMcpServers() killed
M8 populateMcpServerCommand stops stamping cwd killed
M9 drop the tcp guard from the stamping predicate killed
M10 getEffectiveMcpServers() drops getTargetDir() killed
M11 re-pin ACP-injected stdio MCP cwd to the newSession cwd killed

4. Review commit 356ab6c earned its place ✅

I re-created the intermediate commit b694051 behaviour (cwd stamped inside getMcpServers()) in the built artifact and started the TUI in a workspace whose gated MCP server was already approved. The approval modal re-fires, because useMcpApproval.ts:83 hashes config.getMcpServers() and cwd is a behavioural field in hashMcpServerConfig. With the final commit it does not. Persisted approval hash is byte-identical between BEFORE and AFTER (d734c5bf…), so the approval-binding contract is preserved.

approval


⛔ Blocking finding — relocation now waits on MCP discovery

relocateWorkingDirectory() gained await this.waitForMcpReady(); await this.refreshMcpServers(); inline, so the whole MCP connect/discovery round trip is now on the critical path of every relocation. Two constants collide:

  • stdio MCP discovery budget: 30 s (mcp-client-manager.ts:2533isRemote ? 5_000 : 30_000)
  • changeSessionCwd timeout: 30 s (bridge.ts:6441Math.max(initTimeoutMs, 30_000))

So a single slow or wedged stdio MCP server loses that race, and POST /session {worktree} is transactional — it kills the session and deletes the worktree.

regression

one stdio MCP server configured BEFORE AFTER
answers initialize immediately 200 in 1.0 s 200 in 1.0 s
initialize takes 6 s 200 in 1.0 s 200 in 7.2 s
never answers initialize 200 in 1.0 s 500 worktree_relocate_failed in 33.1 s, worktree deleted, session killed

The failure is deterministic (reproduced twice: 33.1 s / 33.2 s). This is not an exotic case — a first-run npx -y @some/mcp-server cold start routinely exceeds 30 s, and a wedged server (auth prompt, dead network mount) is the everyday failure mode. Today those users get degraded MCP; after this PR they cannot create a worktree session at all.

The same wait blocks /cd in the TUI, where there is no 30 s cap at all — the UI is frozen on the command for ~60 s (30 s for waitForMcpReady() on the old directory, then another 30 s for the reconcile in the new one):

cd freeze

Causality is confirmed, not inferred. I patched only that one call site in the built artifact — MCP refresh moved off the relocation critical path, everything else identical — and the wedged case went back to 200 in 1.0 s while the direct shell still correctly reported the worktree cwd. The isolation fix does not depend on the refresh being awaited.

Suggested direction

  1. Drop await this.waitForMcpReady() here. It waits for discovery in the directory we are about to leave, which the following reconcile supersedes anyway — it is pure added latency on both the daemon and /cd paths.
  2. Bound the reconcile (a short Promise.race deadline) or run it after the relocation returns, delivering mcpRefreshError through the existing warning/event stream instead of holding the caller. The mcpRefreshError plumbing and its tests stay useful either way.
  3. Worth a follow-up thought: the session/load restore path (routes/session.ts) catches a changeSessionCwd failure and only logs it, so with a slow MCP server a restored session would silently stay in the base checkout after a daemon restart — i.e. the exact bug this PR fixes. That path is already listed as out of scope, but the new timeout pressure makes it easier to hit.

Minor, not caused by this PR

When two direct shell commands run concurrently, the POST /session/:id/shell response occasionally comes back with exitCode: 0 but an empty output even though the command ran (the file it wrote is present). Observed on both arms, so it predates this PR — flagging it only so it is not mistaken for fallout here.


Verdict

The isolation fix itself is correct, well-scoped, genuinely tested, and reproduces end-to-end on Linux — the ⚠️ Linux row in the description can become ✅. I'd like the inline MCP wait in relocateWorkingDirectory() addressed before merge; with that one change I'm happy to approve.

中文版

本地运行时验证(Linux)——修复有效,但引入了一个阻塞性回归

我从源码分别构建了本 PR 的前后两个版本,在 Linux(本 PR 标记为 ⚠️ 的那一行)上驱动真实的 qwen serve daemon 和真实 TUI 进行验证。PR 描述中关于 worktree 隔离的所有结论都能复现。同时发现一个我认为应在合并前修复的回归。

两个构建——都构建成真实 dist 产物(node_modules link farm,无需 npm install),daemon 从 packages/cli/dist/index.js 启动:

版本 commit
BEFORE 1643a6c9ae(PR 父提交)
AFTER 356ab6c203(PR head)

1. 隔离修复在 Linux 上复现 ✅

同一 daemon workspace 下并发运行两个 Web Shell worktree session,通过真实 REST API 驱动 direct session shell、agent 侧 shell 写文件、git commit,以及一个未显式配置 cwd 的 stdio MCP server。

BEFORE 版本完整复现了该 bug,而且比 PR 描述的更严重:两个 session 的 direct shell 都运行在主 checkout 中,session A 的 same-name.txt 被 session B 静默覆盖;单个隐式 cwd 的 MCP 进程也被两个 session 共享,且位于主目录。AFTER 版本中每一次写入、每一个 commit、每一个 MCP 进程都留在各自的 worktree 内,base HEAD 不变,主 checkout 中没有出现任何 session 文件。

MCP 证据是进程级的:mock stdio server 在启动时记录自己的 OS pid 与 process.cwd()。BEFORE = 1 个进程在 <ws>;AFTER = 2 个进程,每个 worktree 一个,并且没有在主 checkout 中出现短暂的启动(deferMcpDiscovery 交接生效)。

2. 两个既定不变量成立 ✅

同时配置两个 MCP server(一个隐式 cwd,一个显式 cwd)后探测:

BEFORE AFTER
显式 cwd server 1 个进程,固定在配置目录 1 个进程,仍然固定(含 worktree session)
同目录下 2 个普通 session 共享 1 个隐式 cwd 进程 仍然共享 1 个
隐式 cwd 进程数 1 2(按不同目录计,而非按 session 计)

所以 "Risk & Scope" 中提到的进程数上涨是以不同目录数为上界,而不是 session 数——建议在描述里这样表述。

3. 测试通过且有实际约束力 ✅

七个被改动的测试文件,Linux / Node 22.22.2:

acp-bridge  src/bridge.test.ts                                          464 passed
core        config.test.ts, config.safe-mode.test.ts,
            mcp-client.test.ts, mcp-client-manager.test.ts              725 passed
cli         acpAgent.test.ts, cdCommand.test.ts                         365 passed
                                                                      ─────────────
                                                                     1554 passed, 0 failed

随后我逐个把生产代码的改动点还原/破坏,再跑 PR 自带的测试套件。11/11 变异全部被杀死——没有任何一个改动点缺少测试覆盖:

# 变异 结果
M1 direct shell 重新读 entry.workspaceCwd killed
M2 去掉 direct shell 前的 cwdChangeQueue 等待 killed
M3 worktree newSession 不再打 defer 标记 killed
M4 shouldDeferMcpDiscovery 恒为 false killed
M5 去掉 acpAgentmcpRefreshError warning killed
M6 去掉 cdCommandmcpRefreshError warning killed
M7 relocateWorkingDirectory 跳过 refreshMcpServers() killed
M8 populateMcpServerCommand 不再 stamp cwd killed
M9 stamping 判定去掉 tcp 守卫 killed
M10 getEffectiveMcpServers() 不传 getTargetDir() killed
M11 ACP 注入的 stdio MCP cwd 重新固定到 newSession 的 cwd killed

4. Review commit 356ab6c是必要的 ✅

我在构建产物中重建了中间提交 b694051 的行为(在 getMcpServers() 内 stamp cwd),然后在一个 gated MCP server 已被批准的 workspace 中启动 TUI:审批弹窗会再次出现——因为 useMcpApproval.ts:83config.getMcpServers() 做哈希,而 cwdhashMcpServerConfig 中属于行为字段。使用最终提交则不会。持久化的审批哈希在 BEFORE / AFTER 之间完全一致(d734c5bf…),审批绑定契约得以保持。

⛔ 阻塞性问题——relocation 现在会等待 MCP discovery

relocateWorkingDirectory() 新增了内联的 await this.waitForMcpReady(); await this.refreshMcpServers();,于是整个 MCP 连接/发现往返被放到了每次 relocation 的关键路径上。这里有两个常量正面冲突:

  • stdio MCP discovery 预算:30 秒mcp-client-manager.ts:2533isRemote ? 5_000 : 30_000
  • changeSessionCwd 超时:30 秒bridge.ts:6441Math.max(initTimeoutMs, 30_000)

因此只要有一个慢的或卡住的 stdio MCP server,这个竞争就会输,而 POST /session {worktree}事务性的——会杀掉 session 并删除 worktree。

配置一个 stdio MCP server BEFORE AFTER
立即响应 initialize 200,1.0 秒 200,1.0 秒
initialize 耗时 6 秒 200,1.0 秒 2007.2 秒
从不响应 initialize 200,1.0 秒 500 worktree_relocate_failed,33.1 秒,worktree 被删除,session 被杀

该失败是确定性的(复现两次:33.1 秒 / 33.2 秒)。这并非罕见场景——首次执行 npx -y @some/mcp-server 冷启动经常超过 30 秒,而卡住的 server(等待授权、网络挂载失效)本来就是最常见的故障形态。目前这些用户只是 MCP 降级;合并本 PR 后他们将完全无法创建 worktree session。

同一个等待也会阻塞 TUI 中的 /cd,而那条路径上没有任何 30 秒上限——界面在命令上冻结约 60 秒(旧目录上的 waitForMcpReady() 占 30 秒,新目录上的 reconcile 再占 30 秒)。

因果关系是实测的,不是推断的。 我只在构建产物中改了这一个调用点——把 MCP refresh 移出 relocation 关键路径,其余完全不变——卡住场景立刻恢复为 200、1.0 秒,同时 direct shell 仍然正确报告 worktree cwd。也就是说,隔离修复本身并不依赖这个 await。

建议方向

  1. 去掉这里的 await this.waitForMcpReady()。它等待的是即将离开的那个目录上的 discovery,随后的 reconcile 本来就会取代它——在 daemon 和 /cd 两条路径上都是纯粹的额外延迟。
  2. 给 reconcile 加上界(用一个较短的 Promise.race deadline),或者在 relocation 返回之后再执行,把 mcpRefreshError 通过现有的 warning/event 通道投递出去,而不是让调用方一直等待。无论采用哪种方式,mcpRefreshError 的管线和相关测试都仍然有价值。
  3. 一个值得后续关注的点:session/load 恢复路径(routes/session.ts)对 changeSessionCwd 失败只做 catch + log,因此在 MCP 较慢时,daemon 重启后被恢复的 session 会静默地停留在主 checkout——正是本 PR 要修的那个 bug。该路径已被列为 out of scope,但新的超时压力会让它更容易触发。

次要问题,与本 PR 无关

两个 direct shell 命令并发执行时,POST /session/:id/shell 偶尔会返回 exitCode: 0output 为空,尽管命令确实执行了(它写的文件存在)。两个版本上都能观察到,说明早于本 PR——在此说明,以免被误认为是本次改动的副作用。

结论

隔离修复本身是正确的、范围合理、测试真实有效,并且在 Linux 上端到端复现——描述中 Linux 的 ⚠️ 可以改成 ✅。希望在合并前处理掉 relocateWorkingDirectory() 里内联的 MCP 等待;解决这一点后我可以 approve。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix could not start — a setup step failed (or the run was cancelled) before the agent ran, so no fix was attempted. This is normally a transient infra issue, a broken base build, or a cancelled run — not this PR. It will retry on the next scan.

AutoFix failed before producing a verified commit (the run crashed or timed out before it could explain why).

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


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

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Local verification — real daemon, A/B against the merge base

Verdict: merge-ready. Every claim in the PR description that I could test reproduced, and the defect reproduces cleanly on the merge base with the same harness. Verified head 356ab6c2088b8 (fix/web-shell-worktree-session-isolation), control 1643a6c9ae7d6 (merge base). macOS 15 (darwin 25.6.0), Node v24.18.1.

One correction to the PR description is in the Corrections section below — it understates one of the failure modes.

中文摘要(点击展开)

结论:可以合并。 用真实 daemon 在临时 Git 仓库里跑了 A/B 对照:同一 workspace 下并发两个 worktree session,分别执行 direct session shell、agent shell 写文件、git commit,以及一个未显式配置 cwd 的 stdio MCP tool。

  • 合并前(merge base 1643a6c9a:两个 worktree session 的 direct shell 都跑在主 checkoutpwdgit rev-parse --abbrev-ref HEAD 都指向 base / main)。两个 session 写同名文件 same-name.txt 时互相覆盖,只剩一份内容;git commit 一个因为 index.lock 冲突失败、另一个直接提交到了 base 分支 main 上并推进了 base HEAD。隐式 cwd 的 stdio MCP 只起了一个进程、cwd 是主 checkout,两个 session 共用,并在主 checkout 留下了文件。
  • 合并后(PR head 356ab6c20:以上每一项都落在各自的 worktree;base checkout 没有任何业务文件,base HEAD 不变;MCP 起了两个进程,第一次 spawn 的 cwd 就分别是 wt-a / wt-b,不存在"先在 base 起来再迁移"的窗口。
  • 对照组不受影响:built-in file/shell 工具本来就是隔离的(合并前后一致);非 worktree 的普通 session,MCP cwd 仍然是 workspace 目录(符合预期,没有被这个改动带偏)。
  • 测试有效性:把 PR 的 7 个测试文件单独 checkout 到 merge base 源码上,16 个新断言全部失败;在 PR head 上 1554 个测试全绿。也就是说这些测试确实卡住了这个 bug,不是摆设。
  • 已跑通typecheck(core + acp-bridge)、ESLint、Prettier、git diff --check 全部通过。
  • 需要注意:PR 描述里 direct shell 的问题被写轻了——真实表现不只是"用了 base 目录",而是提交会落到 base 分支上并移动 base HEAD,这是数据丢失级别的后果。详见下面 Corrections
  • 未覆盖:daemon 重启后的 worktree 恢复、LSP root、Git 侧边栏、split-pane 元数据;Windows / Linux 未测。

How I verified

A standalone harness boots a real qwen serve daemon (scripts/dev.js serve --enable-session-shell, TypeScript source, --workspace pointed at a throwaway git init repo), then over plain HTTP:

  1. POST /session twice with worktree: {slug} → two worktree sessions in one workspace;
  2. POST /session/:id/shell concurrently in both — pwd, write same-name.txt, print the current branch;
  3. POST /session/:id/prompt concurrently in both, driven by a fake OpenAI-compatible server that emits a run_shell_command tool call and then an mcp__probe__report_cwd tool call;
  4. POST /session/:id/shell again to git add && git commit inside each session;
  5. a third non-worktree session as a control cell.

The MCP server is a mock stdio server configured with no cwd — the exact case this PR changes. It appends its own process.cwd() to a spawn log on startup and drops a breadcrumb file there, so "where did the process actually start" is observable independently of what the tool returns.

The same harness ran unchanged on both commits. Note that @qwen-code/acp-bridge resolves to dist/, not source, so packages/acp-bridge was rebuilt after each checkout — without that the control cell silently runs the fixed bridge. Both cells were run twice; results were identical.

A/B matrix

A/B matrix: before vs after

Observation BEFORE (merge base) AFTER (PR head)
Direct shell cwd — session A <base> <base>/.qwen/worktrees/wt-a fixed
Direct shell cwd — session B <base> <base>/.qwen/worktrees/wt-b fixed
Direct shell git branch — A main worktree-wt-a fixed
Direct shell git branch — B main worktree-wt-b fixed
same-name.txt in BASE checkout A-direct-shell (absent) fixed
same-name.txt in worktree A (absent) A-direct-shell fixed
same-name.txt in worktree B (absent) B-direct-shell fixed
git commit — A lands on FAILED (index.lock held) worktree-wt-a @ 0d24e46c fixed
git commit — B lands on main @ 40d511e1 worktree-wt-b @ 93fb6a1e fixed
BASE branch HEAD moved? yes no fixed
stdio MCP spawn cwd(s) <base> (one process, shared) …/wt-a and …/wt-b (two) fixed
MCP tool-reported cwd — A <base> <base>/.qwen/worktrees/wt-a fixed
MCP tool-reported cwd — B <base> <base>/.qwen/worktrees/wt-b fixed
MCP probe file in BASE checkout present — leaked (absent) fixed
agent-same.txt in worktree A / B A-agent / B-agent A-agent / B-agent control cell
control session (no worktree) MCP cwd <base> <base> control cell

The last two rows are the controls that make the rest meaningful: built-in agent tools were already isolated before this PR (so the diff is not papering over a broader breakage), and a plain non-worktree session still gets the workspace directory as its MCP cwd (so the new stamping did not over-reach).

Before: what the merge base actually did to the base checkout

BEFORE: base checkout damage

The MCP evidence is worth calling out separately: on the merge base the spawn log holds one entry, cwd <base>, for two sessions — the pool key had no cwd to separate them, so both sessions shared one process rooted in the wrong tree. On the PR head the log holds two entries whose first cwd is already the respective worktree, which is what the deferred-discovery half of the change buys: there is no window where the process exists in the base checkout at all.

Test efficacy

Test efficacy on the merge base

The PR's 7 test files were checked out onto merge-base source and run there. 16 new assertions fail, each naming the behaviour this PR adds; all 1,554 tests in those files pass on the PR head.

Package New assertions failing on merge base On PR head
packages/acp-bridge 5 (defer flag, effective cwd, pending-cd wait, failed-cd fallback, abort while cd hung) 464 passed
packages/core 7 (MCP reconcile on relocate, both error paths, pool routing, cwd stamping, no input mutation) 725 passed
packages/cli 4 (worktree discovery deferral, refresh warning, implicit ACP stdio cwd, cdCommand warning) 365 passed

Also green on the PR head: npm run typecheck in packages/core and packages/acp-bridge, ESLint and Prettier over the seven changed source files, and git diff --check.

Corrections

The PR description says direct shell commands "previously used the base workspace directory". That is true but reads as a cosmetic path bug. What the harness observed is stronger and worth putting in the description: because the direct shell ran in the base checkout, git commit from a worktree session committed to the base branch and moved base HEAD, and a second concurrent session lost its commit outright to index.lock contention. Two concurrent worktree sessions could therefore silently rewrite the user's main branch. I'd suggest promoting that sentence in Why it's needed — it changes how a reviewer weighs the fix.

Two smaller notes, neither blocking:

  • The description's "an MCP process could briefly start in the base checkout" understates the pre-fix state as measured here: it started there and stayed there, shared by both sessions, for the lifetime of the run.
  • Test counts in the description have drifted slightly (ACP bridge 462 vs 464 measured). Cosmetic.

Not covered

Daemon restart / load worktree restoration, LSP root relocation, Git UI and sidebar cwd ownership, split-pane worktree metadata, and hooks/extensions — all listed as out of scope in the PR and not exercised here. Windows and Linux untested; this run is macOS only. The MCP server was configured at user scope rather than workspace scope, because workspace-scoped MCP servers sit behind the per-project approval gate and never connect unattended; the cwd behaviour under test is identical for both scopes.

Harness, raw result JSON, and the screenshots above are reproducible from the description in How I verified; evidence images hosted at pr-assets/local-verify-8068.

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

yiliang114
yiliang114 previously approved these changes Jul 30, 2026

@yiliang114 yiliang114 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. The cwd isolation is well-structured: shell commands serialize behind the cwd queue with a proper abort race, worktree sessions defer MCP discovery until relocation, and populateMcpServerCommand stamps cwd only on implicit stdio servers without mutating the input. The getEffectiveMcpServers() extraction removes 6 duplicate call sites cleanly. Test coverage is thorough across all layers.

@wenshao
wenshao enabled auto-merge July 30, 2026 15:02
@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /resolve

Resolve import conflict in bridge.test.ts by keeping both WORKTREE_MCP_DEFER_META_KEY (this PR) and LOAD_REPLAY_HIDE_INHERITED_META_KEY (main) in the bridgeTypes import block.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code resolved the merge conflicts and pushed the branch update.

Merge resolution: PR #8068 ← origin/main

Root cause

Main's feat(web-shell): add contextual task panels (#7929, commit 0a3098a27) added the constant LOAD_REPLAY_HIDE_INHERITED_META_KEY to the ./bridgeTypes.js import block in packages/acp-bridge/src/bridge.test.ts. This PR (#8068, commit 2f4ef7ceb) added WORKTREE_MCP_DEFER_META_KEY to the same import block, right after CHANNEL_STARTUP_PROFILE_VERSION. Two independent additions on the same line collided.

Textual, not semantic

Purely textual. The sides only touched adjacent lines of one import statement; neither modified the same logic. Both constants are independently exported by the auto-merged bridgeTypes.ts and consumed by unrelated tests. Resolution keeps both:

import {
  CHANNEL_STARTUP_PROFILE_META_KEY,
  CHANNEL_STARTUP_PROFILE_VERSION,
  WORKTREE_MCP_DEFER_META_KEY,          // this PR
  LOAD_REPLAY_HIDE_INHERITED_META_KEY,  // main (#7929)
} from './bridgeTypes.js';

This was the only conflicted file. The other six files touched on both sides (bridge.ts, bridgeTypes.ts, acpAgent.ts, acpAgent.test.ts, config.ts, config.test.ts) auto-merged cleanly.

What is load-bearing

Nothing order-sensitive: import order is irrelevant here; the only requirement is that both names stay imported from ./bridgeTypes.js. Both are still exported there (verified: line 170 LOAD_REPLAY_HIDE_INHERITED_META_KEY, line 178 WORKTREE_MCP_DEFER_META_KEY in the merged bridgeTypes.ts) and still referenced by their tests.

What I could not verify

No build, typecheck, or tests were run (out of scope). I confirmed symbol presence, not semantic coherence, of the six auto-merged files. Those merges combine this PR's worktree-isolation logic with unrelated main features landed since the merge base — notably #7929 and the daemon session-maintenance writer changes (#7975, #8144). If any interacts with the worktree isolation path, only the PR's CI will surface it; I must not edit those non-conflicted files here.

中文说明

根因

main 的 feat(web-shell): add contextual task panels#7929,提交 0a3098a27)在 packages/acp-bridge/src/bridge.test.ts./bridgeTypes.js 导入块新增了常量 LOAD_REPLAY_HIDE_INHERITED_META_KEY;本 PR(#8068,提交 2f4ef7ceb)在同一导入块、紧接 CHANNEL_STARTUP_PROFILE_VERSION 之后新增了 WORKTREE_MCP_DEFER_META_KEY。两个互不相关的导入加在同一行而冲突。

文本冲突,非语义冲突

纯文本冲突。双方只改动同一条 import 语句的相邻行,未修改相同逻辑。两个常量都由自动合并后的 bridgeTypes.ts 独立导出,并被互不相关的测试使用。解决方式为两者都保留(见上方代码块)。这是唯一冲突的文件;其余六个双方都改动的文件(bridge.tsbridgeTypes.tsacpAgent.tsacpAgent.test.tsconfig.tsconfig.test.ts)均干净地自动合并。

关键点

无顺序敏感之处:导入顺序在此无关紧要,唯一要求是两个名称都继续从 ./bridgeTypes.js 导入。两者仍被导出(已核实:合并后 bridgeTypes.ts 第 170 行 LOAD_REPLAY_HIDE_INHERITED_META_KEY、第 178 行 WORKTREE_MCP_DEFER_META_KEY),并各自被相应测试引用。

无法验证的部分

本命令不运行构建、类型检查或测试。对那六个自动合并文件,我只确认符号存在,未验证语义一致性。这些合并把本 PR 的 worktree 隔离逻辑与 merge base 之后落地的若干无关 main 功能组合在一起,尤其是 #7929 与守护进程会话维护写入方改动(#7975#8144)。若它们与 worktree 隔离路径有交互,只有本 PR 的 CI 才能发现;我不应也不能在此修改那些未冲突文件。

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

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@wenshao

wenshao commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up: a validated fix for the blocking finding

Two notes since my previous comment:

  1. The finding survives the main merge. I re-checked at 23f08bcb8f: packages/core/src/tools/mcp-client.ts, mcp-client-manager.ts and cdCommand.ts are byte-identical to what I verified, and the bridge.ts / acpAgent.ts / config.ts deltas are merge-only — relocateWorkingDirectory() still has await this.waitForMcpReady(); await this.refreshMcpServers(); inline at config.ts:4645. All the PR's own hunks are intact.
  2. I built and ran a candidate fix, so the suggestion is measured rather than asserted.

The fix

Bound the reconcile instead of dropping it. mcpRefreshError semantics are preserved for every reconcile that settles inside the budget, which is what the PR's two new relocateWorkingDirectory tests exercise — they stay green unchanged.

--- a/packages/core/src/config/config.ts
+++ b/packages/core/src/config/config.ts
@@ -1661,6 +1661,14 @@ export type SubSessionSpawner = (

 class SessionWriterShutdownError extends SessionWriterUnavailableError {}

+/**
+ * How long {@link Config.relocateWorkingDirectory} waits for the MCP reconcile
+ * against the new directory before letting it finish in the background. Kept
+ * well under the daemon's 30s `changeSessionCwd` timeout so a slow MCP server
+ * degrades the reconcile, never the relocation itself.
+ */
+const MCP_RELOCATE_REFRESH_BUDGET_MS = 5_000;
+
 export class Config {
@@ -4580,11 +4588,42 @@ export class Config {
     }

     let mcpRefreshError: unknown;
-    try {
+    // Rebinding MCP to the new directory must never hold the caller longer
+    // than the relocation itself is allowed to take. stdio discovery carries
+    // its own 30s budget (McpClientManager) and the daemon's
+    // `changeSessionCwd` times out at 30s, so awaiting the full reconcile
+    // lets a single slow MCP server fail a Web Shell worktree relocation
+    // outright (500 `worktree_relocate_failed`, worktree deleted) and freeze
+    // `/cd` for as long as discovery runs. Bound the wait; a reconcile that
+    // overruns keeps running and still reports per-server failures through
+    // the `mcp-client-update` stream.
+    const mcpRefresh = (async () => {
       await this.waitForMcpReady();
       await this.refreshMcpServers();
-    } catch (error) {
-      mcpRefreshError = error;
+    })().then(
+      () => 'settled' as const,
+      (error: unknown) => {
+        mcpRefreshError = error;
+        return 'settled' as const;
+      },
+    );
+    let budgetTimer: ReturnType<typeof setTimeout> | undefined;
+    const refreshOutcome = await Promise.race([
+      mcpRefresh,
+      new Promise<'overran'>((resolve) => {
+        budgetTimer = setTimeout(
+          () => resolve('overran'),
+          MCP_RELOCATE_REFRESH_BUDGET_MS,
+        );
+        budgetTimer.unref?.();
+      }),
+    ]);
+    if (budgetTimer) clearTimeout(budgetTimer);
+    if (refreshOutcome === 'overran') {
+      this.debugLogger.debug(
+        '[mcp-hot-reload] relocation reconcile overran its budget — ' +
+          'continuing in the background',
+      );
     }

     return {

One file, +42/−3. mcpRefreshError is read at return time, so a late assignment from an overrunning reconcile cannot mutate an already-returned result; the rejection handler is attached eagerly, so there is no unhandled-rejection window either.

Measured on the same harness

fix

one stdio MCP server configured BEFORE PR 8068 as-is PR + fix
answers initialize immediately 200 in 1.0 s 200 in 1.0 s 200 in 1.0 s
initialize takes 6 s 200 in 1.0 s 200 in 7.2 s 200 in 6.0 s
never answers initialize 200 in 1.0 s 500 in 33.1 s, worktree deleted 200 in 6.1 s

Relocation overhead is now capped at the budget regardless of how the MCP server behaves. Re-running the full two-session E2E on the patched build shows the isolation fix is untouched:

  • direct shell cwd A / B → <ws>/.qwen/worktrees/e2e-a | <ws>/.qwen/worktrees/e2e-b
  • stdio MCP spawn cwds → one process per worktree, none in the base checkout
  • base checkout → HEAD unmoved, no session files (git status: ?? .qwen/)
  • TUI /cd with a wedged MCP server → completes between 3 s and 10 s (was ~60 s)

packages/core suites unchanged and green (config.test.ts, config.safe-mode.test.ts, mcp-client.test.ts, mcp-client-manager.test.ts725 passed); tsc reports nothing new for config.ts; eslint clean.

5 s is a starting point, not a considered constant — pick whatever you prefer as long as it is comfortably below the 30 s changeSessionCwd timeout. Dropping waitForMcpReady() here is also defensible on its own (it waits for discovery in the directory being left), but on its own it does not fix the daemon path: worktree sessions pass skipMcpDiscovery, so that call already returns instantly there and the 33 s came entirely from refreshMcpServers(). The reconcile itself is what needs the bound.

Take it, adapt it, or fix it differently — with the relocation no longer able to lose the 30 s race, I'm happy to approve.

中文版

补充:针对阻塞问题的已验证修复

上一条评论之后有两点更新:

  1. 该问题在合并 main 之后依然存在。 我在 23f08bcb8f 上重新确认:packages/core/src/tools/mcp-client.tsmcp-client-manager.tscdCommand.ts 与我验证过的版本逐字节一致;bridge.ts / acpAgent.ts / config.ts 的差异全部来自 merge——relocateWorkingDirectory()config.ts:4645 处仍然内联着 await this.waitForMcpReady(); await this.refreshMcpServers();。本 PR 自身的改动点全部完好。
  2. 我构建并实际运行了一个候选修复,所以下面的建议是实测结果,而非空口推断。

修复方案

不是删掉 reconcile,而是给它加上界。对于在预算内完成的 reconcile,mcpRefreshError 的语义完全保持不变——这正是本 PR 新增的两个 relocateWorkingDirectory 测试所覆盖的场景,它们无需修改即可继续通过。

补丁见上方英文部分(单文件,+42/−3)。mcpRefreshErrorreturn 时读取,所以超时后才完成的 reconcile 不会篡改已返回的结果;拒绝处理器是提前挂上的,因此也不存在 unhandled rejection 窗口。

在同一套 harness 上的实测

配置一个 stdio MCP server BEFORE 当前 PR 8068 PR + 修复
立即响应 initialize 200,1.0 秒 200,1.0 秒 200,1.0 秒
initialize 耗时 6 秒 200,1.0 秒 200,7.2 秒 200,6.0 秒
从不响应 initialize 200,1.0 秒 500,33.1 秒,worktree 被删除 200,6.1 秒

无论 MCP server 表现如何,relocation 的额外开销现在都被限制在预算之内。在打了补丁的构建上重跑完整的双 session E2E,隔离修复毫发无损:

  • direct shell cwd A / B → <ws>/.qwen/worktrees/e2e-a | <ws>/.qwen/worktrees/e2e-b
  • stdio MCP 启动 cwd → 每个 worktree 一个进程,主 checkout 中没有任何进程
  • 主 checkout → HEAD 未移动,无 session 文件(git status?? .qwen/
  • TUI /cd 配合卡死的 MCP server → 3~10 秒内完成(此前约 60 秒)

packages/core 相关套件未改动且全绿(config.test.tsconfig.safe-mode.test.tsmcp-client.test.tsmcp-client-manager.test.ts——725 passed);tscconfig.ts 没有新增报错;eslint 通过。

5 秒只是一个起点,并非精心论证过的常量——只要明显小于 30 秒的 changeSessionCwd 超时,取值可以由你决定。单独去掉这里的 waitForMcpReady() 本身也说得通(它等待的是即将离开的目录上的 discovery),但仅此一项并不能修复 daemon 路径:worktree session 会传 skipMcpDiscovery,所以那次调用在该路径上本来就立即返回,33 秒完全来自 refreshMcpServers()。真正需要加上界的是 reconcile 本身。

可以直接采用、按需调整,或换一种方式修复——只要 relocation 不会再输掉那个 30 秒竞争,我这边就可以 approve。

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Jul 30, 2026
Merged via the queue into main with commit a1c33de Jul 30, 2026
52 of 53 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.2.

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants