Skip to content

fix(desktop): enable microphone access on macOS - #8715

Merged
yiliang114 merged 7 commits into
mainfrom
codex/8092-macos-validation
Aug 9, 2026
Merged

fix(desktop): enable microphone access on macOS#8715
yiliang114 merged 7 commits into
mainfrom
codex/8092-macos-validation

Conversation

@yiliang114

Copy link
Copy Markdown
Collaborator

What this PR does

This completes the macOS permission chain for Desktop voice dictation. Packaged apps now include the user-facing microphone usage description and the Hardened Runtime audio-input entitlement, and release CI verifies both values on the final app bundle.

Why it's needed

Desktop v0.1.0 shipped without a microphone usage description. The signed app also lacked the audio-input entitlement required by the macOS Hardened Runtime, so WKWebView microphone capture could not complete the native permission flow reliably.

Reviewer Test Plan

How to verify

Build the macOS app, sign it with the configured entitlement set, and inspect the final bundle. The app metadata should contain a microphone usage description, the signature should contain com.apple.security.device.audio-input = true, and the existing packaged-app smoke should still start the bundled runtime successfully.

Evidence (Before & After)

Before: the official Desktop v0.1.0 arm64 bundle has no NSMicrophoneUsageDescription, and its signed executable has no audio-input entitlement.

After: a locally rebuilt bundle contains the expected usage description; after local Hardened Runtime signing, strict signature verification passes and the extracted audio-input entitlement is true.

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

Environment (optional)

macOS arm64. Verified the official v0.1.0 DMG, Desktop Rust tests (23 passed), release helper tests, a debug app bundle, local ad-hoc Hardened Runtime signing, plist validation, Prettier, actionlint, and the repository build/typecheck plus focused SSE, WebSocket, and voice tests.

Risk & Scope

  • Main risk or tradeoff: macOS will now present the native microphone permission prompt when voice dictation first requests capture.
  • Not validated / out of scope: a production-certificate permission prompt and real system sleep/wake were not exercised locally; release CI still performs the production signing check. SPA deep-link behavior in v0.1.0 is already fixed on main by fix(web-shell): allow session refresh with daemon auth #8445.
  • Breaking changes / migration notes: None.

Linked Issues

Part of #8092.

中文说明

这个 PR 做了什么

这个 PR 补全 Desktop 语音听写在 macOS 上的权限链路。打包后的应用现在会包含面向用户的麦克风用途说明和 Hardened Runtime 音频输入 entitlement,发布 CI 也会在最终 App 产物上验证这两个值。

为什么需要它

Desktop v0.1.0 发布包缺少麦克风用途说明,已签名应用也缺少 macOS Hardened Runtime 所要求的音频输入 entitlement,因此 WKWebView 的麦克风采集无法可靠完成系统权限流程。

Reviewer 测试计划

如何验证

构建 macOS App,使用配置的 entitlement 完成签名,然后检查最终 bundle。应用元数据应包含麦克风用途说明,签名应包含 com.apple.security.device.audio-input = true,现有打包 App smoke 仍应能正常启动内置 runtime。

证据(修复前 / 修复后)

修复前:官方 Desktop v0.1.0 arm64 bundle 没有 NSMicrophoneUsageDescription,已签名可执行文件也没有音频输入 entitlement。

修复后:本地重新构建的 bundle 包含预期用途说明;完成本地 Hardened Runtime 签名后,严格签名校验通过,提取出的音频输入 entitlement 为 true

已测试平台

OS 状态
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

环境(可选)

macOS arm64。已验证官方 v0.1.0 DMG、Desktop Rust 测试(23 项通过)、发布辅助测试、debug App bundle、本地 ad-hoc Hardened Runtime 签名、plist 校验、Prettier、actionlint,以及仓库 build/typecheck 和 SSE、WebSocket、语音相关定向测试。

风险与范围

  • 主要风险或权衡:语音听写首次请求采集时,macOS 现在会展示原生麦克风权限弹窗。
  • 未验证 / 范围外:本地未使用生产证书验证权限弹窗,也未执行真实系统休眠/唤醒;发布 CI 仍会执行生产签名检查。v0.1.0 的 SPA 深链问题已由 main 上的 fix(web-shell): allow session refresh with daemon auth #8445 修复。
  • 破坏性变更 / 迁移说明:无。

关联 Issue

#8092 的一部分。

@yiliang114

Copy link
Copy Markdown
Collaborator Author

macOS Desktop validation report

Tested the official Desktop v0.1.0 arm64 DMG in an isolated home/workspace and the locally rebuilt fixed bundle.

  • PASS: release checksum, strict code signature, Gatekeeper assessment, notarization staple, LaunchServices startup, workspace picker, Web Shell/settings load, ACP SSE and WebSocket initialization/10-second connections, daemon crash/retry recovery, graceful shutdown, and updater feed integrity.
  • REPRODUCED: v0.1.0 has no NSMicrophoneUsageDescription; its signed executable also lacks com.apple.security.device.audio-input.
  • FIX VERIFIED LOCALLY: the rebuilt bundle contains the usage description; after Hardened Runtime signing, strict verification passes and the extracted audio-input entitlement is true.
  • ALREADY FIXED ON MAIN: v0.1.0 session deep links return 401; fix(web-shell): allow session refresh with daemon auth #8445 addresses this, so this PR does not duplicate it.
  • NOT EXERCISED: a production-certificate microphone prompt, real system sleep/wake, authenticated prompt/edit/clipboard/external-link paths, and an actual updater install.

Automated checks also passed: Desktop Rust tests (23/23), release helper tests, debug app bundle, plist validation, Prettier, actionlint, repository build/typecheck, and focused SSE, WebSocket, and voice tests.

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

🚫 Qwen Triage was cancelledview run. The run was cancelled before finishing. Check for a newer run before re-running.

🚫 Qwen Triage 已取消 —— 查看运行。运行未完成即被取消。重跑前请先确认是否有更新的运行。

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed, not theoretical — the shipped Desktop v0.1.0 DMG was inspected and lacks both NSMicrophoneUsageDescription and the Hardened Runtime audio-input entitlement, which is why WKWebView microphone capture cannot complete the macOS permission flow. The repo's own live-host.yml packaging checks already expect the same values, so this also aligns the Tauri shell with an existing requirement.

Direction: aligned — completes the permission chain for the already-shipped Desktop voice dictation feature (part of #8092). No new surface, nothing speculative.

Size: not applicable — 90 changed lines (86 added) across one release workflow, one release-test script, and three plist files; no core paths touched.

Approach: scope still feels right after the two follow-up commits. Since the first pass, the PR gained a helper-entitlement narrowing (ripgrep now signs without app entitlements; the bundled Node runtime keeps only allow-jit via a new minimal plist) and test pins for every new gate. Both are on-mission hardening of exactly this change, not scope creep. The release-workflow edits remain verification-only plus entitlement scoping; what gets released is unchanged.

Risk: no elevated risk signals (no high-risk path matches).

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到,不是理论问题——已发布的 Desktop v0.1.0 DMG 经检查缺少 NSMicrophoneUsageDescription 和 Hardened Runtime 音频输入 entitlement,因此 WKWebView 麦克风采集无法完成 macOS 权限流程。仓库自己的 live-host.yml 打包检查本来就要求同样的值,这个 PR 也让 Tauri shell 与既有要求对齐。

方向:对齐——补全已上线的 Desktop 语音听写功能的权限链路(#8092 的一部分)。没有新增面,也没有投机性内容。

规模:不适用——共 90 行改动(86 行新增),涉及一个发布 workflow、一个发布测试脚本和三个 plist 文件;不涉及核心路径。

方案:两个后续 commit 之后范围依然合理。首轮审查后,PR 新增了 helper entitlement 收窄(ripgrep 签名不再携带应用 entitlement,内置 Node runtime 通过新的最小 plist 仅保留 allow-jit)以及针对每个新闸门的测试钉住。两者都是对本改动的加固,不是范围蔓延。发布 workflow 改动仍然只是验证与 entitlement 范围调整,不改变发布内容本身。

风险:无升级风险信号(未命中高风险路径)。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

My independent take before reading the diff: a packaged Tauri app needs (1) the usage-description key merged into the bundle Info.plist, (2) the audio-input entitlement in the file the signer already consumes, and (3) something that stops v0.1.0's silent regression from recurring. The PR does exactly these three things, and nothing else.

What I verified against upstream Tauri sources (tauri-cli-v2.8.4, matching this repo's @tauri-apps/cli ^2.8.5):

  • The new src-tauri/Info.plist is picked up automatically — tauri-cli sets the bundler's info_plist_path to tauri_dir()/Info.plist when it exists, and tauri-bundler merges its keys into the generated Contents/Info.plist per-key. So NSMicrophoneUsageDescription lands in the final bundle with no config change needed.
  • The entitlement reaches the main binary: tauri.conf.json already points Tauri's signing at Entitlements.plist with hardenedRuntime: true, so adding com.apple.security.device.audio-input there is sufficient. One side note: the vendor-binary signing step (node, ripgrep) uses the same file, so those binaries gain the entitlement too — consistent with how every other entitlement in that file is already handled, harmless.
  • Both new release assertions fail closed under set -euo pipefail: the smoke-step check errors if the usage-description key is missing, and the signature check tests the extracted entitlement equals true. The entitlement check runs on signed (non-dry-run) releases only; the usage-description check covers dry runs too.
  • test-release.js pins desktop-release.yml content and step ordering — the added lines don't disturb any pinned substring.

No correctness, security, or convention issues found.

Not verified: actual macOS bundling and signing — this review runs on Linux and doesn't execute PR code. The guard for that gap is the release-time assertion this PR itself adds. Neither @qwen-code /verify nor @qwen-code /tmux could settle it either — both run Linux sandboxes that cannot build or sign a macOS Tauri bundle — so the first real release run is the moment of truth, by design failing closed if either value is absent.

CI evidence

The PR's own CI on the reviewed commit, fetched via API (nothing re-run here). The two Desktop Shell jobs are the substantive ones: they run cargo test plus test-release.js, and both are green. The ubuntu Test job — which carries actionlint/yamllint over the edited workflow — is still in flight. Separately, a push-triggered "Qwen Pull Request Review" run shows failed before starting any job; that workflow is not part of PR CI and the same failure pattern appears across many unrelated branches — pre-existing infra noise, not caused by this PR.

Final CI results for e94c50c (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Classify PR ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Post Coverage Comment (ubuntu-latest, 22.x) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

中文说明

代码审查

读 diff 之前我的独立思路:打包后的 Tauri 应用需要 (1) 把用途说明 key 合并进 bundle 的 Info.plist,(2) 在签名器已在使用的 entitlement 文件里加上音频输入权限,(3) 有机制防止 v0.1.0 这种静默回归再次发生。这个 PR 正好做了这三件事,没有多余内容。

对照上游 Tauri 源码(tauri-cli-v2.8.4,与本仓库 @tauri-apps/cli ^2.8.5 对应)验证:

  • 新增的 src-tauri/Info.plist 会被自动识别——tauri-cli 在文件存在时把 bundler 的 info_plist_path 指向 tauri_dir()/Info.plist,tauri-bundler 会把其中的 key 逐个合并进生成的 Contents/Info.plist。因此 NSMicrophoneUsageDescription 无需改配置就能进入最终 bundle。
  • entitlement 会到达主二进制:tauri.conf.json 已把 Tauri 签名指向 Entitlements.plisthardenedRuntime: true,在里面加 com.apple.security.device.audio-input 即可。附带说明:vendor 二进制(node、ripgrep)签名步骤用的是同一个文件,所以它们也会带上这个 entitlement——与该文件中其他 entitlement 的既有处理方式一致,无副作用。
  • 两个新增的发布断言在 set -euo pipefail 下都是 fail closed:smoke 步骤在缺少用途说明 key 时报错,签名检查断言提取出的 entitlement 等于 true。entitlement 检查只在正式签名(非 dry-run)发布时运行;用途说明检查在 dry-run 也生效。
  • test-release.js 固定了 desktop-release.yml 的内容片段和步骤顺序——新增行不影响任何被固定的断言。

未发现正确性、安全性或规范问题。

未验证:真实的 macOS 打包与签名——本审查运行在 Linux 上,且不执行 PR 代码。这个缺口的守卫正是 PR 自己新增的发布期断言。@qwen-code /verify@qwen-code /tmux 也无法验证——两者都是 Linux 沙箱,无法构建或签名 macOS Tauri bundle——因此首次真实发布才是最终验证点,且设计上缺任何一个值都会直接阻断发布。

CI 证据

以上是通过 API 获取的该 commit 自身 CI 结果(未重跑任何东西)。两个 Desktop Shell 任务是实质性的:运行 cargo testtest-release.js,均已通过。ubuntu Test 任务(包含对改动 workflow 的 actionlint/yamllint)仍在运行。另外,一个 push 触发的 "Qwen Pull Request Review" run 在启动任何 job 前就失败;该 workflow 不属于 PR CI,且同样的失败模式出现在许多无关分支上——属于既有基础设施噪音,与本 PR 无关。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — small, focused, and the mechanism is independently verified against upstream Tauri sources; the one reservation is that the new release-workflow assertions are only linted in PR CI and will first execute at release time (fail closed by design).

Stepping back: this is exactly the kind of PR the gate should wave through. The problem is observed on a shipped artifact (the v0.1.0 DMG), the fix is the minimum viable set — two plist values plus assertions that make the regression class visible — and my independent proposal matches the diff one-for-one. No drive-by changes, no scope creep, no core paths. If I'm maintaining this in six months, the release-time checks are the part I'll be glad about: they turn "the signed app silently lacks an entitlement" from a user report into a failed release step.

The residual uncertainty is inherent to the change: macOS signing behavior can't be exercised in Linux CI, and the author's local ad-hoc signing results remain their claim rather than evidence I can re-run. That's acceptable here because the PR's own assertions close the loop at the first real release — loudly, not silently.

Verdict: approve. CI is still in flight on this commit (the ubuntu Test job), so approval is deferred until it lands green on e94c50c1661fce42b02c6e7f3ade4d787b51c177.

中文说明

置信度:4/5 —— 改动小而聚焦,机制已对照上游 Tauri 源码独立验证;唯一的保留是新增的发布流程断言在 PR CI 里只经过 lint,要到发布时才真正执行(设计上 fail closed)。

整体来看:这正是应该放行的 PR。问题来自已发布产物(v0.1.0 DMG)的实际观测,修复是最小可行集——两个 plist 值加上让这类回归可见的断言——diff 与我的独立方案完全一致。没有顺手改动,没有范围蔓延,不涉及核心路径。半年后维护这段代码时,最值得庆幸的会是发布期检查:它把"签名后的应用悄悄缺少某个 entitlement"从用户报告变成一次失败的发布步骤。

剩余的不确定性是这类改动固有的:Linux CI 无法执行 macOS 签名行为,作者本地 ad-hoc 签名的结果仍是其自述而非可复跑的证据。这里可以接受,因为 PR 自带的断言会在首次真实发布时闭环——而且是响亮地失败,不是静默通过。

结论:批准。该 commit 的 CI 仍在运行(ubuntu Test 任务),批准将延后到 CI 在该 commit 上全绿时执行。

Qwen Code · qwen3.8-max

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

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

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

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

@qwen-code-ci-bot qwen-code-ci-bot 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 — CI landed green after the review. ✅

@yiliang114

Copy link
Copy Markdown
Collaborator Author

macOS packaged-app verification

Verified the current head 97e0e30ae091415928bd7868970947589afd3f4e against a freshly prepared arm64 release app bundle on macOS. This is a partial E2E pass: the packaged metadata, signature boundary, daemon, and WKWebView are verified; the native microphone consent prompt is not.

Result

  • Pass: the packaged Info.plist contains NSMicrophoneUsageDescription with the expected voice-dictation explanation.
  • Pass: codesign --verify --deep --strict succeeds on the locally ad-hoc-signed app bundle.
  • Pass: the main app carries com.apple.security.device.audio-input together with its existing network/JIT entitlements.
  • Pass: bundled Node carries only com.apple.security.cs.allow-jit; it does not inherit microphone access.
  • Pass: both Darwin ripgrep binaries are signed without app entitlements.
  • Pass: smoke:packaged started the real packaged executable and reached Packaged desktop runtime ready.
  • Pass: the native app, bundled daemon, and WKWebView started; the loaded Web Shell completed real capabilities, settings, voice, and session requests successfully.

The local artifact used ad-hoc signing to reproduce the workflow's entitlement separation. Developer ID signing, notarization, and updater archive signing require release secrets and were not claimed here.

Remaining manual gate

I could not honestly mark the microphone permission flow itself as passed. The 0.0.1 source build is intercepted by the published 0.1.0 updater native modal before the voice button can be exercised, and macOS denied automated modal interaction because this terminal does not have Accessibility control. One bounded fallback did not suppress the updater.

So this verifies that the required usage string and entitlement are present in the real packaged app and that the app runs, but a human still needs to dismiss the updater and confirm the first microphone request produces the macOS consent prompt and usable capture. No microphone/TCC screenshot is attached because that state was not reached.

@yiliang114

yiliang114 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up: packaged WKWebView microphone E2E pass

The remaining native capture gate is now exercised against a fresh local 0.1.0 release app built from current head 97e0e30.

To expose the existing voice control in an isolated test home, I configured qwen3-asr-flash with a deliberately invalid test-only credential. Clicking the microphone reached the recording state, and the packaged daemon logged the full local path: Voice WebSocket accepted → start received → PCM audio received → stop received → upstream transcription failed. The batch transcriber is only invoked when at least one PCM chunk has arrived, so the final provider error confirms that WKWebView getUserMedia succeeded and microphone audio crossed into the bundled daemon.

The visible Voice transcription failed result below is therefore expected from the invalid test credential; it is not a microphone permission failure.

Packaged Desktop voice capture reaching the expected test-provider failure

I then switched the isolated configuration to an authorized qwen3-asr-flash credential. A direct request through the packaged daemon's /workspace/voice/transcribe route returned HTTP 200, confirming that the selected credential and ASR model were usable. The first two credentials returned 403 Model.AccessDenied, which explains the UI error above.

Finally, I exercised one uninterrupted packaged-app path: the existing Voice button started WKWebView microphone capture, system speech played through the Mac speakers, the bundled daemon received PCM and finalized the real ASR request successfully, and the transcript was inserted into the prompt composer. Because macOS denied external click automation without Accessibility permission, the start/stop clicks were triggered by a one-shot test-only script injected into a copied app bundle under /private/tmp; no source or PR file was changed.

Packaged Desktop voice dictation inserting the real ASR transcript

Both screenshots contain only the Qwen Code Desktop window (the first is a tighter crop of the composer); no full-screen capture was uploaded. This closes the local WKWebView microphone → bundled daemon → real ASR → composer-insert path. It does not claim Developer ID signing or a newly displayed TCC consent prompt; macOS reused the existing authorization for this local app identity.

@yiliang114

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

Scripted assertions: 79 passed · 0 failed · 79 total

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

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

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

Verification report

Verification report — PR #8715 fix(desktop): enable microphone access on macOS

Verdict: merge-ready — 79/79 scripted assertions passed (0 unexpected failures) at verified head 97e0e30ae091415928bd7868970947589afd3f4e (merge-ref HEAD^2; base d91c66119b). Round 1 (no previous report).

中文摘要
  • 结论: merge-ready。79/79 脚本化断言通过,0 个非预期失败。
  • A/B 结论: 核心链路成立。src-tauri/Info.plist 会被 tauri-cli(与 package-lock 钉住的 @tauri-apps/cli@2.11.4 同 tag 的源码 interface/rust.rs 证实:macOS 宿主上自动合并 tauri_dir/Info.plist)并入打包 bundle 的 Contents/Info.plistaudio-inputtauri.conf.jsonbundle.macOS.entitlementssign.rs 流入主 app 签名。新增的两个发布 CI 闸门在 stub 重放中对 v0.1.0 形状的 bundle 变红、对 head 形状变绿,base 闸门对同一 fixture 保持盲视(A/B 对照成立)。helper entitlement 收窄(rg 不再继承 app entitlements,node 仅保留 allow-jit)在签名步骤重放中逐参数确认,且 node 在 hardened runtime 下被强制的 entitlement 集合与 base 相同(仅 allow-jit),无行为回归。
  • Findings: 均为非阻塞。(1) codesign -d --entitlements - --xml--xml 标志无法在 Linux 容器验证,仓库内已验证的先例是 live-host.yml:- 形式;所有失败模式均 fail-closed(set -euo pipefail),不会静默放行。(2) test-release.js 钉住了签名步骤的改动,但没有钉住两个新增验证闸门——属覆盖缺口,不是合并条件。
  • 未覆盖: 真实 macOS 行为(TCC 弹窗、WKWebView 采集、codesign/spctl/PlistBuddy 真实语义、--xml 标志);yamllint(容器无 pip);逐 commit 归因(shallow depth-2,验证的是聚合 diff);stub 重放未经真实发布产物校准。

Central claim and A/B

Central claim: the packaged macOS Tauri app now carries NSMicrophoneUsageDescription and a signed com.apple.security.device.audio-input = true, and release CI fails if either regresses. Secondary: helper binaries lose the app's entitlements (ripgrep: none; node: minimal NodeEntitlements.plist).

Wiring (static proof, authoritative source): the pinned CLI is @tauri-apps/cli@2.11.4 (packages/desktop-shell/package-lock.json). At the matching tag tauri-cli-v2.11.4:

  • crates/tauri-cli/src/interface/rust.rs:1648-1661 — on a macOS host, the CLI merges tauri_dir/Info.plist (i.e. src-tauri/Info.plist, the new file) into the bundler's info_plist even without an explicit bundle.macOS.infoPlist setting; #[cfg(not(target_os = "macos"))] leaves Linux/Windows builds untouched.
  • crates/tauri-bundler/src/bundle/macos/app.rs:354 — the merged user plist overrides generated defaults and is written to Contents/Info.plist.
  • crates/tauri-bundler/src/bundle/macos/sign.rs:54-67bundle.macOS.entitlements ("Entitlements.plist", pre-existing config, unchanged by the PR) is passed to codesign for the app, so the new audio-input key flows into the signature.
  • crates/tauri-cli/src/helpers/plist.rsmerge_plist is a plain dict merge; no collision possible for the single new key.

A/B table (harnesses 01-test-release-ab.mjs, 02-workflow-replay.mjs; witness: 01-ab-test-release-head-vs-base.png, 02-workflow-replay-sign-verify-smoke.png):

cell oracle base head
test-release.js on own tree exit code green green
head test-release.js on base tree expected red red, ripgrep must not inherit the app entitlements
base test-release.js on head tree expected red red, old rg assertion
sign step, rg fixture recorded codesign args --entitlements src-tauri/Entitlements.plist no --entitlements, still --options runtime --timestamp
sign step, node fixture recorded codesign args full Entitlements.plist NodeEntitlements.plist
verify step on no-audio-input bundle (v0.1.0 shape) step exit 0 (blind) non-zero
verify step on audio-input=true bundle step exit 0
verify step on audio-input=false / empty dump step exit non-zero (fail-closed)
smoke step on Info.plist without mic key step exit, npm call 0, smoke ran (blind) non-zero, smoke not called
smoke step on Info.plist with mic key step exit, npm call 0, smoke:packaged -- <exe> recorded

Mutation matrix on the new test-release.js assertions (M1 rg-entitlements reverted, M2 node-entitlements reverted, M3 audio-input added to NodeEntitlements.plist, M4 rg warning removed): all four killed by their named assertion message; unmutated controls green on both arms.

Plist content deltas head vs base (parse + key/value assertions, 03-plist-validation.mjs, witness 03-plist-validation-head-vs-base.png): 20/20 — head Entitlements.plist = exactly {allow-jit, audio-input, network.client, network.server}; base lacks audio-input; NodeEntitlements.plist = exactly {allow-jit}, no mic/network keys; Info.plist = exactly one non-empty NSMicrophoneUsageDescription string, wording identical to the Electron app's (packages/desktop/apps/electron/electron-builder.yml); tauri.conf.json macOS bundle config byte-identical to base (the PR routes everything through the pre-existing entitlements key).

Repo gates on the changed surfaces (04-gates.mjs, witness 04-lint-gates-with-live-controls.png): 13/13 — actionlint 1.7.12 (repo flags) clean on head and base workflows, shellcheck clean on all six extracted step blocks (-s bash), prettier and eslint clean on the changed JS; every linter's live plant control caught its violation.

Helper-narrowing blast radius: runtime.rs spawns node with only QWEN_CODE_DESKTOP/QWEN_SERVER_TOKEN env; no DYLD* anywhere in desktop-shell. The only Hardened-Runtime-enforced entitlement node had on base was allow-jit (network.* are App-Sandbox entitlements, unenforced without com.apple.security.app-sandbox, which the app does not declare), and NodeEntitlements.plist keeps exactly allow-jit — the enforced surface is unchanged. Ripgrep is a plain Rust binary; losing allow-jit/network.* removes nothing it uses.

Reviewer Test Plan walkthrough:

plan step result here
Build macOS app, sign, inspect bundle not executable on Linux; reproduced structurally: bundler source proves the merge, stub replay proves the gates
Metadata contains mic usage description verified at config/source level (wiring above) + plist parse (03-plist-validation.mjs); not against a built bundle
Signature contains audio-input = true verified at config/source level + replay of the new verify gate on fixture bundles
Existing packaged-app smoke still starts smoke step logic replayed; new plist check runs before smoke and fails closed; the runtime-start half is unchanged by this PR and runs in the lane's macOS CI

Findings (non-blocking)

F1 (nit). Verify macOS signature uses codesign -d --entitlements - --xml, while the repo's proven production pattern is codesign -d --entitlements :- (.github/workflows/live-host.yml:146). The --xml flag's existence could not be verified from this Linux container (codesign is not in Apple's open-source SecurityTool repo; no macOS available). Bounded: every failure mode is fail-closed — an unrecognized flag aborts the step under set -euo pipefail, a missing key yields test "" = true → red, and PlistBuddy parses both XML and binary plists so a format mismatch cannot silently pass. Worst case is a loud failure on the first signed release run, not a silent false green.

Suggested fix (unmeasured here — macOS-only tool)
-          codesign -d --entitlements - --xml "$app" > "$entitlements" 2>/dev/null
+          codesign -d --entitlements :- "$app" > "$entitlements" 2>/dev/null

(matches the live-host precedent; cannot be executed in this environment)

F2 (coverage gap, completeness report). test-release.js pins the signing-step changes (rg/node entitlements, ordering, warnings) but nothing pins the two new verification gates (Print :com.apple.security.device.audio-input in Verify macOS signature, Print :NSMicrophoneUsageDescription in the macOS smoke step): deleting those lines keeps the suite green (observation assertions in harness 01). The gates themselves are exercised by this round's replay; a future workflow edit could drop them without a red test. Not a merge condition.

Not covered

  • Real macOS behavior: TCC prompt, WKWebView mic capture, actual codesign/spctl/PlistBuddy semantics, and the --xml flag question (F1). The container has no macOS toolchain; the replay substitutes stubs for those four tools (documented below), so it reproduces the gate logic, not the Apple-tool trigger path. Production-certificate signing was also not exercised by the author.
  • yamllint (repo gate) not run: the container has no pip/ensurepip/venv. YAML parse validity is established instead by actionlint (which parses the full document) and the js-yaml extraction.
  • Per-commit attribution: checkout is depth-2 (only merge, base tip, PR head reachable); the three commits in the metadata were verified as the aggregate HEAD^1..HEAD diff only.
  • The stub replay is uncalibrated: round 1 has no real release-run artifact to byte-compare against (the steps run only on macOS release runners). Calibration would be the log of the next real desktop-release run.
  • Full npm test -w-style gates for desktop-shell were not run (the package has no vitest suite; its release helper suite is test-release.js, which is the A/B subject above). Rust cargo test not run (no Rust toolchain in container; the PR touches no Rust code).

Methodology

Environment: CI verify container (node:22-bookworm), merge-ref checkout (HEAD merge, HEAD^1 base d91c66119b, HEAD^2 head 97e0e30ae0), npm ci+npm run build pre-run at head. Harnesses live in this artifact dir (01..04-*.mjs) and drive the real repo files: 01 runs the real test-release.js in symlinked scratch trees (head/base × head/base + four mutations); 02 extracts the three changed run: blocks verbatim via js-yaml (only substitutions: ${{ matrix.rust_target }}aarch64-apple-darwin, and /usr/libexec/PlistBuddy → PATH stub because the container user cannot write /usr/libexec; the stub reimplements Print :key exit/print semantics via python3 plistlib), then executes them under bash --noprofile --norc with stub codesign/spctl/npm against fixture bundles, asserting on recorded call logs and exit codes; 03 parses all three plists with plistlib and asserts key/value deltas head vs base; 04 runs the repo-pinned gates (actionlint 1.7.12 with scripts/lint.js flags, shellcheck, prettier, eslint), each with a planted-violation live control. Tauri wiring was proven from tauri-apps/tauri source at tag tauri-cli-v2.11.4 (exact pinned CLI version). Raw logs in logs/; captures 01-04*.png are the harness runs as printed.

Evidence images

01-ab-test-release-head-vs-base

02-workflow-replay-sign-verify-smoke

03-plist-validation-head-vs-base

04-lint-gates-with-live-controls

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

Qwen Code · sandboxed verification

@yiliang114

Copy link
Copy Markdown
Collaborator Author

Follow-up: second packaged-app voice pass

Repeated the packaged WKWebView voice flow with the same one-shot test-only start/stop hook described above. The audio fixture was played only after the bundled daemon logged voice websocket start received; the session then received stop, finalized successfully, and inserted It's kind of like that. into the prompt composer.

Second packaged Desktop voice transcription pass

This was captured by macOS window ID, so the image contains only the Qwen Code Desktop window and no desktop or other application content.

@yiliang114
yiliang114 enabled auto-merge August 8, 2026 16:39

@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: reverse audit — stopped before round 3 by the review time budget. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。 建议见行内评论。 未审查:反向审计——评审时间预算不足,未能开始第 3 轮。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

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

Comment thread packages/desktop-shell/scripts/test-release.js
Comment thread packages/desktop-shell/scripts/test-release.js
doudouOUC
doudouOUC previously approved these changes Aug 9, 2026

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

Approving — reviewed at 00eabce419. The change is correct and well-shaped; two things below need saying, one of which I confirmed with my own probe.

The shape is right

Getting mic access under the hardened runtime needs three things, and all three are here: the com.apple.security.device.audio-input entitlement on the app, an NSMicrophoneUsageDescription string (without which macOS denies the request outright), and — the part that is easy to miss — not handing that entitlement to the helper binaries.

The entitlement split is the best part of this PR. Previously the vendored rg and the Node runtime were both signed with the app's full Entitlements.plist; after this change ripgrep is signed with no entitlements at all (correct — a Rust search binary needs none) and Node gets a minimal NodeEntitlements.plist carrying only allow-jit. That means adding microphone to the app does not silently grant microphone to two extra executables.

I checked the one thing that could have made the Node narrowing a regression: Entitlements.plist has no com.apple.security.app-sandbox key, so the network.client / network.server entries in it are App Sandbox entitlements and inert here. Dropping them from the Node sidecar therefore costs it nothing — Node keeps the allow-jit it actually needs for V8.

Adding release-time assertions for both halves (dumping the signed app's entitlements and requiring audio-input, and requiring NSMicrophoneUsageDescription in the bundled Info.plist) is the right compensating control for a property that can only really be observed on a signed bundle.

R1-2 confirmed — the ripgrep guard pins the text, not the property

I reproduced this rather than relaying it. Re-adding --entitlements src-tauri/Entitlements.plist on its own continuation line between --sign "$APPLE_SIGNING_IDENTITY" and --options runtime — a perfectly valid codesign argument order — leaves all five of the PR's new assertions green:

PASS  ripgrep must not inherit app entitlements (exact old form absent)
PASS  ripgrep codesign continuation form present
PASS  Node uses NodeEntitlements.plist
PASS  Node must NOT receive microphone access
PASS  ripgrep-missing warning retained

while the vendored rg is once again signed with the full app entitlement set, microphone included. assert.doesNotMatch(/--entitlements src-tauri\/Entitlements\.plist \{\} \+/) only catches the flag immediately before {} +, and the release-time entitlement dump inspects the .app bundle, not ripgrep — so nothing downstream catches it either.

This is a guard weakness, not a live defect: the workflow as written today signs ripgrep correctly. Suggestion severity is right. But it is worth fixing while the context is fresh, because the whole point of the split is that the next edit cannot quietly undo it.

R1-1 is also fair — only the negative half is pinned

The new PR-time assertions cover "Node must not have microphone" but none of the positive invariants. I checked all four by hand and they hold today: Entitlements.plist keeps audio-input, NodeEntitlements.plist keeps allow-jit, Info.plist carries a non-empty usage description, and both release-time assertion lines are present in the workflow. None of them is guarded, so reverting the audio-input hunk or deleting Info.plist would leave the suite green.

Info.plist deserves a specific mention: its only wiring into the bundle is Tauri's filename auto-discovery — nothing in the repo references the file. That is a legitimate Tauri convention, but it means a rename, a relocation, or a Tauri behaviour change would produce a silently mic-less build, caught only at release time.

Coverage — this is the part I would not let slide

CI never ran on this head. Not "the relevant job was skipped" — there are zero workflow runs for 00eabce419, and the branch is in-repo, not a fork. All 51 check-runs on the commit are skipped bot workflows; there is no Test, no Desktop Shell, no Classify PR. So the Desktop Shell job that runs test-release.js — the very guard this PR extends — has not executed against this change.

I ran those assertions myself to fill the gap: 10/10 pass (the PR's five, plus the five unguarded positive invariants above). What I could not verify, and no one can at PR time: that Tauri actually merges src-tauri/Info.plist into the built bundle, and that the entitlement lands on the signed binary. Both require a real macOS signed build; the new release-time assertions are the right place for them, and they only fire on workflow_dispatch.

Please re-trigger CI on this head before merging so the desktop leg actually runs.

中文说明

批准 —— 审查提交 00eabce419。改动正确且形态得当;下面两点需要说明,其中一点我用自己的探针复现了。

形态是对的:在 hardened runtime 下拿到麦克风需要三件事,本 PR 三件齐备——应用侧 com.apple.security.device.audio-input 权限、NSMicrophoneUsageDescription 文案(缺失时 macOS 会直接拒绝请求),以及容易被忽略的一点:不要把该权限一并交给辅助二进制。

权限拆分是本 PR 最好的部分。此前随附的 rg 与 Node 运行时都用应用完整的 Entitlements.plist 签名;改动后 ripgrep 完全不带权限签名(正确——Rust 搜索程序不需要),Node 改用只含 allow-jit 的最小 NodeEntitlements.plist。这意味着给应用加麦克风权限,不会顺带把麦克风授予另外两个可执行文件。

我核对了唯一可能让 Node 收窄变成回归的点:Entitlements.plist没有 com.apple.security.app-sandbox,因此其中的 network.client/network.server 属 App Sandbox 权限、在此为惰性。把它们从 Node 侧移除不产生任何代价——Node 保留了 V8 真正需要的 allow-jit

为两侧都加发布期断言(导出已签名应用的权限并要求含 audio-input;要求打包后的 Info.plistNSMicrophoneUsageDescription)是对"只能在已签名 bundle 上观察到的属性"的正确补偿控制。

R1-2 已确认——ripgrep 的守卫钉的是文本而非属性:我复现而非转述。把 --entitlements src-tauri/Entitlements.plist 重新加在 --sign--options runtime 之间的独立续行上(codesign 完全合法的参数顺序),本 PR 新增的五条断言全部保持通过,而随附的 rg 又会以应用完整权限集(含麦克风)签名。assert.doesNotMatch(/--entitlements … \{\} \+/) 只能捕获紧邻 {} + 之前的那种写法,而发布期的权限导出只检查 .app bundle、不检查 ripgrep,因此下游也拦不住。

这是守卫弱点而非现行缺陷——今天的 workflow 对 ripgrep 的签名是正确的,Suggestion 的定级是恰当的。但趁上下文尚新修掉值得:拆分的全部意义就在于下一次改动不能悄悄把它撤销。

R1-1 也成立——只钉住了否定的一半:新增的 PR 期断言只覆盖"Node 不得有麦克风",四条正向不变式一条未钉。我逐条手工核对,今天都成立Entitlements.plist 保留 audio-inputNodeEntitlements.plist 保留 allow-jitInfo.plist 文案非空、两条发布期断言均在 workflow 中。由于都无守卫,撤掉 audio-input 那个 hunk 或删掉 Info.plist,套件依然全绿。

Info.plist 值得单独一提:它接入 bundle 的唯一途径是 Tauri 按文件名自动发现——仓库里没有任何地方引用该文件。这是 Tauri 的正当约定,但也意味着一次改名、移动位置或 Tauri 行为变更,都会产出一个静默没有麦克风的构建,且只有到发布期才会被发现。

覆盖率——这一点我不会放过CI 在本 head 上从未运行过。 不是"相关 job 被跳过",而是 00eabce419 的 workflow 运行数为,且该分支在本仓库内、并非 fork。该提交上 51 个 check-run 全是被跳过的机器人工作流;没有 Test、没有 Desktop Shell、没有 Classify PR。因此运行 test-release.jsDesktop Shell job——也就是本 PR 所扩展的那个守卫——并未对本次改动执行过。

我自己跑了这些断言来填补空缺:10/10 通过(本 PR 的五条,加上上述五条无守卫的正向不变式)。我无法验证、且任何人在 PR 期都无法验证的是:Tauri 是否真的把 src-tauri/Info.plist 合并进构建产物,以及该权限是否真的落在已签名二进制上。两者都需要真实的 macOS 签名构建;新增的发布期断言正是它们该待的地方,而那只在 workflow_dispatch 时触发。

合并前请在本 head 上重新触发 CI,让 desktop 腿真正跑一次。

@yiliang114

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

Scripted assertions: 78 passed · 0 failed · 78 total

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

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

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

Verification report

Verification report — PR #8715 fix(desktop): enable microphone access on macOS (round 2)

Verdict: merge-ready — 78/78 scripted assertions passed (0 unexpected failures) at verified head 00eabce4190f3c85420f27a0451e444f035b91db (merge-ref HEAD^2; base 3037744602e97070e0870d75c32604747d081fc3). Follow-up round — previous report: round 1, merge-ready, 79/79, at head 97e0e30ae0.

中文摘要
  • 结论: merge-ready。78/78 脚本化断言通过,0 个非预期失败。本轮为跟进轮(round 2)。
  • 与上一轮的差异: head 由 97e0e30 变为 00eabce(仅合并 main),base 由 d91c661 前移至 3037744fix(integration-tests): make the project typecheckable and fix what that found #8693,integration-tests typecheck 修复,不触及本 PR 闭包)。PR 的 5 个文件内容逐字节稳定:round 1 的全部含量断言在本轮重新脚本化复核通过(见下表及 harness 01–03)。
  • A/B 结论: 核心链路在新 head 上全部重测成立。test-release.js 四格 A/B(head/base 脚本 × head/base 树)交叉格均按预期红在目标断言上;签名步骤重放中 rg 不再携带 entitlements、node 改用 NodeEntitlements.plist;新增 verify 闸门对 v0.1.0 形状 bundle 变红、对 head 形状变绿(base 闸门对同一 fixture 盲视放行);smoke 闸门在缺少 NSMicrophoneUsageDescription 时于 npm run smoke:packaged 之前失败关闭。tauri-cli 接线在钉住的 @tauri-apps/cli@2.11.4 tag 源码上逐条重新核实(src-tauri/Info.plist 在 macOS 宿主无条件并入 Contents/Info.plistbundle.macOS.entitlements 随 hardened runtime 流入 codesign)。
  • 既往 findings 状态: F1(--xml 标志 nit)与 F2(两个新闸门无测试钉住,覆盖缺口)均 stands(详见状态表),非阻塞。
  • 未覆盖: 真实 macOS 行为(TCC 弹窗、WKWebView 采集、codesign/spctl/PlistBuddy 真实语义、--xml 标志);yamllint(容器无 pip);逐 commit 归因(depth-2 浅克隆);stub 重放未经真实发布产物校准。

Previous-finding status (round 1 → round 2)

# finding severity status at head 00eabce
F1 Verify macOS signature dumps entitlements with codesign -d --entitlements - --xml, while the repo's proven pattern is --entitlements :- (.github/workflows/live-host.yml:146) nit stands — re-grepped at the new head: workflow still uses --xml, precedent still :-. Failure modes remain fail-closed (set -euo pipefail: unknown flag aborts the step; missing key → test "" = true → red; PlistBuddy parses XML and binary plists). Worst case unchanged: a loud failure on the first signed release run, never a silent false green.
F2 nothing pins the two new workflow verification gates (Print :com.apple.security.device.audio-input in Verify macOS signature; Print :NSMicrophoneUsageDescription in the macOS smoke step) coverage gap stands — re-measured, not diffed: mutants M5a (verify gate deleted) and M5b (smoke gate deleted) both keep test-release.js green (exit=0 each) at the new head, while positive controls M1–M4 are each killed by their named assertion, so the suite is proven capable of going red. Completeness report, not a merge condition.

No round-1 measurement was carried forward on paper: every cell below was rebuilt and re-executed at head 00eabce / base 3037744. The Tauri wiring proof is the one static fact re-verified at its source (the pinned tag), after re-asserting its input closure locally — packages/desktop-shell/package-lock.json still pins @tauri-apps/cli@2.11.4 and the PR changes no dependency files (harness 03).

Delta since round 1

  • Head 97e0e3000eabce: the added commit is Merge branch 'main' into codex/8092-macos-validation. The effective diff HEAD^1..HEAD is the same 5 files / +49 / −4 as round 1, and all round-1 content claims (plist key sets, assertion texts, workflow hunks, wording) re-assert true byte-for-byte at the new head (harnesses 01–03) — the merge only re-based the PR, it changed none of its content. No conflict markers in any changed file (clean merge).
  • Base d91c6613037744: the new tip is fix(integration-tests): make the project typecheckable and fix what that found (#8693). It does not touch any file in this PR's closure; base-side continuity is established empirically — cell B (base script × base tree) is green, the base-arm workflow cells replay exactly the pre-PR shape, and base Entitlements.plist is precisely the pre-PR key set (harness 03).
  • Because HEAD is itself the clean merge of the PR into the current base tip, "verify the merge, not only the PR" holds by construction for this round.
  • Per-commit attribution: git rev-list HEAD^1..HEAD^2 returns 1 commit at this depth-2 shallow checkout while the metadata snapshot lists 4 — the shallow boundary is confirmed, so the aggregate diff is what was verified (see Not covered).

Central claim and A/B

Central claim: the packaged macOS Tauri app carries NSMicrophoneUsageDescription and a signed com.apple.security.device.audio-input = true, and release CI fails if either regresses. Secondary: helper binaries no longer inherit the app entitlements (ripgrep: none; node: minimal NodeEntitlements.plist).

Wiring (re-verified at tag tauri-cli-v2.11.4, the exact pinned CLI version):

  • crates/tauri-cli/src/interface/rust.rs (~1640–1670): on a macOS host the CLI builds MacOsSettings.info_plist from tauri_dir.join("Info.plist") when it exists (plus any explicit config.macos.info_plist), merged via merge_plist; #[cfg(not(target_os = "macos"))] info_plist: None leaves Linux/Windows builds untouched. The merge is unconditional on macOS hosts — no bundle.macOS.infoPlist config needed.
  • crates/tauri-bundler/src/bundle/macos/app.rs, create_info_plist(): after generating the default keys, settings.macos().info_plist overrides key-by-key and the result is written to Contents/Info.plist — so NSMicrophoneUsageDescription lands in the bundle.
  • crates/tauri-bundler/src/bundle/macos/sign.rs, sign(): settings.macos().entitlements (path form — tauri.conf.json uses the pre-existing "entitlements": "Entitlements.plist", byte-identical head vs base) is handed to the signer with is_an_executable && settings.macos().hardened_runtime — so the new audio-input key reaches the app's codesign under hardened runtime.

A/B table (harnesses 01-test-release-ab.mjs, 02-workflow-replay.mjs; witnesses: 01-test-release-ab-head-vs-base.png, 02-workflow-replay-sign-verify-smoke.png):

cell oracle base head
test-release.js on own tree exit code green green
head test-release.js on base tree expected red red, AssertionError: ripgrep must not inherit the app entitlements
base test-release.js on head tree expected red red, AssertionError: ripgrep codesign failures must fail the signing step
sign step, rg fixture (2 binaries, batched find -exec {} +) recorded codesign args 2 rg paths with --entitlements src-tauri/Entitlements.plist 2 rg paths, no --entitlements, --options runtime --timestamp kept
sign step, node fixture recorded codesign args full Entitlements.plist NodeEntitlements.plist
sign step, ripgrep dir missing exit, stdout 0, ::warning::Ripgrep vendor directory not found (fail-soft branch works)
verify step on v0.1.0-shape bundle (no audio-input) step exit 0 (blind) non-zero
verify step on head-shape bundle (audio-input=true) step exit, recorded args 0; codesign -d --entitlements - --xml recorded
verify step on audio-input=false / empty dump step exit non-zero / non-zero (fail-closed both)
smoke step on Info.plist without mic key exit, npm call 0, smoke:packaged called (blind) non-zero, smoke:packaged not reached
smoke step on Info.plist with mic key exit, npm call 0, smoke:packaged -- <found executable> recorded

Workflow blocks were extracted verbatim via js-yaml from head and base; a round-trip assertion proves the only substitutions are ${{ matrix.rust_target }}aarch64-apple-darwin and /usr/libexec/PlistBuddy → PATH stub (container user uid 1000 cannot create /usr/libexec). Blocks ran under bash --noprofile --norc with each step's own set -euo pipefail. Stub semantics were control-checked first: the PlistBuddy stub (python3 plistlib) reproduces value-print / missing-key-red / unparseable-red before any cell used it. Replay is still uncalibrated (see Not covered).

Mutation matrix on the head tree (scratch worktree at HEAD; unmutated control green first; witness 01-test-release-ab-head-vs-base.png):

mutant suite result classification
M1 rg --entitlements line restored killed — ripgrep must not inherit the app entitlements pinned
M2 node entitlements path reverted killed — Node.js must use its minimal helper entitlements pinned
M3 audio-input added to NodeEntitlements.plist killed — Node.js must not receive microphone access pinned
M4 rg-missing ::warning:: line removed killed — missing ripgrep binaries must be visible in release logs pinned
M5a verify gate (4 lines) deleted survives (green) coverage gap — F2
M5b smoke gate (2 lines) deleted survives (green) coverage gap — F2

Positive control: M1–M4 prove the harness turns the suite red; the M5 survivors are therefore real unpinned axes, not harness blindness.

Plist content deltas (harness 03-plist-validation.mjs, witness 03-plist-validation-head-vs-base.png): head Entitlements.plist = exactly {allow-jit, audio-input, network.client, network.server}, all true; base = same minus audio-input; NodeEntitlements.plist = exactly {allow-jit}; Info.plist = exactly one non-empty NSMicrophoneUsageDescription, wording byte-identical to the Electron app's (packages/desktop/apps/electron/electron-builder.yml); tauri.conf.json bundle.macOS byte-identical head vs base; PR touches exactly the 5 expected files and no package*.json.

Helper-narrowing blast radius (carried analysis, inputs re-checked): tauri.conf.json and the runtime spawn path are unchanged by the PR; the only Hardened-Runtime-enforced entitlement node had on base was allow-jit (network.* are App-Sandbox entitlements, unenforced without com.apple.security.app-sandbox, which the app does not declare), and NodeEntitlements.plist keeps exactly allow-jit — the enforced surface is unchanged. Ripgrep is a plain Rust binary; losing allow-jit/network.* removes nothing it uses.

Reviewer Test Plan walkthrough:

plan step result here
Build macOS app, sign, inspect bundle not executable on Linux; reproduced structurally: pinned-tag bundler source proves the merge (above), stub replay proves the gates
Metadata contains mic usage description config/source level + plist parse (harness 03); not against a built bundle
Signature contains audio-input = true config/source level + replay of the new verify gate on fixture bundles
Existing packaged-app smoke still starts smoke step logic replayed; the new plist check runs before smoke:packaged and fails closed; the runtime-start half is unchanged by this PR and runs in the lane's macOS CI

Gates (harness 04-gates.mjs, witness 04-lint-gates-with-live-controls.png)

  • actionlint 1.7.12 with the repo's exact flags: clean on head and base desktop-release.yml; live plant (broken expression) caught with the expected diagnostic.
  • shellcheck 0.11.0 -s bash: clean on all six extracted run blocks (sign block gets the step's env: APPLE_SIGNING_IDENTITY as scaffold); live plant (unused variable, SC2034) caught.
  • prettier --check clean on the changed files; live plant (misformatting) caught.
  • eslint clean on the changed JS; live plant (unused variable) caught.
  • yamllint: not installable (no pip in container) — see Not covered.

Findings (non-blocking, both carried from round 1)

F1 (nit, stands). Verify macOS signature uses codesign -d --entitlements - --xml "$app" while the repo's proven production pattern is codesign -d --entitlements :- (.github/workflows/live-host.yml:146). The --xml flag's existence still cannot be verified from this Linux container (no macOS toolchain; codesign is not in Apple's open-source releases). Bounded as before: every failure mode is fail-closed under the step's set -euo pipefail, so the worst case is a loud failure on the first signed release run, never a silent false green.

Suggested fix (unmeasured — macOS-only tool)
-          codesign -d --entitlements - --xml "$app" > "$entitlements" 2>/dev/null
+          codesign -d --entitlements :- "$app" > "$entitlements" 2>/dev/null

F2 (coverage gap, stands). Re-measured at the new head via M5a/M5b above: deleting either new verification gate keeps test-release.js green, so a future workflow edit could drop them without a red test. The gates themselves pass this round's replay; this is completeness reporting, not a merge condition.

No new findings this round.

Not covered

  • Real macOS behavior: TCC prompt, WKWebView mic capture, actual codesign/spctl/PlistBuddy semantics, and the --xml flag question (F1). The replay substitutes stubs for those tools (documented in Methodology), so it reproduces the gate logic, not the Apple-tool trigger path — the shape of the checks, not the cause side. Production-certificate signing was not exercised by the author either.
  • yamllint (repo gate): container has no pip/pip3 (pip3: Permission denied from the installer; python3 -m pip absent). YAML validity is established instead by actionlint's full-document parse and the js-yaml extraction.
  • Per-commit attribution: depth-2 checkout — git rev-list HEAD^1..HEAD^2 returns 1 commit while the snapshot lists 4 (e94c50c, 4d44ed5, 97e0e30, 00eabce), so 97e0e30 and earlier are unreachable; verified the aggregate HEAD^1..HEAD diff only.
  • The stub replay remains uncalibrated: no real desktop-release run artifact exists to byte-compare against (these steps run only on macOS release runners); calibration would be the log of the next real run. Round 1 said the same; nothing changed.
  • Rust cargo test not run (no Rust toolchain in container; the PR touches no Rust code). packages/desktop-shell has no vitest suite — its release-helper suite is test-release.js, which is the A/B subject itself.

Methodology

Environment: CI verify container (node:22-bookworm; node v22.23.2, python 3.11.2, uid 1000), merge-ref checkout (HEAD = merge 025a613, HEAD^1 = base 3037744, HEAD^2 = head 00eabce), npm ci + npm run build pre-run at head. Scratch trees: git worktree add tmp/base-tree-pr8715 HEAD^1 and git worktree add tmp/head-scratch-pr8715 HEAD (both removed after the A/B cells were captured; recreate with those commands to re-run harnesses 01–03). Harnesses live in this artifact dir and drive real repo files: 01 runs the real test-release.js across head/base trees (4 A/B cells + 6 mutants + controls); its dependency closure imports only node: builtins (grep-verified) and the base tree has no node_modules, so no cross-tree resolution is possible (realpath checks in the harness output). 02 extracts the three changed run: blocks verbatim via js-yaml (round-trip-asserted substitutions: matrix.rust_targetaarch64-apple-darwin, /usr/libexec/PlistBuddy → PATH stub reimplementing Print :key semantics via python3 plistlib) and executes them under bash --noprofile --norc with recording stubs for codesign/spctl/npm against fixture bundles. 03 parses all three plists with plistlib and asserts exact key sets head vs base plus scope/closure facts. 04 runs the repo-pinned gates (actionlint 1.7.12 with scripts/lint.js flags, shellcheck 0.11.0, prettier, eslint), each with a planted-violation live control. Tauri wiring was re-confirmed from tauri-apps/tauri source at tag tauri-cli-v2.11.4. Raw per-cell logs in logs/; captures 01-04*.png are the harness runs as printed.

Evidence images

01-test-release-ab-head-vs-base

02-workflow-replay-sign-verify-smoke

03-plist-validation-head-vs-base

04-lint-gates-with-live-controls

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

Qwen Code · sandboxed verification

@yiliang114

Copy link
Copy Markdown
Collaborator Author

Resolved the two entitlement test gaps in 4378146f197.

  • PR checks now pin the app microphone entitlement, a non-empty usage description, the Node JIT entitlement, and both release-time assertions.
  • The ripgrep signing guard now checks the whole signing block, so formatting changes cannot reintroduce app entitlements unnoticed.
  • Verified with the desktop release helper, Prettier, and git diff --check.

No screenshot: this is a packaging invariant with no meaningful UI state.

中文说明

已在 4378146f197 补齐 entitlement 打包不变量,并将 ripgrep 检查改为覆盖完整签名区块。Desktop release helper、Prettier 和 git diff --check 均通过。此改动没有可展示的 UI 状态,因此未附截图。

@yiliang114

Copy link
Copy Markdown
Collaborator Author

The post-fix Ubuntu failure was outside this PR: four BackgroundShellRegistry retention-cap tests failed, while this PR only changes desktop macOS packaging tests.

Per the CI refresh rule, I merged the latest main in 18a812f with no conflicts and pushed it without changing the PR implementation. Verification is pending on the refreshed head.

@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: reverse audit — stopped before round 3 by the review time budget. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。 建议见行内评论。 未审查:反向审计——评审时间预算不足,未能开始第 3 轮。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

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

Comment thread packages/desktop-shell/scripts/test-release.js Outdated
Comment thread packages/desktop-shell/scripts/test-release.js
@wenshao

wenshao commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Local verification on a real macOS stack — ✅ recommend merge

I built this PR's macOS app bundle locally and exercised the whole permission chain against the real OS, not just the plists. macOS 26.6 (25G72), arm64, Node 22.23.2, Tauri 2.11.5 / wry 0.55.1.

Base for every A/B below: 4a79517815 (merge-base). Both bundles come from the same tree and the same build; only packages/desktop-shell/src-tauri/ differs, and both are ad-hoc signed with codesign --options runtime --entitlements <its own set>.

The result that matters

macOS silently denies the microphone on the pre-PR bundle — no prompt is ever shown. With this PR, the native prompt appears carrying the exact usage string, and access is granted.

pre-PR bundle this PR's bundle
NSMicrophoneUsageDescription in Contents/Info.plist absent present
native permission prompt never shown shown
AVCaptureDevice.requestAccess(for: .audio) granted=false granted=true
resulting AVAuthorizationStatus denied authorized

macOS microphone prompt

TCC A/B transcript

Method: a small Swift probe was made the bundle's CFBundleExecutable in a copy of each built .app, then launched with open so LaunchServices attributes the request to the app itself. Everything TCC reads — bundle id com.alibaba.qwen-code, Info.plist, entitlements, hardened-runtime flag — is exactly what the build produced. Launching the probe from a terminal instead makes TCC attribute the request to the terminal and use the terminal's usage string, so that path can't verify this and was discarded.

The claim that could not be checked statically

tauri-codegen's Info.plist merge (context.rs:303) is guarded by dev && !running_tests, so it does not run for tauri build. Whether dropping src-tauri/Info.plist into the crate dir reaches a packaged bundle therefore only holds if the bundler merges it. A real build confirms it does, and that it clobbers nothing:

$ diff <(plutil -p base.app/Contents/Info.plist) <(plutil -p head.app/Contents/Info.plist)
16a17
> "NSMicrophoneUsageDescription" => "Qwen Code uses the microphone for voice dictation in the prompt composer."

Exactly one key added; CFBundleName, CFBundleIdentifier, CFBundleShortVersionString, LSMinimumSystemVersion all unchanged.

The two new release gates, run verbatim

bundle diff and CI gates

gate pre-PR bundle this PR's bundle
PlistBuddy -c 'Print :NSMicrophoneUsageDescription' (smoke step) exit 1 → release blocked exit 0 → passes
codesign --verify --deep --strict --verbose=2 valid valid
codesign -d --entitlements - --xml + PlistBuddy … audio-input = true key absent → release blocked true → passes

Both gates fail closed on the pre-PR artifact and pass on this one. I also confirmed codesign -d --entitlements - --xml and the test "$(…)" = true comparison behave as written on macOS 26.6 (PlistBuddy prints bare true for <true/>).

The app still starts after hardened-runtime signing with the new entitlement set — npm run smoke:packaged reports Packaged desktop runtime ready, and the real window loads the web-shell:

app running after hardened-runtime signing

Why the second commit (narrow helper entitlements) is load-bearing

I pulled the shipped v0.1.0 arm64 DMG (sha256 matches the release SHA256SUMS.txt; genuine Developer ID Application: Alibaba Cloud (Singapore) Private Limited (NF4574S59H)). Today all three binaries carry the identical entitlement set:

shipped v0.1.0 binary entitlements
Qwen Code Desktop.app allow-jit, network.client, network.server
bundled node allow-jit, network.client, network.server
vendored rg allow-jit, network.client, network.server

So without 97e0e30, adding audio-input to Entitlements.plist would also have handed the microphone entitlement to node and to ripgrep. Narrowing them is the right call, and it costs nothing — signed ad-hoc under the hardened runtime, both helpers behave identically before and after:

  • node with the old set vs. NodeEntitlements.plist (allow-jit only): HTTP server + client OK, JIT/new Function OK, child spawn OK — both.
  • rg with the old set vs. no entitlements at all: ripgrep 15.0.0, search OK — both.

That is expected: com.apple.security.network.* are App Sandbox entitlements and this app does not enable the sandbox, so removing them is a no-op at runtime.

Are the new test:release assertions real guards?

I reverted each guarded value one at a time in a sandboxed copy of the tree. 9/9 mutations were caught — no dead assertions:

# mutation caught by
M1 drop audio-input from Entitlements.plist the app bundle must keep microphone access for voice dictation
M2 empty NSMicrophoneUsageDescription string must declare a non-empty microphone usage description
M3 delete Info.plist (pre-PR state) hard ENOENT
M4 give audio-input to bundled Node Node.js must not receive microphone access
M5 strip allow-jit from NodeEntitlements.plist the bundled Node.js runtime must keep its JIT entitlement
M6 re-attach app entitlements to ripgrep signing ripgrep must not inherit the app entitlements
M7 remove the audio-input check from the CI verify step the macOS signature check must keep verifying the audio-input entitlement
M8 remove the NSMicrophoneUsageDescription check from the smoke step the packaged smoke must keep verifying the microphone usage description
M9 point Node signing back at the app entitlements Node.js must use its minimal helper entitlements

Also clean: actionlint on desktop-release.yml, prettier --check on the workflow and test-release.js, and plutil -lint on all three plists.

Consistency check

packages/desktop/apps/electron/ already ships the byte-identical usage string and already carries com.apple.security.device.audio-input in build/entitlements.mac.plist. This brings the Tauri shell to parity rather than inventing new wording.

I also confirmed the chain has no other gap: wry 0.55.1 implements webView:requestMediaCapturePermissionForOrigin:… and unconditionally returns WKPermissionDecision::Grant (wry/src/wkwebview/class/wry_web_view_ui_delegate.rs:126), so the WebKit layer was never the blocker — TCC was, and TCC needs exactly the two things this PR adds. The shell loads the web-shell from http://127.0.0.1:<port>, a potentially-trustworthy origin, so getUserMedia in packages/web-shell/client/voice/useVoiceCapture.ts is in a secure context.

Minor, non-blocking

  1. M3 is an unhandled ENOENT, not an assertion. If someone deletes src-tauri/Info.plist, test:release dies with a raw stack trace instead of the clear message every sibling check produces. A fs.existsSync guard with a message would match the surrounding style.
  2. The smoke gate accepts an empty string. PlistBuddy -c 'Print :NSMicrophoneUsageDescription' … >/dev/null succeeds for <string></string>. test:release catches an empty value in the source plist, so the hole is only reachable if the bundler mangles it — worth a [ -n … ] if you want the bundle-level gate to be as strict as the source-level one.
  3. The CI signature gate only checks the app. It asserts audio-input = true on the .app but never asserts its absence on the signed node / rg. That invariant currently lives only in test:release's plist-text assertions, so a future edit to the signing step's --entitlements argument would be caught, but a change to what those files contain at sign time would not.

Not covered

Production-certificate signing and notarization (ad-hoc signing only here, so spctl --assess was not meaningful), real sleep/wake, and the end-to-end voice-dictation UI — the voice button is gated behind a configured voice model and an authenticated session, so I verified the OS permission layer directly instead. Bundles were built with tauri build --debug; CI builds --release, but the Info.plist merge and entitlement signing are profile-independent.

中文版

在真实 macOS 环境本地验证 —— ✅ 建议合入

我在本地构建了这个 PR 的 macOS App bundle,并在真实系统上跑通了整条权限链路,而不只是检查 plist 文件。macOS 26.6 (25G72)、arm64、Node 22.23.2、Tauri 2.11.5 / wry 0.55.1。

下面所有 A/B 的基线都是 4a79517815(merge-base)。两个 bundle 来自同一棵源码树、同一次构建,只有 packages/desktop-shell/src-tauri/ 不同,并且都用 codesign --options runtime --entitlements <各自的集合> 做了 ad-hoc 签名。

最关键的结论

修复前的 bundle 会被 macOS 静默拒绝,系统弹窗根本不出现。加上这个 PR 之后,原生弹窗正常出现,并带着预期的用途说明文案,权限授予成功。

修复前 bundle 本 PR 的 bundle
Contents/Info.plist 里的 NSMicrophoneUsageDescription 缺失 存在
系统权限弹窗 从未出现 正常出现
AVCaptureDevice.requestAccess(for: .audio) granted=false granted=true
最终 AVAuthorizationStatus denied authorized

方法:把一个很小的 Swift 探针设为构建产物 .app 副本的 CFBundleExecutable,然后用 open 启动,让 LaunchServices 把请求归属到 App 自己。TCC 读取的所有东西——bundle id com.alibaba.qwen-codeInfo.plist、entitlements、hardened runtime 标志——都完全是构建产物本身。如果直接从终端启动探针,TCC 会把请求归属到终端并使用终端自己的用途说明,那条路径无法验证本 PR,已弃用。

静态检查无法确认的那一条

tauri-codegenInfo.plist 合并逻辑(context.rs:303)被 dev && !running_tests 守住,不会tauri build 时执行。所以「把 src-tauri/Info.plist 放进 crate 目录就能进入打包产物」只可能由 bundler 完成。真实构建证明确实如此,且没有覆盖任何其他键:

$ diff <(plutil -p base.app/Contents/Info.plist) <(plutil -p head.app/Contents/Info.plist)
16a17
> "NSMicrophoneUsageDescription" => "Qwen Code uses the microphone for voice dictation in the prompt composer."

只多了一个键;CFBundleNameCFBundleIdentifierCFBundleShortVersionStringLSMinimumSystemVersion 全部未变。

两个新增的发布门禁,原样执行

门禁 修复前 bundle 本 PR 的 bundle
PlistBuddy -c 'Print :NSMicrophoneUsageDescription'(smoke 步骤) exit 1 → 阻断发布 exit 0 → 通过
codesign --verify --deep --strict --verbose=2 有效 有效
codesign -d --entitlements - --xml + PlistBuddy … audio-input = true 键缺失 → 阻断发布 true → 通过

两个门禁在修复前的产物上都 fail-closed,在本 PR 的产物上都通过。我还确认了 codesign -d --entitlements - --xmltest "$(…)" = true 的写法在 macOS 26.6 上行为符合预期(PlistBuddy<true/> 输出裸 true)。

用新的 entitlement 集合做 hardened runtime 签名后 App 仍能正常启动:npm run smoke:packaged 输出 Packaged desktop runtime ready,真实窗口也能加载 web-shell。

第二个 commit(收窄 helper entitlements)为什么是必要的

我拉取了已发布的 v0.1.0 arm64 DMG(sha256 与 release 的 SHA256SUMS.txt 一致,签名是真实的 Developer ID Application: Alibaba Cloud (Singapore) Private Limited (NF4574S59H))。目前三个二进制携带的 entitlement 完全相同:

已发布 v0.1.0 二进制 entitlements
Qwen Code Desktop.app allow-jitnetwork.clientnetwork.server
内置 node allow-jitnetwork.clientnetwork.server
vendored rg allow-jitnetwork.clientnetwork.server

也就是说,如果没有 97e0e30,往 Entitlements.plist 里加 audio-input 会连带把麦克风 entitlement 发给 node ripgrep。收窄是正确的,而且没有代价——在 hardened runtime 下 ad-hoc 签名后,两个 helper 前后行为完全一致:

  • node 用旧集合 vs. NodeEntitlements.plist(仅 allow-jit):HTTP 服务端+客户端 OK、JIT/new Function OK、子进程 spawn OK——两者相同。
  • rg 用旧集合 vs. 完全不带 entitlements:ripgrep 15.0.0、搜索 OK——两者相同。

这符合预期:com.apple.security.network.* 属于 App Sandbox 的 entitlement,而这个 App 并未启用沙箱,所以移除它们在运行时是 no-op。

新增的 test:release 断言是真守卫吗?

我在沙箱副本里逐个回退被守护的值。9/9 变异全部被拦截,没有空断言:

# 变异 被谁拦下
M1 Entitlements.plist 删掉 audio-input the app bundle must keep microphone access for voice dictation
M2 NSMicrophoneUsageDescription 置空 must declare a non-empty microphone usage description
M3 删除 Info.plist(回到修复前状态) 直接 ENOENT
M4 给内置 Node 加上 audio-input Node.js must not receive microphone access
M5 NodeEntitlements.plist 去掉 allow-jit the bundled Node.js runtime must keep its JIT entitlement
M6 给 ripgrep 签名重新挂上 App entitlements ripgrep must not inherit the app entitlements
M7 从 CI verify 步骤删掉 audio-input 校验 the macOS signature check must keep verifying the audio-input entitlement
M8 从 smoke 步骤删掉 NSMicrophoneUsageDescription 校验 the packaged smoke must keep verifying the microphone usage description
M9 把 Node 签名指回 App entitlements Node.js must use its minimal helper entitlements

另外全部通过:desktop-release.ymlactionlint、工作流与 test-release.jsprettier --check、三个 plist 的 plutil -lint

一致性

packages/desktop/apps/electron/ 已经在用逐字相同的用途说明文案,并且 build/entitlements.mac.plist 里已经有 com.apple.security.device.audio-input。本 PR 是让 Tauri shell 与之对齐,而不是新造措辞。

我也确认链路上没有其他缺口:wry 0.55.1 实现了 webView:requestMediaCapturePermissionForOrigin:… 并无条件返回 WKPermissionDecision::Grantwry/src/wkwebview/class/wry_web_view_ui_delegate.rs:126),所以 WebKit 这一层从来不是阻塞点,卡住的是 TCC,而 TCC 需要的恰好就是本 PR 补上的这两样。Shell 从 http://127.0.0.1:<port> 加载 web-shell,属于 potentially-trustworthy origin,因此 packages/web-shell/client/voice/useVoiceCapture.ts 里的 getUserMedia 处于安全上下文。

次要问题,不阻塞合入

  1. M3 抛的是未处理的 ENOENT,不是断言。 如果有人删掉 src-tauri/Info.plisttest:release 会直接抛裸栈,而不是像相邻检查那样给出清晰信息。加一个带消息的 fs.existsSync 守卫会更贴合周围风格。
  2. smoke 门禁接受空字符串。<string></string>PlistBuddy -c 'Print :NSMicrophoneUsageDescription' … >/dev/null 仍会成功。test:release 会在 plist 上拦下空值,所以这个洞只有在 bundler 出问题时才可达——如果希望 bundle 级门禁和源码级一样严格,可以补一个 [ -n … ]
  3. CI 签名门禁只检查了 App。 它断言 .appaudio-input = true,但从未断言签名后的 node / rg没有这个 entitlement。该不变量目前只存在于 test:release 的 plist 文本断言里;也就是说改动签名步骤的 --entitlements 参数会被抓到,但改动这些文件在签名时的内容不会。

未覆盖

生产证书签名与公证(这里只做了 ad-hoc 签名,所以 spctl --assess 没有参考意义)、真实休眠/唤醒,以及端到端的语音听写 UI——语音按钮需要已配置的语音模型和已认证会话才会出现,因此我改为直接验证操作系统权限层。产物用 tauri build --debug 构建;CI 走 --release,但 Info.plist 合并与 entitlement 签名与 profile 无关。

doudouOUC
doudouOUC previously approved these changes Aug 9, 2026

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

Approving — re-reviewed at 18a812f88573733b62576ddd66bc4d547600597e. My earlier approval was dismissed by the push, so this is a fresh look at the delta since 00eabce419, plus a re-check of what I raised last round. Both of my Suggestions are addressed, and the coverage complaint is resolved. One residual guard gap remains, non-blocking, with a reproduction.

R1-2 is genuinely fixed — I re-ran my own evasion

Last round I showed that assert.doesNotMatch(workflow, /--entitlements src-tauri\/Entitlements\.plist \{\} \+/) pinned a text shape, not a property: re-adding --entitlements on its own continuation line left all five assertions green while ripgrep went back to being signed with the app's full entitlement set, microphone included.

The block-slice replacement closes that. I applied the same evasion to this head and it now fails, along with every other mutation I could think of — 8/8 caught:

baseline (unmutated): passes ✅
caught  M1 re-add --entitlements to ripgrep on its own continuation line (last round's evasion)
caught  M2 same evasion + rename the "# ripgrep vendor binaries" slice marker
caught  M3 drop audio-input from the app Entitlements.plist
caught  M4 empty the NSMicrophoneUsageDescription string
caught  M5 drop allow-jit from NodeEntitlements.plist
caught  M6 grant audio-input to the bundled Node runtime
caught  M7 delete the release-time audio-input entitlement assertion
caught  M8 delete the release-time NSMicrophoneUsageDescription assertion
restored; baseline again: passes ✅

M3–M8 are the R1-1 gap — the four positive invariants plus both release-time assertion lines that were unguarded last round. They are all pinned now. The rewrite of the old assert.ok(includes('--entitlements src-tauri/Entitlements.plist {} +')) into assert.match(/--options runtime --timestamp \\\n\s+\{\} \+/) also preserves the original intent of that assertion (the -exec … + form, so a codesign failure fails the step) without dragging the entitlements flag back in. Good adaptation.

Coverage: my previous blocker is gone

Last round there were zero workflow runs on the reviewed head. This head has four, and both Desktop Shell (ubuntu-22.04) and Desktop Shell (windows-2022) are green — that is the job which runs node scripts/test-release.js (and cargo test), i.e. the guard this PR extends actually executed against this change. Test (ubuntu-latest, Node 22.x) and the rest are green too. Nothing further owed here.

Residual, non-blocking: the slice anchor can make the guard vacuous

ripgrepSigningBlock is workflow.slice(indexOf('# ripgrep vendor binaries'), indexOf('# Node.js runtime binary')). If the opening marker is ever renamed, indexOf returns -1, slice(-1, end) yields the empty string, and assert.doesNotMatch('', /--entitlements/) passes for free — the guard stops guarding without saying so.

That is not reachable by the marker rename alone (M2 above is caught) but only because a different assertion — the --options runtime --timestamp \ + {} + continuation form — happens to break when you insert the flag there. Put the flag one line earlier instead, where that form stays intact, and both fire blank:

caught      M9  --entitlements before --options runtime, marker intact
NOT CAUGHT  M10 same, but the ripgrep marker is renamed
NOT CAUGHT  M11 marker renamed only (no entitlements added)
caught      M12 closing marker "# Node.js runtime binary" renamed only

M10 is a two-part edit — reorder codesign args, reword a comment — each half of which looks innocent in review, and it puts the app's full entitlements (microphone included) back on the vendored rg with the whole suite green. Nothing downstream catches it either: the release-time entitlement dump inspects the .app bundle, never ripgrep.

Note the asymmetry, which is worth keeping: renaming the closing marker fails closed (M12 — the block then runs to EOF and swallows Node's --entitlements). Only the opening marker fails open. One line fixes it:

const rgStart = workflow.indexOf('# ripgrep vendor binaries');
const rgEnd = workflow.indexOf('# Node.js runtime binary');
assert.ok(rgStart !== -1 && rgEnd > rgStart, 'the ripgrep signing block must be locatable');

Suggestion severity, same as last round's: the workflow as written today signs ripgrep correctly, so this is guard robustness, not a live defect. But the entire point of the entitlement split is that the next edit cannot quietly undo it, and this is now the only thing standing between that and a green suite.

Unchanged from last round

Still true, still unverifiable at PR time, still correctly handled by the release-time assertions: whether Tauri actually merges src-tauri/Info.plist into the built bundle (its only wiring is filename auto-discovery — nothing in the repo references it), and whether the entitlement lands on the signed binary. Those need a real signed macOS build; the workflow_dispatch assertions are the right place for them and they are both now pinned by tests.

中文说明

批准 —— 在 18a812f88573733b62576ddd66bc4d547600597e 上重新审查。我之前的批准已被推送 dismiss,因此这次是对 00eabce419 之后增量的新一轮审查,并复核我上轮提出的问题。两条 Suggestion 都已处理,覆盖率方面的阻塞项也已解决。仍有一处残留的守卫缺口,不阻塞,附复现。

R1-2 确实修好了——我重跑了自己的绕过手法

上轮我证明 assert.doesNotMatch(workflow, /--entitlements src-tauri\/Entitlements\.plist \{\} \+/) 钉的是文本形状而非属性:把 --entitlements 加在独立续行上,五条断言全绿,而 ripgrep 又会以应用完整权限集(含麦克风)签名。

改用"切出 ripgrep 签名块"后这条路被堵住了。我把同样的绕过手法应用到本 head,现在会失败;我能想到的其他变异也都被捕获——8/8:

基线(未变异):通过 ✅
捕获  M1 把 --entitlements 以独立续行重新加回 ripgrep(上轮的绕过手法)
捕获  M2 同样的绕过 + 重命名 "# ripgrep vendor binaries" 切片标记
捕获  M3 从应用 Entitlements.plist 删除 audio-input
捕获  M4 把 NSMicrophoneUsageDescription 文案清空
捕获  M5 从 NodeEntitlements.plist 删除 allow-jit
捕获  M6 给随附 Node 运行时授予 audio-input
捕获  M7 删除发布期 audio-input 权限断言
捕获  M8 删除发布期 NSMicrophoneUsageDescription 断言
恢复后基线:通过 ✅

M3–M8 正是 R1-1 的缺口——上轮无守卫的四条正向不变式加两条发布期断言行,现已全部钉住。把旧的 assert.ok(includes('--entitlements src-tauri/Entitlements.plist {} +')) 改写为 assert.match(/--options runtime --timestamp \\\n\s+\{\} \+/),同时保留了该断言原本的意图(-exec … + 形态,使 codesign 失败能让步骤失败),且没有把 entitlements 标志重新拖回来。改写得当。

覆盖率:我上轮的阻塞项已消除

上轮被审 head 上的 workflow 运行数为。本 head 有四次运行,且 Desktop Shell (ubuntu-22.04)(windows-2022) 均为绿色——正是运行 node scripts/test-release.js(以及 cargo test)的那个 job,也就是本 PR 所扩展的守卫,这次真的对本改动执行了。Test (ubuntu-latest, Node 22.x) 等也为绿。此项无遗留。

残留(不阻塞):切片锚点可能让守卫变成空断言

ripgrepSigningBlockworkflow.slice(indexOf('# ripgrep vendor binaries'), indexOf('# Node.js runtime binary'))。一旦起始标记被改名,indexOf 返回 -1slice(-1, end) 得到空字符串,于是 assert.doesNotMatch('', /--entitlements/) 白白通过——守卫停止守卫而不作声。

仅改名标记还触发不了它(上面 M2 被捕获),但那只是因为另一条断言——--options runtime --timestamp \ + {} + 的续行形态——恰好会因为在那里插入标志而失效。把标志往前挪一行、让该形态保持完整,两条断言就都会落空:

捕获      M9  --entitlements 放在 --options runtime 之前,标记不变
未捕获    M10 同上,但 ripgrep 标记被改名
未捕获    M11 仅改名标记(未加 entitlements)
捕获      M12 仅改名收尾标记 "# Node.js runtime binary"

M10 是一次两部分的编辑——调整 codesign 参数顺序 + 改一句注释——两半在评审里各自看起来都很无辜,合起来却让随附的 rg 重新带上应用完整权限(含麦克风),而整套断言全绿。下游也拦不住:发布期的权限导出只检查 .app bundle,从不检查 ripgrep。

注意这处不对称,值得保留:改名收尾标记是 fail-closed(M12——此时块一直延伸到文件尾,把 Node 的 --entitlements 一并吞进来)。只有起始标记是 fail-open。一行即可修复:

const rgStart = workflow.indexOf('# ripgrep vendor binaries');
const rgEnd = workflow.indexOf('# Node.js runtime binary');
assert.ok(rgStart !== -1 && rgEnd > rgStart, 'the ripgrep signing block must be locatable');

定级与上轮相同,为 Suggestion:今天的 workflow 对 ripgrep 的签名是正确的,所以这是守卫健壮性问题而非现行缺陷。但权限拆分的全部意义就在于下一次改动不能悄悄把它撤销,而现在这已是横在"撤销"与"全绿套件"之间的唯一屏障。

与上轮相同、未变的部分

依旧成立、依旧无法在 PR 期验证、也依旧由发布期断言正确兜底:Tauri 是否真的把 src-tauri/Info.plist 合并进构建产物(它唯一的接入方式是按文件名自动发现——仓库里没有任何地方引用它),以及权限是否真的落在已签名二进制上。这两者需要真实的 macOS 签名构建;workflow_dispatch 的断言正是它们该待的地方,且现在都已被测试钉住。

— reviewed by doudouOUC

@yiliang114

Copy link
Copy Markdown
Collaborator Author

Closeout for f294c8d80c8:

  • Changed: the release guard now fails closed when signing-section markers disappear, and both macOS audio-input and Node allow-jit entitlements must remain true.
  • Verified: Desktop release helper, Node syntax check, Prettier, and git diff --check.
  • Intentionally not changed: none.
  • Pending: exact-head CI is running; re-review was requested from @doudouOUC.
中文摘要

发布校验现在会在签名段 marker 缺失时失败,并确认 macOS 麦克风权限与 Node JIT 权限值均为 true。定向验证已通过;当前 exact-head CI 正在运行,已请求 @doudouOUC 复审。

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

Approving again — reviewed at f294c8d80c876aee451f2e567393e67dab09c4c2. My approval from twenty minutes ago was dismissed by this push, so here is the delta review: the one commit since 18a812f885 is test(desktop): strengthen entitlement release guards, and it closes exactly the residual gap I reported — plus two hardenings I had not asked for.

The fail-open is gone

The guard now validates both markers before slicing:

const ripgrepStart = workflow.indexOf('# ripgrep vendor binaries');
const ripgrepEnd = workflow.indexOf('# Node.js runtime binary');
assert.ok(ripgrepStart !== -1 && ripgrepEnd > ripgrepStart, '…must keep its ripgrep/Node section markers');

I re-ran both of my probes against this head. The two cases that slipped through last round are now caught, and the whole set holds:

caught  M9  --entitlements before --options runtime, marker intact
caught  M10 same, but the ripgrep marker is renamed      ← was NOT CAUGHT
caught  M11 marker renamed only (no entitlements added)   ← was NOT CAUGHT
caught  M12 closing marker renamed only
caught  M1–M8 (last round's full set, re-run)
baseline: passes ✅

M11 being caught is the better outcome than the one I proposed: renaming the marker now fails immediately and on its own, rather than only when combined with a bad codesign edit. The guard says "I can no longer find what I am supposed to check" instead of silently checking nothing.

Two hardenings beyond the ask

The positive assertions moved from bare substring matches to key/value pairs:

/com\.apple\.security\.device\.audio-input/  →  /<key>com\.apple\.security\.device\.audio-input<\/key>\s*<true\/>/
/com\.apple\.security\.cs\.allow-jit/        →  /<key>com\.apple\.security\.cs\.allow-jit<\/key>\s*<true\/>/

That closes a hole neither of us had named: a key present but set to <false/> satisfied the old regex, so a disabled entitlement read as a healthy one. I probed both:

caught  N1 app audio-input set to <false/> (key still present)
caught  N2 Node allow-jit set to <false/> (key still present)

Both would have passed before this commit. Note the negative assertion (nodeEntitlements must not carry audio-input) correctly stays a bare match — there, mentioning the key at all is what matters, and requiring <true/> would have introduced the same class of hole in reverse.

Nothing else in the diff. Desktop Shell is green on ubuntu-22.04 and windows-2022 at this head; the Node lane is still running. Everything from my previous review stands, minus the residual finding, which is now resolved.

中文说明

再次批准 —— 审查提交 f294c8d80c876aee451f2e567393e67dab09c4c2。我二十分钟前的批准被这次推送 dismiss,因此这是增量审查:18a812f885 之后的唯一提交是 test(desktop): strengthen entitlement release guards,它正好补上了我报告的残留缺口,另外还多做了两处我并未要求的加固。

fail-open 已消除

守卫现在会在切片之前校验两个标记:

const ripgrepStart = workflow.indexOf('# ripgrep vendor binaries');
const ripgrepEnd = workflow.indexOf('# Node.js runtime binary');
assert.ok(ripgrepStart !== -1 && ripgrepEnd > ripgrepStart, '…must keep its ripgrep/Node section markers');

我把两个探针都在本 head 上重跑了一遍。上一轮漏掉的两个用例现已被捕获,整套结果保持成立:

捕获  M9  --entitlements 放在 --options runtime 之前,标记不变
捕获  M10 同上,但 ripgrep 标记被改名        ← 上轮未捕获
捕获  M11 仅改名标记(未加 entitlements)     ← 上轮未捕获
捕获  M12 仅改名收尾标记
捕获  M1–M8(上轮全套,已重跑)
基线:通过 ✅

M11 被捕获,比我提议的方案更好:改名标记现在会立即、独立地失败,而不是只有与错误的 codesign 编辑组合时才失败。守卫会说"我已经找不到该检查的东西了",而不是默默地什么都不检查。

超出要求的两处加固

两条正向断言从裸子串匹配改成了键值对匹配:

/com\.apple\.security\.device\.audio-input/  →  /<key>com\.apple\.security\.device\.audio-input<\/key>\s*<true\/>/
/com\.apple\.security\.cs\.allow-jit/        →  /<key>com\.apple\.security\.cs\.allow-jit<\/key>\s*<true\/>/

这补上了我们双方都没点出的一个漏洞:键存在但被设为 <false/> 也能满足旧正则,于是被禁用的权限会被读成健康状态。两种情形我都探测了:

捕获  N1 应用 audio-input 被设为 <false/>(键仍存在)
捕获  N2 Node allow-jit 被设为 <false/>(键仍存在)

在本提交之前,这两种情形都会通过。另外注意:否定断言(nodeEntitlements 不得含 audio-input)正确地保持了裸匹配——在那里,只要提到该键就要报警,若也要求 <true/> 反而会引入同一类漏洞的反向版本。

diff 中没有其他内容。本 head 上 Desktop Shell 在 ubuntu-22.04 与 windows-2022 均为绿色,Node 通道仍在运行。我上一轮审查的其余结论全部维持,唯一的残留发现现已解决。

— reviewed by doudouOUC

@yiliang114
yiliang114 added this pull request to the merge queue Aug 9, 2026
Merged via the queue into main with commit ab61d81 Aug 9, 2026
50 of 51 checks passed

@wenshao wenshao 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 linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。 建议见行内评论。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/desktop-release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

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

Comment on lines +392 to +393
codesign -d --entitlements - --xml "$app" > "$entitlements" 2>/dev/null
test "$(/usr/libexec/PlistBuddy -c 'Print :com.apple.security.device.audio-input' "$entitlements")" = 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] Release-time verification is asymmetric: the new artifact-level assertions check only the app's main executable (audio-input entitlement here, usage description in Contents/Info.plist). The PR's actual behavioral change — Node signed with NodeEntitlements.plist (allow-jit only), ripgrep signed with no entitlements — has no release-time artifact check; only the workflow-text/source-file unit assertions cover it. — Failure scenario: a future divergence between the source plists and the final bundle — a build step re-signing or replacing the embedded node/rg binaries, or the signing step dropping the NodeEntitlements.plist flag while the workflow-text test is updated in the same commit — ships Node carrying com.apple.security.device.audio-input (or ripgrep the full app entitlements), exactly the exposure this PR exists to prevent. codesign --verify --deep --strict checks validity, not entitlement content; every release gate stays green.

Suggested change
codesign -d --entitlements - --xml "$app" > "$entitlements" 2>/dev/null
test "$(/usr/libexec/PlistBuddy -c 'Print :com.apple.security.device.audio-input' "$entitlements")" = true
node_bin="$app/Contents/Resources/runtime/qwen-code/node/bin/node"
if [ -f "$node_bin" ]; then
node_entitlements="$(mktemp)"
codesign -d --entitlements - --xml "$node_bin" > "$node_entitlements" 2>/dev/null
test "$(/usr/libexec/PlistBuddy -c 'Print :com.apple.security.device.audio-input' "$node_entitlements")" != true
test "$(/usr/libexec/PlistBuddy -c 'Print :com.apple.security.cs.allow-jit' "$node_entitlements")" = true
rm -f "$node_entitlements"
fi
中文说明

发布期验证不对称:新增的产物级断言只检查 App 主可执行文件(此处的 audio-input 权限,以及 Contents/Info.plist 里的用途说明)。本 PR 真正的行为变更——Node 改用仅含 allow-jit 的 NodeEntitlements.plist 签名、ripgrep 不带任何权限签名——没有任何发布期产物检查,只有 workflow 文本/源文件级的单元断言在覆盖。— 失败场景:未来源 plist 与最终 bundle 出现偏差——某步构建重新签名或替换内嵌的 node/rg 二进制,或签名步骤丢掉 NodeEntitlements.plist 参数且同一提交里改了 workflow 文本测试——Node 带着 com.apple.security.device.audio-input(或 ripgrep 带着完整应用权限)发布,这正是本 PR 要防止的暴露。codesign --verify --deep --strict 只检查签名有效性,不检查权限内容;所有发布关卡仍然全绿。

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

Comment on lines +126 to 130
assert.match(
workflow,
/--options runtime --timestamp \\\n\s+\{\} \+/,
'ripgrep codesign failures must fail the signing step',
);

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 assertion message 'ripgrep codesign failures must fail the signing step' (carried over from the pre-diff assertion) does not match what the regex tests: /--options runtime --timestamp \\n\s+\{\} \+/ only pins the codesign command's syntactic continuation shape. The property the message names actually lives in set -euo pipefail at the top of the 'Sign bundled vendor binaries (macOS)' step — and no assertion in test-release.js checks it. — Failure scenario: set -e (or set -euo pipefail) is removed from that step, or the codesign command is detached from that shell context → a failing codesign becomes a non-fatal warning → unsigned/partially-signed helper binaries ship in the release, while this test, whose stated purpose is exactly to prevent that, still passes.

Suggested change
assert.match(
workflow,
/--options runtime --timestamp \\\n\s+\{\} \+/,
'ripgrep codesign failures must fail the signing step',
);
const signingStep = workflow.slice(
workflow.indexOf("name: 'Sign bundled vendor binaries (macOS)'"),
workflow.indexOf("name: 'Build desktop installers'"),
);
assert.match(
signingStep,
/set -euo pipefail/,
'the signing step must keep failing closed on codesign errors',
);
assert.match(
workflow,
/--options runtime --timestamp \\n\s+\{\} \+/,
'the ripgrep codesign command must keep its hardened-runtime flags',
);
中文说明

断言消息 "ripgrep codesign failures must fail the signing step"(沿用自改动前的断言)与正则实际测试的内容不符:/--options runtime --timestamp \\n\s+\{\} \+/ 只固定了 codesign 命令的语法续行形态。消息所指的属性实际存在于 'Sign bundled vendor binaries (macOS)' 步骤顶部的 set -euo pipefail——而 test-release.js 中没有任何断言检查它。— 失败场景:该步骤删掉 set -e(或 set -euo pipefail),或 codesign 命令脱离该 shell 上下文 → 失败的 codesign 变成非致命警告 → 未签名/部分签名的辅助二进制随发布流出,而这个声称正是要阻止该情况的测试仍然通过。

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

Comment on lines +390 to +393
entitlements="$(mktemp)"
trap 'rm -f "$entitlements"' EXIT
codesign -d --entitlements - --xml "$app" > "$entitlements" 2>/dev/null
test "$(/usr/libexec/PlistBuddy -c 'Print :com.apple.security.device.audio-input' "$entitlements")" = 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] Dry-run rehearsal silently skips the app-side mic-entitlement gate: the audio-input check landed in 'Verify macOS signature' (if: runner.os == 'macOS' && inputs.dry_run == false), while the sibling NSMicrophoneUsageDescription check went into 'Smoke packaged application' (ungated). Since dry_run defaults to true and this workflow is workflow_dispatch-only, the codesign-dump path executes nowhere — not in CI, not in a dry-run rehearsal — until the first real signed release. Separately, tauri.conf.json's bundle.macOS.entitlements: "Entitlements.plist" is asserted by no test. — Failure scenario: an operator triggers the default dry-run to rehearse a release; the smoke step's Info.plist check passes green but the audio-input assertion is skipped, so a regression such as bundle.macOS.entitlements being repointed at NodeEntitlements.plist sails through the dry-run and is first caught on the real release run — whose codesign-dump assertion has never executed anywhere before.

中文说明

干跑排练会静默跳过应用侧麦克风权限关卡:audio-input 检查放在了 'Verify macOS signature'(if: runner.os == 'macOS' && inputs.dry_run == false),而同族的 NSMicrophoneUsageDescription 检查放在了 'Smoke packaged application'(不设门控)。由于 dry_run 默认是 true,且该 workflow 仅由 workflow_dispatch 触发,codesign 导出路径在任何地方都不会执行——CI 不执行、干跑也不执行——直到第一次真实签名发布。另外,tauri.conf.json 中的 bundle.macOS.entitlements: "Entitlements.plist" 没有任何测试断言。— 失败场景:操作员触发默认干跑来排练发布;smoke 步骤的 Info.plist 检查通过,但 audio-input 断言被跳过,于是诸如把 bundle.macOS.entitlements 改指向 NodeEntitlements.plist 之类的回归可以安然通过干跑,直到真实发布时才被发现——而那条 codesign 导出断言此前从未在任何地方执行过。

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

Comment on lines +128 to 129
/--options runtime --timestamp \\\n\s+\{\} \+/,
'ripgrep codesign failures must fail the signing step',

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 regex /--options runtime --timestamp \\n\s+\{\} \+/ pins the rg codesign command's exact flag sequence AND its multi-line continuation shape; any semantically-correct future edit — a flag reorder or a new flag inserted before {} — makes the assertion fail, breaking CI on correct changes rather than on regressions (probe-verified: inserting --verbose=4 between --timestamp and {} fails the suite; revert restores green). — Failure scenario: a future maintainer adds a flag to the ripgrep codesign (e.g. --verbose=4) or reorders flags while keeping the command fully valid → assert.match fails → CI goes red on a correct change, and the author must discover that this whitespace-sensitive regex — not the signing — is what broke.

中文说明

正则 /--options runtime --timestamp \\n\s+\{\} \+/ 同时固定了 rg codesign 命令的精确参数顺序和多行续行形态;任何语义正确的未来改动——调整参数顺序或在 {} 前插入新参数——都会让断言失败,CI 因正确改动而非回归变红(探针实测:在 --timestamp{} 之间插入 --verbose=4 会让套件失败,还原后恢复绿色)。— 失败场景:未来维护者给 ripgrep codesign 加一个参数(如 --verbose=4)或调整参数顺序但命令完全合法 → assert.match 失败 → CI 因正确改动变红,作者还得查明是这个对空白敏感的 regex——而不是签名本身——坏了事。

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

Comment on lines +131 to +134
assert.ok(
workflow.includes(
'--entitlements src-tauri/NodeEntitlements.plist "$node_bin"',
),

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 test pins the ripgrep sibling's full invocation (--options runtime --timestamp \ + {} +) but pins only the entitlements argument for the Node sibling — the hardened-runtime flags on the Node codesign (--options runtime --timestamp) are asserted nowhere. Asymmetric guard (probe-verified: deleting those flags from the Node line leaves the suite green). — Failure scenario: a future edit drops --options runtime --timestamp from the Node codesign line (leaving --entitlements src-tauri/NodeEntitlements.plist "$node_bin" intact) → the assertion still passes on the substring → the suite greenlights a Node binary signed without hardened runtime, and the regression surfaces only at release (child-process launch failure under the hardened parent, or notarization rejection).

Suggested change
assert.ok(
workflow.includes(
'--entitlements src-tauri/NodeEntitlements.plist "$node_bin"',
),
assert.match(
workflow,
/codesign --force --sign "\$APPLE_SIGNING_IDENTITY" \\n\s+--options runtime --timestamp \\n\s+--entitlements src-tauri\/NodeEntitlements\.plist "\$node_bin"/,
'Node.js must keep its hardened-runtime flags and minimal entitlements',
);
中文说明

测试固定了 ripgrep 兄弟命令的完整调用形态(--options runtime --timestamp \ + {} +),但对 Node 兄弟只固定了 entitlements 参数——Node codesign 行上的 hardened-runtime 标志(--options runtime --timestamp)没有任何断言。守卫不对称(探针实测:删掉 Node 行的这些标志后套件仍然全绿)。— 失败场景:未来某次编辑从 Node codesign 行删掉 --options runtime --timestamp(保留 --entitlements src-tauri/NodeEntitlements.plist "$node_bin")→ 断言仍能匹配子串 → 套件给一个没有 hardened runtime 签名的 Node 二进制放行,回归要到发布时才暴露(在 hardened 父进程下子进程启动失败,或公证被拒)。

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

Comment on lines +179 to +183
assert.match(
workflow,
/Print :com\.apple\.security\.device\.audio-input/,
'the macOS signature check must keep verifying the audio-input entitlement',
);

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 regex pins only the PlistBuddy key name, not the load-bearing = true comparison on the same workflow line. Mutation-verified: deleting = true from that workflow line leaves the unit suite fully green. — Failure scenario: a packaged app whose com.apple.security.device.audio-input entitlement is <false/> (or a non-boolean value) then passes the release gate that this test exists to guard. (The missing-key case is still caught via the empty output; the false-value case is not.)

Suggested change
assert.match(
workflow,
/Print :com\.apple\.security\.device\.audio-input/,
'the macOS signature check must keep verifying the audio-input entitlement',
);
assert.match(
workflow,
/Print :com\.apple\.security\.device\.audio-input' "\$entitlements"\)" = true/,
'the macOS signature check must keep verifying the audio-input entitlement',
);
中文说明

正则只固定了 PlistBuddy 的键名,没有固定同一行上承载核心语义的 = true 比较。变异实测:从 workflow 那行删掉 = true 后,单元套件仍然全绿。— 失败场景:打包应用里 com.apple.security.device.audio-input 权限被设为 <false/>(或非布尔值)时,本测试要守护的发布关卡仍然放行。(键缺失的情况仍会因空输出被抓到;false 值的情况抓不到。)

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.9.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants