Skip to content

feat(ui): word-wise drag after double-click, line-wise extension after triple-click - #8739

Merged
wenshao merged 15 commits into
mainfrom
feat/word-line-drag-selection
Aug 12, 2026
Merged

feat(ui): word-wise drag after double-click, line-wise extension after triple-click#8739
wenshao merged 15 commits into
mainfrom
feat/word-line-drag-selection

Conversation

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

What this PR does

Extends the VP-mode mouse text selection so that holding and dragging after a double-click grows the selection word-by-word, and after a triple-click grows it line-by-line. Previously a double/triple click selected a single word/line and returned immediately; dragging after it did nothing.

Implementation: on a multi-click the controller now enters a drag-capable word/line selection (SelectionState.mode + a spanDragRef anchor span) instead of a static selectSpan. On move/left-release, extendSpanDrag re-anchors to the original word/line and extends the focus to the word/line boundary under the cursor (falling back to a single cell over whitespace). Copy now happens on release for word/line selects, matching char drags.

Why it's needed

Standard editor gestures: double-click+drag to select consecutive words, triple-click+drag to select whole lines. Without them, selecting multiple words requires a precise char-mode drag, which is slow and unpredictable in a terminal grid. Requested in #8738.

Reviewer Test Plan

How to verify

  1. npx vitest run packages/cli/src/ui/selection/use-text-selection.test.tsx — 11 tests pass, including two new ones: double-click+drag on "foo bar baz" selects the full range and copies "foo bar baz"; triple-click+drag across two lines selects both lines and copies "hello\nworld!".
  2. Manual (VP mode): double-click a word then hold and drag — selection should snap word-by-word; triple-click then drag — selection should snap line-by-line. Release copies to clipboard.

Evidence (Before & After)

N/A — behavior verified by unit tests. Before: drag after double/triple click was a no-op. After: it extends word/line-wise.

Tested on

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

Environment

Unit tests via vitest (@testing-library/react + mocked mouse events).

Risk & Scope

  • Main risk or tradeoff: word/line selects now copy on release rather than immediately on the multi-click; a plain double-click (press+release, no move) still copies the same word, so observable behavior for the no-drag case is unchanged.
  • Not validated / out of scope: selection remains visible-region-only (B1) and clears on scroll/streaming, as before.
  • Breaking changes / migration notes: None.

Linked Issues

Fixes #8738

中文说明

这个 PR 做了什么

扩展 VP 模式鼠标选择:双击后按住拖动按词扩展、三击后按住拖动按行扩展。此前双击/三击只选中单个词/行,拖动无效。实现上多点点击时进入可拖动的 word/line 选择态(记录锚点 span),move/release 时把焦点吸附到光标处的词/行边界;词/行选择的复制改在释放时触发,与字符拖动一致。

为什么需要

编辑器常用手势:双击+拖动连选多个词、三击+拖动整行扩展。没有它只能靠精确的字符级拖动,慢且不准。见 #8738

风险与范围

  • 主要风险:词/行选择改为释放时复制;但单纯双击(不按拖)仍复制同一个词,行为不变。
  • 未验证/超出范围:选择仍仅限可视区域(B1),滚动/流式输出时清除,维持原状。
  • 破坏性变更:无。

…lick

Double/triple click already selected a single word/line, but holding and
dragging did not extend the selection by word/line. Enter a drag-capable
word/line selection on multi-click and extend the range to the word/line
boundary under the cursor on move/release, so double-click+drag grows by
words and triple-click+drag by lines.

Fixes #8738
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Re-run after the head moved through seven fix rounds plus main merges (now aaaae0d749); re-gated from scratch against the current head.

Template looks good ✓

Problem: real and demonstrated, not theoretical. Issue #8738 documents the exact gap — the multi-click branch selects a word/line and returns without ever entering drag mode — and a maintainer's local BASE-vs-HEAD comparison in a real pty confirms every drag-extension gesture is a no-op on the merge base and functional on this head.

Direction: aligned. This completes the standard editor gesture set on top of the VP-mode selection shipped in #6937, and the issue carries roadmap/terminal-ux. CHANGELOG (Claude Code) has no direct reference to drag-after-multi-click extension, but sustained investment in TUI double-click selection there keeps the area relevant.

Size: not applicable — no core paths. Everything sits in packages/cli/src/ui/selection/: 132 production lines (103 additions + 29 deletions across selection-span.ts, selection-state.ts, use-text-selection.tsx) plus 280 test lines. Well under every threshold.

Approach: scope feels right, and the diff is minimal — it follows the shape the issue suggested (record a word/line mode plus an anchor span on multi-click, stay drag-capable, snap the focus to the word/line boundary under the cursor on move/release), and the previously orphaned selectSpan was removed rather than left as dead code. One behavioral nuance I verified rather than took on faith: copying now happens at press as well as release for multi-clicks, because a streaming repaint can clear the selection between press and release. That was a real regression caught in round 5, and it is pinned by a dedicated test.

Risk: no elevated risk signals — none of the changed files match the revert-correlated high-risk paths.

Moving on to code review. 🔍

中文说明

Re-run:head 经过 7 轮修复 + 多次合并 main(现为 aaaae0d749),本次对当前 head 重新走完整门禁。

模板完整 ✓

问题:真实且已被证实,不是理论问题。Issue #8738 指出了确切缺口——多点点击分支选中词/行后直接返回、从未进入拖动模式;维护者在真实 pty 中做的 BASE 与 HEAD 对照也确认:所有拖动扩展手势在 merge base 上无效、在本 head 上生效。

方向:对齐。在 #6937 已上线的 VP 模式选择之上补全标准编辑器手势,关联 issue 带有 roadmap/terminal-ux 标签。Claude Code 的 CHANGELOG 没有直接提到多点点击后拖动扩展,但其 TUI 在双击选词上持续投入,该领域仍然相关。

规模:不适用——未触及核心路径。改动全部位于 packages/cli/src/ui/selection/:132 行生产代码(103 增 29 删,分布在 selection-span.tsselection-state.tsuse-text-selection.tsx)+ 280 行测试,远低于任何阈值。

方案:范围合理,diff 也是最小集——实现遵循 issue 建议的形态(多点点击时记录 word/line 模式与锚点 span、保持可拖动、move/release 时把焦点吸附到光标下的词/行边界),且此前沿用的 selectSpan 已被删除而不是留成死代码。有一处行为变化我亲自核实过而非轻信描述:多点点击现在在 press 与 release 时都复制,因为流式重绘可能在 press 与 release 之间清掉选择。那是第 5 轮发现的真实回归,现已有专门测试钉住。

风险:无升级风险信号——改动文件均未命中与 revert 相关的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at aaaae0d749b72aae239e44e7c814cfb0d70c81f5 · 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.99% 83.99% 89.89% 83.22%
Core 87.85% 87.85% 89.4% 86.36%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.99 |    83.22 |   89.89 |   83.99 |                   
 src               |   85.12 |     81.7 |   88.49 |   85.12 |                   
  cli.ts           |   95.68 |    84.11 |     100 |   95.68 | ...60-561,565-566 
  gemini.tsx       |   73.75 |    79.33 |   80.76 |   73.75 | ...1319-1323,1450 
  ...ractiveCli.ts |   86.74 |    81.15 |   88.13 |   86.74 | ...2955,2961,3026 
  ...liCommands.ts |   89.33 |     85.6 |      90 |   89.33 | ...01,518,552,674 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   71.47 |    73.67 |   91.19 |   71.47 |                   
  acpAgent.ts      |   70.88 |    73.47 |   90.74 |   70.88 | ...61,12266-12268 
  ...k-reporter.ts |     100 |    80.95 |     100 |     100 | 77,80,115,135     
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |     100 |      100 |     100 |     100 |                   
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |    97.1 |    95.83 |   93.33 |    97.1 |                   
  filesystem.ts    |    97.1 |    95.83 |   93.33 |    97.1 | ...22-123,246-247 
 ...ration/session |   91.49 |    86.99 |   96.71 |   91.49 |                   
  Session.ts       |   90.51 |    85.18 |   95.94 |   90.51 | ...90,10717-10721 
  ...entTracker.ts |    96.8 |    89.36 |      90 |    96.8 | 137-143,221       
  ...projection.ts |   98.57 |    93.29 |     100 |   98.57 | ...76,333,344,356 
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |   93.44 |    91.74 |     100 |   93.44 | 74,85-88,115-125  
  ...y-replayer.ts |   98.54 |    95.65 |     100 |   98.54 | 241-243           
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    87.32 |     100 |   89.76 | ...54-270,326-328 
  ...lure-guard.ts |   98.32 |    97.75 |     100 |   98.32 | 294-295,340-341   
  tasksSnapshot.ts |    94.3 |     87.5 |     100 |    94.3 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   96.01 |    94.15 |   96.66 |   96.01 |                   
  ...ageEmitter.ts |   95.95 |       96 |     100 |   95.95 | 52-59             
  PlanEmitter.ts   |     100 |       90 |     100 |     100 | 66                
  base-emitter.ts  |   78.26 |       75 |     100 |   78.26 | 23-24,26-28       
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   99.18 |    96.47 |     100 |   99.18 | 355-356           
 ...ession/rewrite |    91.8 |    89.13 |   94.44 |    91.8 |                   
  LlmRewriter.ts   |    82.4 |     86.2 |     100 |    82.4 | ...,88-89,166-170 
  ...Middleware.ts |   96.96 |    88.09 |     100 |   96.96 | 144,152-154       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/agent-view    |   89.03 |    81.37 |   89.09 |   89.03 |                   
  ...t-cli-argv.ts |     100 |      100 |     100 |     100 |                   
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  ...sor-client.ts |   80.38 |    72.54 |   76.66 |   80.38 | ...22-626,652-656 
  ...or-process.ts |   96.61 |    89.47 |   84.61 |   96.61 | 129-130,150-151   
  ...sor-runner.ts |    84.9 |     75.6 |      85 |    84.9 | ...44,468,471-481 
  ...sor-server.ts |   85.71 |    83.06 |   95.45 |   85.71 | ...67-468,471-488 
  ...isor-store.ts |   97.73 |    81.16 |     100 |   97.73 | ...92,594,607,643 
  ...nal-bridge.ts |   93.98 |     91.3 |   83.33 |   93.98 | 228-238           
 src/commands      |   90.81 |    79.71 |   66.66 |   90.81 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   55.55 |      100 |       0 |   55.55 | 18-22,30-40       
  extensions.tsx   |   96.77 |      100 |      50 |   96.77 | 39                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   98.66 |      100 |      50 |   98.66 | 86                
  serve.ts         |   89.84 |    77.45 |     100 |   89.84 | ...52,855-858,870 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   88.91 |    88.49 |   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.39 |   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.66 |    88.04 |   88.42 |   87.66 |                   
  agent-prompt.ts  |   93.64 |    91.71 |   97.22 |   93.64 | ...2486,2610-2690 
  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.87 |    92.52 |   96.55 |   96.87 | ...2126,2154-2176 
  cost-ledger.ts   |   94.67 |    95.86 |   78.57 |   94.67 | ...04-505,545-555 
  drive.ts         |   76.07 |    85.71 |   81.81 |   76.07 | ...90-492,497-499 
  extract-step.ts  |   91.36 |    90.62 |   88.88 |   91.36 | ...90-707,714-729 
  fetch-pr.ts      |    76.7 |    68.75 |   63.63 |    76.7 | ...95,417,450-455 
  findings.ts      |   89.35 |    89.13 |   95.45 |   89.35 | ...15-918,927-928 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  match-remote.ts  |   85.54 |     92.3 |   66.66 |   85.54 | 67-72,131-136     
  mock-provider.ts |   95.44 |    90.25 |   89.47 |   95.44 | 145,690-709       
  parse-args.ts    |   99.66 |    96.55 |     100 |   99.66 | 404               
  plan-diff.ts     |   64.04 |      100 |   66.66 |   64.04 | 127-163           
  pr-context.ts    |   81.77 |    80.86 |   92.85 |   81.77 | ...1043,1072-1074 
  presubmit.ts     |   83.75 |    92.72 |   88.88 |   83.75 | ...77-578,655-685 
  ...ish-assets.ts |   77.18 |    82.14 |   71.42 |   77.18 | ...85-531,533-544 
  repo-context.ts  |   94.92 |    90.82 |     100 |   94.92 | ...67-368,376-377 
  ...ve-anchors.ts |   77.77 |    88.88 |      75 |   77.77 | ...77-182,194-211 
  run.ts           |   82.16 |    87.12 |   91.66 |   82.16 | ...52,468-516,529 
  save-artifact.ts |    89.9 |    81.81 |   94.11 |    89.9 | ...08-311,404-407 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...59-773,775-797 
  submit.ts        |   83.77 |    83.95 |      90 |   83.77 | ...55,544,571-607 
  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 |   97.05 |    94.98 |    97.9 |   97.05 |                   
  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 |    97.14 |     100 |     100 | 513,553           
  coverage.ts      |   94.49 |    94.61 |      96 |   94.49 | ...72-489,526-537 
  deadline.ts      |    98.1 |    92.85 |     100 |    98.1 | ...77,226,543,575 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.01 |     100 |   98.73 | ...41,264,290-291 
  disk.ts          |     100 |      100 |     100 |     100 |                   
  effort.ts        |     100 |      100 |     100 |     100 |                   
  gh.ts            |   87.07 |    92.45 |   76.47 |   87.07 | ...72,309-310,337 
  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 |                   
  npm-toolchain.ts |   97.36 |    95.37 |     100 |   97.36 | ...86,409,770,787 
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |     100 |     87.5 |     100 |     100 | 92                
  prompt-record.ts |   97.88 |    93.87 |     100 |   97.88 | 260-261,267       
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  remote-match.ts  |   97.26 |    91.42 |     100 |   97.26 | 49-50             
  report.ts        |   94.68 |    93.75 |     100 |   94.68 | 189-193           
  ...ry-context.ts |     100 |    98.66 |     100 |     100 | 184               
  retirement.ts    |     100 |    92.39 |     100 |     100 | ...28,308-309,449 
  review-footer.ts |     100 |      100 |     100 |     100 |                   
  roster.ts        |     100 |    95.71 |     100 |     100 | 145,163,208       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  stale-bundle.ts  |   98.11 |    94.04 |     100 |   98.11 | 416,457,497-498   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  toolchain.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 |    96.77 |     100 |     100 | 222,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.9 |    89.84 |   96.27 |    94.9 |                   
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   89.35 |    83.56 |     100 |   89.35 | ...97-298,314-315 
  ...eMcpImport.ts |   87.91 |    81.52 |     100 |   87.91 | ...63-371,453-454 
  compile-cache.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   88.93 |    88.59 |   83.33 |   88.93 | ...2451,2453-2461 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.02 |    88.88 |     100 |   83.02 | ...02-209,232-240 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |    96.5 |    93.58 |      95 |    96.5 | ...85-586,640-641 
  ...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.4 |       50 |     100 |    97.4 | 240-243           
  ...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 
  session-id.ts    |     100 |      100 |     100 |     100 |                   
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   91.27 |    92.64 |      90 |   91.27 | ...1030,1032-1033 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...ngsWatcher.ts |   95.54 |    88.34 |     100 |   95.54 | ...28,277-278,293 
  ...d-env-keys.ts |     100 |      100 |     100 |     100 |                   
  ...l-settings.ts |     100 |      100 |     100 |     100 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...precedence.ts |   98.79 |     92.3 |     100 |   98.79 | 62                
  ...tedFolders.ts |   92.53 |     93.4 |     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.81 |    66.19 |   55.26 |   44.81 |                   
  ...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.67 |    60.71 |   46.66 |   37.67 | ...38-650,659-688 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |    98.1 |    94.16 |   95.23 |    98.1 |                   
  ...putAdapter.ts |   97.98 |    93.23 |   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.53 |    83.79 |   90.47 |   87.53 |                   
  ...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 | 679               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...op-mcp-ipc.ts |   81.06 |    73.68 |   94.11 |   81.06 | ...37-242,267,289 
  ...nt-service.ts |    94.1 |    86.89 |     100 |    94.1 | ...75-477,484,486 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   88.59 |    93.68 |   96.29 |   88.59 | ...95-207,451-454 
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   87.27 |     85.2 |     100 |   87.27 | ...10,816-820,838 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   92.42 |    84.44 |    97.1 |   92.42 | ...1466,1520-1524 
  ...e-grouping.ts |     100 |    94.28 |     100 |     100 | 71,137            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |    90.1 |    77.83 |   94.73 |    90.1 | ...1014,1021-1026 
  daemon-logger.ts |    82.2 |    77.42 |   91.76 |    82.2 | ...1720,1747-1753 
  ...y-pressure.ts |     100 |    96.96 |     100 |     100 | 135               
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.57 |     90.8 |     100 |   98.57 | ...1411,1413-1414 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |   93.37 |    85.18 |     100 |   93.37 | 114-117,195-202   
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...d-provider.ts |   92.06 |    86.95 |     100 |   92.06 | ...72,287-293,316 
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  ...h-settings.ts |   94.94 |    90.41 |     100 |   94.94 | ...30,708,724,734 
  fast-path.ts     |   90.99 |    81.38 |   95.45 |   90.99 | ...33-542,608-609 
  ...ration-sse.ts |   42.55 |    33.33 |     100 |   42.55 | 23-24,30,33-56    
  health-query.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-144             
  ...e-observer.ts |   89.89 |    83.24 |      96 |   89.89 | ...11-512,541-543 
  ...back-binds.ts |     100 |    88.88 |     100 |     100 | 32                
  ...-workspace.ts |    90.9 |    85.71 |     100 |    90.9 | ...30-131,142-143 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |     100 |    86.95 |     100 |     100 | 36,66,92          
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.68 |    88.29 |     100 |   92.68 | ...89-291,303-305 
  ...qwen-serve.ts |   84.01 |    80.02 |   75.43 |   84.01 | ...7461,7467-7468 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   94.22 |    87.96 |     100 |   94.22 | ...27,531-532,572 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   90.59 |    91.18 |   71.81 |   90.59 | ...2720,2734-2738 
  ...-admission.ts |   98.24 |    94.73 |     100 |   98.24 | 79-80,303-304     
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    95.23 |     100 |     100 | 12                
  ...-admission.ts |   98.71 |    89.65 |     100 |   98.71 | 68                
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |    93.3 |    76.83 |     100 |    93.3 | ...20,823,836-838 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   92.18 |    88.37 |     100 |   92.18 | ...21-224,267-270 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.58 |       79 |     100 |   98.58 | 106,134,174,177   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   93.89 |     87.5 |     100 |   93.89 | ...18-519,525-526 
  ...e-remember.ts |   98.23 |    92.51 |     100 |   98.23 | ...36,340-345,386 
  ...te-runtime.ts |   83.98 |    90.29 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |   91.63 |    84.26 |     100 |   91.63 | ...71-273,306-307 
 ...serve/acp-http |   78.25 |    80.02 |    93.1 |   78.25 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.55 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   73.85 |     77.7 |   94.23 |   73.85 | ...5227,5275-5281 
  index.ts         |   82.23 |    80.11 |   91.07 |   82.23 | ...2341,2425-2426 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   87.73 |    76.21 |    97.5 |   87.73 |                   
  ...r-emulator.ts |   93.27 |    77.77 |     100 |   93.27 | ...53-256,282-283 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |    6.12 |    57.89 |   46.15 |    6.12 |                   
  ...helpers.d.mts |       0 |        0 |       0 |       0 | 1                 
  ...e-helpers.mjs |   97.64 |    70.96 |     100 |   97.64 | 22-23             
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-124             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  ...re-server.mjs |       0 |        0 |       0 |       0 | 1-59              
  ...ols-smoke.mjs |       0 |        0 |       0 |       0 | 1-268             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
  ...al-chrome.mjs |       0 |        0 |       0 |       0 | 1-223             
 src/serve/fs      |   86.46 |    81.42 |     100 |   86.46 |                   
  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 |    74.21 |     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.27 |    80.56 |     100 |   86.27 | ...2699,2709-2710 
 src/serve/live    |   78.01 |    69.54 |   90.61 |   78.01 |                   
  ...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.8 |   97.01 |   82.67 | ...1319,1351-1353 
  ...-installer.ts |    64.3 |    82.35 |   80.76 |    64.3 | ...45-446,460-472 
  ...oordinator.ts |   75.99 |    65.18 |   85.71 |   75.99 | ...1883,1974-1975 
  ...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.3 |    59.78 |   93.33 |    86.3 | ...1160,1184-1191 
  ...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.59 |    80.08 |   94.73 |   85.59 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...nel-notify.ts |   86.45 |       88 |     100 |   86.45 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.71 |    83.33 |     100 |   85.71 | 101-108           
  goals.ts         |   98.92 |     90.9 |     100 |   98.92 | 146               
  health.ts        |   99.09 |    91.17 |     100 |   99.09 | 147               
  live-setup.ts    |   33.33 |     37.5 |      50 |   33.33 | ...18-123,130-135 
  live.ts          |    82.4 |    71.42 |     100 |    82.4 | ...-94,96-101,121 
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.29 |    82.94 |   92.59 |   87.29 | ...1275,1318-1319 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   85.72 |    82.14 |    91.3 |   85.72 | ...4825,4827-4828 
  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  |    91.8 |    88.97 |   96.85 |    91.8 |                   
  access-log.ts    |   98.68 |     97.1 |     100 |   98.68 | 115,186           
  ...er-helpers.ts |   63.82 |    77.96 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    81.81 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.29 |       75 |     100 |   97.29 | 17                
  ...r-response.ts |   86.54 |    72.48 |     100 |   86.54 | ...49,766,829-838 
  fs-factory.ts    |     100 |    94.54 |     100 |     100 | 42,103,159        
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...list-cache.ts |   98.58 |    94.87 |     100 |   98.58 | 156-157           
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.13 |    95.09 |     100 |   95.13 | ...66-168,423-428 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |      95 |     87.5 |     100 |      95 | 182-188           
  ...on-archive.ts |   89.55 |    87.72 |   97.14 |   89.55 | ...32-836,888-889 
  ...ion-export.ts |     100 |    94.44 |     100 |     100 | 64                
  session-list.ts  |    97.1 |     92.5 |     100 |    97.1 | ...95,798-804,964 
  telemetry.ts     |   99.03 |    97.44 |     100 |   99.03 | ...31,645,787-789 
 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.15 |    75.52 |   67.03 |   73.15 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   74.35 |    72.04 |   68.57 |   74.35 | ...4181,4297-4303 
  ...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.51 |       74 |    62.5 |   70.51 | ...12,339,392-397 
  ...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 | ...28-129,137-146 
  ...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 | 48-53,68-71,92-97 
  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.73 |    79.32 |   79.85 |   71.73 |                   
  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       |   81.19 |    69.23 |      50 |   81.19 | ...02,240,262-267 
  ...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  |   84.26 |    82.94 |      80 |   84.26 | ...2215,2236,2332 
  ...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.31 |    95.06 |      50 |   96.31 | ...01,464-468,471 
  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.82 |    86.66 |     100 |   93.82 | ...17,279,299-301 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   95.62 |    87.09 |     100 |   95.62 | ...24-125,273-275 
  ...inalImage.tsx |     100 |    93.93 |     100 |     100 | 75,129            
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |   55.05 |    69.09 |      50 |   55.05 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   69.48 |    33.33 |   66.66 |   69.48 | ...51,269,277-279 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    42.3 |    68.69 |   73.68 |    42.3 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |       0 |        0 |       0 |       0 | 1-166             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |   85.34 |    84.91 |   92.98 |   85.34 |                   
  ...sksDialog.tsx |   81.87 |    82.77 |   85.71 |   81.87 | ...1853,1965-1971 
  ...TasksPill.tsx |   78.84 |    94.28 |     100 |   78.84 | 64,109-129        
  ...gentPanel.tsx |   97.08 |    86.31 |     100 |   97.08 | 132,442-446,520   
  agent-forest.ts  |    99.2 |    93.93 |     100 |    99.2 | 258               
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
  ...e-overlay.tsx |    88.2 |    76.47 |     100 |    88.2 | ...36-138,140-142 
 ...nts/extensions |   84.32 |    76.78 |   83.33 |   84.32 |                   
  ...gerDialog.tsx |   82.15 |    76.08 |     100 |   82.15 | ...91-198,258,260 
  TabBar.tsx       |   97.29 |    88.88 |     100 |   97.29 | 33                
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   46.26 |       85 |   58.82 |   46.26 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |       0 |        0 |       0 |       0 | 1-145             
  ...nListStep.tsx |   75.26 |    88.37 |   66.66 |   75.26 | ...53,174,203-209 
  ...electStep.tsx |       0 |        0 |       0 |       0 | 1-83              
  ...nfirmStep.tsx |   16.32 |      100 |       0 |   16.32 | 28-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
 ...xtensions/tabs |   71.92 |    68.21 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.44 |   83.33 |   75.49 | ...77,782-783,820 
  SourcesTab.tsx   |   71.67 |    70.47 |   77.77 |   71.67 | ...28,547,621-633 
 ...tensions/views |   50.97 |    52.38 |   20.83 |   50.97 |                   
  ...tionsView.tsx |   73.75 |    56.36 |   66.66 |   73.75 | ...30,353,369-374 
  ...tionsView.tsx |   43.45 |    44.82 |    6.66 |   43.45 | ...98-405,408-420 
  ...etailView.tsx |    9.56 |      100 |       0 |    9.56 | 40-67,70-158      
 ...mponents/hooks |   87.11 |    81.37 |   91.89 |   87.11 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.91 |    63.44 |   70.58 |   40.91 |                   
  ...ealthPill.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   90.26 |    86.89 |   85.57 |   90.26 |                   
  ...ionDialog.tsx |   89.23 |     84.9 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   94.11 |    95.91 |   76.92 |   94.11 | ...47-349,352-355 
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   81.73 |     65.9 |      75 |   81.73 | ...10-214,222,245 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   91.87 |    82.63 |     100 |   91.87 | ...49-651,658-660 
  ...upMessage.tsx |   98.38 |    95.38 |     100 |   98.38 | 188-191,422       
  ToolMessage.tsx  |   93.06 |    86.32 |   93.75 |   93.06 | ...1037,1082-1084 
 ...ponents/shared |   86.29 |    82.41 |   94.17 |   86.29 |                   
  ...ctionList.tsx |     100 |      100 |      75 |     100 |                   
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  ...rBoundary.tsx |     100 |      100 |     100 |     100 |                   
  MaxSizedBox.tsx  |   84.71 |    86.95 |      90 |   84.71 | ...67-568,685-686 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...ontroller.tsx |     100 |    83.33 |     100 |     100 | 73,93-95          
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   81.48 |    84.84 |     100 |   81.48 | 46-66,73-76       
  StaticRender.tsx |     100 |      100 |     100 |     100 |                   
  TextInput.tsx    |    80.8 |    67.24 |      80 |    80.8 | ...36-240,252-258 
  ...ontroller.tsx |     100 |    81.81 |     100 |     100 | 59-62             
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   91.49 |    86.66 |   83.33 |   91.49 | ...18-846,859,959 
  text-buffer.ts   |   85.98 |    81.81 |   97.91 |   85.98 | ...2664,2762-2763 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |       0 |        0 |       0 |       0 |                   
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-681             
 ...ents/subagents |       0 |        0 |       0 |       0 |                   
  constants.ts     |       0 |        0 |       0 |       0 | 1-71              
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |       0 |        0 |       0 |       0 | 1-190             
  types.ts         |       0 |        0 |       0 |       0 | 1-125             
  utils.ts         |       0 |        0 |       0 |       0 | 1-102             
 ...bagents/create |       0 |        0 |       0 |       0 |                   
  ...ionWizard.tsx |       0 |        0 |       0 |       0 | 1-299             
  ...rSelector.tsx |       0 |        0 |       0 |       0 | 1-85              
  ...onSummary.tsx |       0 |        0 |       0 |       0 | 1-331             
  ...tionInput.tsx |       0 |        0 |       0 |       0 | 1-177             
  ...dSelector.tsx |       0 |        0 |       0 |       0 | 1-63              
  ...nSelector.tsx |       0 |        0 |       0 |       0 | 1-58              
  ...EntryStep.tsx |       0 |        0 |       0 |       0 | 1-78              
  ToolSelector.tsx |       0 |        0 |       0 |       0 | 1-253             
 ...bagents/manage |   14.14 |    53.19 |    37.5 |   14.14 |                   
  ...ctionStep.tsx |       0 |        0 |       0 |       0 | 1-103             
  ...eleteStep.tsx |       0 |        0 |       0 |       0 | 1-62              
  ...tEditStep.tsx |       0 |        0 |       0 |       0 | 1-124             
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |       0 |        0 |       0 |       0 | 1-73              
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-341             
 ...mponents/views |    70.1 |    72.89 |   61.11 |    70.1 |                   
  ContextUsage.tsx |   71.49 |    64.86 |      80 |   71.49 | ...30-436,473-567 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   84.16 |    81.83 |   85.13 |   84.16 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.83 |    68.51 |   42.85 |   93.83 | ...44,281-285,317 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   85.65 |    84.85 |     100 |   85.65 | ...1612-1614,1620 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   80.77 |       80 |    92.3 |   80.77 | ...31-434,443-446 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...edContext.tsx |     100 |      100 |      50 |     100 |                   
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 156-157           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 235-236           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
  ...rtContext.tsx |     100 |      100 |     100 |     100 |                   
 src/ui/daemon     |   88.35 |    73.51 |   95.45 |   88.35 |                   
  ...ui-adapter.ts |   88.35 |    73.51 |   95.45 |   88.35 | ...74,792-793,879 
 src/ui/editors    |       0 |        0 |       0 |       0 |                   
  ...ngsManager.ts |       0 |        0 |       0 |       0 | 1-67              
 src/ui/hooks      |   85.49 |    83.02 |   87.79 |   85.49 |                   
  ...dProcessor.ts |   85.53 |    85.13 |     100 |   85.53 | ...-970,1017-1018 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...87-288,293-294 
  ...dProcessor.ts |   85.75 |     68.4 |   81.81 |   85.75 | ...1464,1485-1489 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.ts |     100 |      100 |     100 |     100 |                   
  ...ng-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...oice-input.ts |   92.36 |    81.95 |   66.66 |   92.36 | ...00,502-503,658 
  ...ke-repaint.ts |     100 |      100 |     100 |     100 |                   
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      52 |    63.63 |     100 |      52 | ...59,67-70,76-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   86.44 |    88.48 |     100 |   86.44 | ...14-515,525-541 
  ...ifications.ts |   87.82 |    96.77 |     100 |   87.82 | 138-152           
  ...tIndicator.ts |   88.28 |    81.57 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.89 |    77.55 |     100 |   94.89 | 164-168,257,263   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   95.53 |    83.01 |     100 |   95.53 | ...64-165,289-292 
  ...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 |   85.29 |    80.28 |    92.3 |   85.29 | ...36,351-361,441 
  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.34 |    77.14 |     100 |   95.34 | 124-125,227-232   
  ...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.32 |    93.93 |     100 |   97.32 | ...18-422,518-525 
  ...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  |   92.65 |    84.69 |     100 |   92.65 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   93.75 |    91.66 |     100 |   93.75 | 41-42,71-72       
  ...tion-state.ts |     100 |      100 |     100 |     100 |                   
  ...ction-text.ts |   92.85 |    92.59 |     100 |   92.85 | 30-34,114-115     
  ...selection.tsx |   90.26 |    75.32 |     100 |   90.26 | ...75-376,392-393 
 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.56 |    85.64 |   95.76 |   87.56 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   80.07 |     75.6 |     100 |   80.07 | ...70,274,332-333 
  ...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 |   93.63 |    81.77 |   95.23 |   93.63 | ...47-750,803-808 
  ...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.24 |     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          |   91.33 |    79.03 |     100 |   91.33 | ...73,273,277-278 
  ...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 |   95.19 |      100 |   88.88 |   95.19 | 121-126           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...e-renderer.ts |   90.61 |    83.44 |     100 |   90.61 | ...80,482-484,607 
  ...ize-reflow.ts |     100 |     92.3 |     100 |     100 | 57,62,209,217,347 
  ...wOptimizer.ts |     100 |    94.11 |     100 |     100 | 33,76             
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.94 |    95.49 |   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.41 |    87.07 |   92.57 |   81.41 |                   
  ...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.52 |    57.35 |   76.92 |   45.52 | ...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 |   93.51 |    90.95 |   96.96 |   93.51 |                   
  cleanup.ts       |   92.59 |    93.75 |     100 |   92.59 | ...02-205,209-211 
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |      93 |    88.34 |      95 |      93 | ...57-359,411-415 
  throttledOnce.ts |   95.95 |    93.93 |     100 |   95.95 | 77-78,153-154     
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   87.85 |    86.36 |    89.4 |   87.85 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   90.38 |    84.54 |   94.85 |   90.38 |                   
  ...transcript.ts |   87.63 |    83.52 |     100 |   87.63 | ...80,588,594-598 
  ...ent-resume.ts |   85.59 |    77.55 |   83.33 |   85.59 | ...1793-1797,1800 
  ...ound-tasks.ts |   94.63 |    90.13 |   96.38 |   94.63 | ...1773,1793-1796 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   94.79 |     87.7 |     100 |   94.79 | ...1067,1081-1083 
  ...w-snapshot.ts |   92.12 |    77.14 |     100 |   92.12 | ...65,189,196-198 
 src/agents/arena  |   76.32 |    67.71 |   78.94 |   76.32 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.11 |    64.51 |   78.57 |   75.11 | ...1887,1893-1894 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   78.09 |    85.23 |   76.28 |   78.09 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    90.9 |    85.36 |   93.33 |    90.9 | ...70,672,674-675 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |    91.1 |    86.68 |   89.23 |    91.1 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   85.07 |     76.8 |   77.77 |   85.07 | ...2291,2337-2339 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    89.41 |   83.33 |   93.49 | ...96-497,500-501 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.34 |      100 |    92.3 |   98.34 | 81-82             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...-scheduler.ts |   97.43 |    96.36 |     100 |   97.43 | 128-130           
  ...ow-journal.ts |   91.76 |    75.86 |     100 |   91.76 | ...38-139,179-181 
  ...chestrator.ts |    92.4 |       90 |   83.78 |    92.4 | ...1862,1911-1914 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...low-runner.ts |   94.85 |     87.5 |   92.85 |   94.85 | ...93,260,280-283 
  ...ow-sandbox.ts |   96.85 |    91.28 |     100 |   96.85 | ...1705,1711-1712 
  ...flow-saved.ts |   96.51 |    94.36 |     100 |   96.51 | 134-135,234-237   
  ...flow-stall.ts |    97.9 |    83.33 |     100 |    97.9 | 138-139,236       
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   82.04 |    84.17 |   88.97 |   82.04 |                   
  TeamManager.ts   |   72.02 |    79.41 |   79.24 |   72.02 | ...1632,1655-1656 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   96.02 |    87.23 |     100 |   96.02 | 352-358           
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   89.24 |    82.82 |     100 |   89.24 | ...-994,1038-1039 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    94.26 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    84.21 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.08 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   84.98 |    87.13 |   75.37 |   84.98 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   84.29 |    86.85 |   73.79 |   84.29 | ...8350,8354-8355 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.39 |    91.57 |   88.23 |   94.39 | ...45-446,449-450 
 ...nfirmation-bus |   98.27 |    97.14 |     100 |   98.27 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   92.37 |    88.09 |   93.29 |   92.37 |                   
  baseLlmClient.ts |    88.4 |     83.8 |   81.81 |    88.4 | ...59,672,678-680 
  client.ts        |   92.05 |     87.4 |   91.66 |   92.05 | ...3987,4085-4086 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...96-497,542-548 
  ...lScheduler.ts |   90.04 |    84.69 |   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.25 |   88.54 |   88.07 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  context-usage.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.57 |    91.48 |     100 |   96.57 | ...20-321,402,404 
  ...entHandler.ts |   95.57 |    84.76 |   94.73 |   95.57 | ...1040-1041,1051 
  hookPlanner.ts   |   87.55 |    85.54 |   86.66 |   87.55 | ...22-226,233-244 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.65 |    72.34 |   66.66 |   62.65 | ...70-771,780-781 
  hookSystem.ts    |   87.64 |     98.5 |   70.83 |   87.64 | ...58-759,765-766 
  ...HookRunner.ts |   79.06 |    66.66 |      80 |   79.06 | ...33-434,452-456 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   94.19 |    84.37 |   81.81 |   94.19 | ...76-384,458-459 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   94.87 |    88.88 |     100 |   94.87 | ...84,325,327-329 
  ssrfGuard.ts     |   86.45 |    87.91 |     100 |   86.45 | ...85,289-295,301 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.25 |    96.09 |   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.86 |   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 |    81.81 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |    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.6 |   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 |    74.04 |   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 | 81-83,86-88,90-93 
  ...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.69 |     84.6 |   96.92 |   89.69 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |    98.5 |     87.5 |     100 |    98.5 | 81-82,105,476-477 
  ...ionService.ts |   97.51 |    96.15 |     100 |   97.51 | ...,929,1072-1080 
  ...ingService.ts |   91.41 |    85.15 |   95.65 |   91.41 | ...2116,2143-2144 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    93.93 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.17 |    90.45 |      98 |   94.17 | ...1333,1736-1737 
  cronTasksFile.ts |   96.31 |    91.81 |     100 |   96.31 | ...11,336-337,483 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |    97.5 |    96.07 |     100 |    97.5 | 349-350,363-364   
  ...temService.ts |    92.8 |    84.68 |   94.11 |    92.8 | ...53,479-486,531 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    73.7 |    68.49 |   95.83 |    73.7 | ...2196,2225-2226 
  ...on-service.ts |   87.38 |       72 |     100 |   87.38 | ...01-305,343-344 
  ...references.ts |   98.39 |    88.76 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.26 |    97.35 |     100 |   98.26 | ...13-714,761-762 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.52 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |    97.3 |    91.22 |     100 |    97.3 | ...53-454,611-612 
  ...ttachments.ts |   97.74 |    90.85 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   90.95 |    78.75 |     100 |   90.95 | ...78,963-964,992 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |    98.5 |    94.11 |    90.9 |    98.5 | 64-65             
  ...ipt-reader.ts |   94.55 |    89.78 |   96.66 |   94.55 | ...1353-1354,1422 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   82.45 |    74.11 |   97.61 |   82.45 | ...2433,2445-2448 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.79 |    83.72 |   97.18 |   88.79 | ...2477,2553-2573 
  sessionTitle.ts  |   94.26 |    73.21 |     100 |   94.26 | ...45-248,279-280 
  ...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 
  ...ite-origin.ts |     100 |    93.33 |     100 |     100 | 32                
  ...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.73 |    83.97 |   84.83 |   81.73 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.08 |    80.95 |     100 |   99.08 | 185,199           
  ...on-tracing.ts |   76.31 |    74.62 |   73.68 |   76.31 | ...80,387-389,405 
  ...attributes.ts |   95.15 |    87.27 |     100 |   95.15 | ...97-198,216-217 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |   96.85 |    85.71 |     100 |   96.85 | 170-173           
  ...-exporters.ts |   65.78 |    83.33 |   55.55 |   65.78 | ...04-105,108-109 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |       99 |     100 |     100 | 99                
  ...ai-request.ts |   87.52 |    92.79 |   83.78 |   87.52 | ...55-561,564-570 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |    99.1 |    95.72 |      95 |    99.1 | 145,369-370       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   60.03 |    76.51 |   66.07 |   60.03 | ...1484,1501-1521 
  metrics.ts       |   80.37 |    82.35 |   80.95 |   80.37 | ...1150,1153-1164 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   91.06 |    87.15 |   68.75 |   91.06 | ...32,482-483,499 
  sdk.ts           |   82.12 |    90.47 |   66.66 |   82.12 | ...90-194,232-254 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |    91.1 |    88.68 |   96.77 |    91.1 | ...1737,1768-1771 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  trace-context.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.56 |    88.63 |     100 |   98.56 | 52,101            
  types.ts         |      83 |    94.32 |   86.36 |      83 | ...1467,1471-1478 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.23 |     80.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.76 |    86.77 |   81.25 |   82.76 | ...45-746,865-915 
  ...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.71 |    77.08 |   81.25 |   85.71 | ...96-912,958-959 
  ...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 | ...5036,5099-5100 
  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.72 |    84.92 |   88.88 |   86.72 | ...25-828,865-900 
  zoom-image.ts    |   95.76 |    93.75 |      90 |   95.76 | 54-59,203-204     
 src/tools/agent   |   87.22 |    87.68 |   88.69 |   87.22 |                   
  agent.ts         |   85.84 |    86.59 |   86.31 |   85.84 | ...4315,4337-4347 
  fork-profile.ts  |   93.65 |       90 |     100 |   93.65 | ...33-134,171-174 
  fork-subagent.ts |   98.73 |       95 |     100 |   98.73 | 101-102,173       
 ...tools/artifact |   95.78 |    92.51 |   88.63 |   95.78 |                   
  artifact-tool.ts |   91.46 |    88.46 |   71.42 |   91.46 | ...13-314,322-325 
  ...-publisher.ts |     100 |    85.71 |     100 |     100 | 32                
  ...-publisher.ts |   96.74 |    97.72 |    87.5 |   96.74 | 29-30,156-157     
  html.ts          |     100 |    96.77 |     100 |     100 | 122               
  ...-publisher.ts |     100 |       80 |     100 |     100 | 30                
  oss-publisher.ts |    98.1 |    91.48 |     100 |    98.1 | 43-45             
  publisher.ts     |     100 |      100 |     100 |     100 |                   
 ...s/computer-use |   90.21 |    82.17 |   78.08 |   90.21 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   80.11 |       90 |   77.77 |   80.11 | ...97,242-243,274 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    96.3 |    85.71 |     100 |    96.3 | 75-76,184,252-258 
 ...tools/workflow |   86.51 |    84.81 |      75 |   86.51 |                   
  workflow.ts      |   86.51 |    84.81 |      75 |   86.51 | ...67,512,514-515 
 src/utils         |   92.89 |    89.62 |   96.88 |   92.89 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.94 |    92.47 |     100 |   94.94 | ...43-544,651-655 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.45 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.88 |    94.11 |      95 |   95.88 | ...98-499,511-524 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   83.01 |    95.03 |    61.9 |   83.01 | ...62-378,382-388 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  file-identity.ts |     100 |      100 |     100 |     100 |                   
  fileUtils.ts     |   94.87 |    92.95 |   96.15 |   94.87 | ...1907,1915-1916 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |     100 |      100 |     100 |     100 |                   
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.39 |    94.28 |     100 |   94.39 | ...29-132,343-348 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  git-branches.ts  |    91.6 |    84.21 |    92.3 |    91.6 | ...90,405-410,570 
  ...fig-safety.ts |   97.01 |       80 |     100 |   97.01 | 53-54             
  gitDiff.ts       |   95.19 |    81.36 |     100 |   95.19 | ...1073,1419-1420 
  gitDirect.ts     |   98.84 |    94.28 |     100 |   98.84 | 234,318           
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |   78.02 |    81.25 |   85.71 |   78.02 | ...22-123,147-198 
  github-prs.ts    |   95.74 |    82.27 |     100 |   95.74 | 216,314-322       
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  image-view.ts    |   95.12 |    93.33 |     100 |   95.12 | ...68-172,240-244 
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   95.27 |     93.1 |     100 |   95.27 | ...16-317,359-362 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   94.01 |       90 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.21 |     100 |   98.96 | 153               
  ...kerChecker.ts |    90.9 |    91.66 |     100 |    90.9 | 73-79             
  notebook.ts      |   94.57 |    89.91 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   91.66 |    89.74 |     100 |   91.66 | ...26-228,251-256 
  osc8.ts          |   54.26 |    64.86 |   83.33 |   54.26 | ...72-195,197-257 
  partUtils.ts     |     100 |    98.64 |     100 |     100 | 211               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.61 |    92.42 |     100 |   93.61 | ...62-563,565-567 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   71.15 |       86 |     100 |   71.15 | ...-90,96-101,147 
  ...noreParser.ts |   92.63 |    91.66 |     100 |   92.63 | ...77-178,197-198 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |   96.98 |    87.15 |     100 |   96.98 | ...87-688,763-764 
  readManyFiles.ts |   95.75 |    80.86 |     100 |   95.75 | ...05,558,568-572 
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...67,558-559,577 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.08 |     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 |       64 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.13 |    96.42 |     100 |   96.13 | ...34-339,341-346 
  ...pt-records.ts |    87.5 |    86.13 |     100 |    87.5 | ...76-480,510-525 
  truncation.ts    |   90.56 |    90.43 |     100 |   90.56 | ...35-443,480-486 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   96.74 |    91.04 |     100 |   96.74 | ...69,196,299-301 
  xml.ts           |    97.8 |    87.69 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    77.27 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.94 |    80.72 |   94.73 |   83.94 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |    82.9 |    76.81 |   95.08 |    82.9 | ...1563,1597-1598 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  ignore.ts        |     100 |    97.36 |     100 |     100 | 187               
  result-cache.ts  |     100 |    93.75 |     100 |     100 | 49                
 ...uest-tokenizer |   69.76 |    75.47 |   85.29 |   69.76 |                   
  ...eTokenizer.ts |   65.72 |    74.02 |    92.3 |   65.72 | ...65-466,479-533 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |   76.92 |      100 |   33.33 |   76.92 | 46-49,56-57       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

Full read of the three production files plus tests at the reviewed head. The approach matches my independent proposal: stay inside the existing anchor/focus model, record a word/line mode plus the original span in anchorSpanRef on multi-click, and re-derive the range from anchor-to-current-span on every move/release — no parallel state machine, ~130 production lines, nothing extraneous. The two-direction logic in extendSpanDrag (anchor at span start vs end depending on which side of the original span the cursor sits), the whitespace fallback to a single cell, and the state resets (clearSelection, the single-click path, and post-extension on release) all trace correctly.

The Critical from my last pass is fixed and regression-tested:

  • Single-cell no-drag multi-click copies again. The collapsed-span check at release now reads isEmpty || isBareClick, where isBareClick is isCollapsed && mode === 'char' — exactly the mode-aware guard that was missing. A plain double-click on a (or triple-click on a one-cell line) no longer clears before copying; pinned by copies a single-character word on a no-drag double-click and copies a one-cell line on a no-drag triple-click.
  • The second regression, found later in a real terminal rather than in this diff's first review: moving the copy to release alone let a streaming B1 repaint clear the selection between press and release, so nothing copied. Copy-at-press restores it, and keeps the double-click copy when streaming clears the selection before release pins it.

Both minor notes from last pass are addressed too: the orphaned selectSpan is removed (its only call site was this diff), and the stale release-branch comment is gone. New behaviors are each pinned: release-without-move still extends to the release cell, backward drags, the triple-click chain surviving pointer drift during a held double-click (that is what the conditional lastClickRef clear is for), and the multi-row trailing-space copy matching the pre-existing getSelectedText contract.

One non-blocking nit, echoed from the maintainer's verification: copying at press and release doubles clipboard writes for plain multi-clicks (2 writes for a double-click, 4 for a triple-click), which shows up as duplicate entries in clipboard-history tools. Final content is always correct. Skipping the release-time copy when it is byte-identical to the press copy would tidy it without touching the streaming fix — fine as a follow-up, not a merge blocker. Also purely cosmetic: the PR body still says "11 tests" where this file now has 22.

sequenceDiagram
    participant P1 as User
    participant P2 as Mouse handler
    participant P3 as SelectionState
    P1->>P2: double or triple click, hold
    P2->>P3: start plus extend the span, record mode and anchor, copy at press
    P1->>P2: move or release while held
    P2->>P3: extendSpanDrag snaps focus to the word or line under the cursor
    P2->>P3: on release, copy again (survives a streaming clear before release)
Loading

Testing evidence

This is an unattended CI-path run, so I did not build or drive the product; the evidence below is the PR's own CI (fetched via API for the reviewed commit) plus the maintainer's independently performed local verification, attributed as such.

All checks on the reviewed commit are green — 27 successes, zero failures (the 115 skipped entries and the one pending review-address check-run are bot orchestration, not this PR's CI; the only pending workflow run is a pull_request_review-event autofix job, also not PR CI). Notably Test (ubuntu-latest, Node 22.x) — the check that was red on earlier heads of this PR — now passes.

Check Conclusion
Qwen Code CI (workflow) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
build-cli ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success

The CI suite pins the change — the 12 new tests target behaviors that are all no-ops on the merge base (drag-after-multi-click extension, release-cell extension, collapsed-span copies), so a green suite here is meaningful rather than diff-blind. Beyond that, maintainer @wenshao performed two rounds of local real-environment verification, the latest against exactly this head (aaaae0d749): a real pty driven with raw SGR mouse sequences, a 13-gesture BASE-vs-HEAD matrix (every drag-extension row no-op on BASE, functional on HEAD), a 12/12 press-hold × token-gap timing sweep under streaming, and a mutation probe — deleting only the new press-time copy line empties the clipboard, proving the fix load-bearing rather than defensive — plus 69/69 unit tests across the selection directory. That is the maintainer's own hands-on evidence, not something this run re-executed; it is the strongest possible confirmation for a TUI gesture change, and it covers the one platform (macOS) beyond the author's Linux unit runs.

中文说明

代码审查

在受审 head 上完整通读了三个生产文件与测试。方案与我独立设想一致:不引入平行状态机,沿用现有 anchor/focus 模型——多点点击时在 anchorSpanRef 记录 word/line 模式与原始 span,move/release 时按「锚点 span → 当前位置 span」重推范围;约 130 行生产代码,无夹带。extendSpanDrag 的双向逻辑(依光标在原始 span 哪一侧决定 anchor 取 span 首或尾)、落在空白时回退单格、以及各处状态复位(clearSelection、单击路径、release 扩展后清 ref)都推演无误。

上一轮的 Critical 已修复并有回归测试

  • **单格无拖动多点点击恢复复制。**release 处的折叠判断改为 isEmpty || isBareClick,其中 isBareClickisCollapsed && mode === 'char'——正是此前缺失的模式感知守卫。单纯双击单字符(或三击单格行)不再先清除后复制;由 copies a single-character word on a no-drag double-clickcopies a one-cell line on a no-drag triple-click 钉住。
  • 第二个回归是后来在真实终端里发现的:只把复制挪到 release 时,流式 B1 重绘会在 press 与 release 之间清掉选择导致复制丢失。press 时复制修复了它,keeps the double-click copy when streaming clears the selection before release 将其钉住。

上轮两条 minor 也已处理:孤儿 selectSpan 已删除(唯一调用点就在本 diff),过时的 release 分支注释已移除。每个新行为都有测试钉住:无 move 时 release 仍扩展到释放格、反向拖动、按住双击期间指针漂移后三击链不断(这正是条件性清除 lastClickRef 的用途)、多行拖动保留被覆盖行尾随空格(符合既有 getSelectedText 约定)。

一条非阻塞小问题,与维护者验证结论一致:press 与 release 各复制一次使纯多点点击的剪贴板写入翻倍(双击 2 次、三击 4 次),剪贴板历史类工具会出现连续重复条目;最终内容始终正确。release 时若与 press 已复制内容逐字节相同则跳过即可收敛,且不触及流式修复——适合作为后续项,不阻塞合并。另纯观感:PR 描述仍写 "11 tests",该文件现为 22 个。

(时序图见英文正文,流程为:按住多击 → 记录模式与锚点并 press 复制 → move/release 吸附到光标下的词/行 → release 再复制一次。)

测试证据

本次为无人值守 CI 路径运行,不构建、不驱动产品本体;以下证据为 PR 自身 CI(通过 API 按受审 commit 拉取)+ 维护者独立完成的本地真实环境验证(如实注明归属)。

受审 commit 上所有检查全绿——27 项成功、0 失败(115 项 skipped 与唯一 pending 的 review-address check-run 均为机器人编排任务,非本 PR CI;唯一 pending 的 workflow run 是 pull_request_review 事件的 autofix 任务,同样非 PR CI)。值得注意的是 Test (ubuntu-latest, Node 22.x)——该检查在本 PR 更早的 head 上曾红——现已通过。

(CI 明细表见英文正文标记区域。)

CI 套件确实钉住了本次改动——12 个新测试针对的行为在 merge base 上全部无效(多点点击后拖动扩展、释放格扩展、折叠 span 复制),因此这里的绿灯有意义而非对 diff 视而不见。在此之上,维护者 @wenshao 做了两轮本地真实环境验证,最新一轮正是针对本 head(aaaae0d749):真实 pty + 原始 SGR 鼠标序列驱动,13 手势 BASE 对 HEAD 矩阵(所有拖动扩展行 BASE 无效、HEAD 生效),流式输出下 12/12 按住时长 × token 间隔时序扫描,以及变异测试——仅删除新增的 press 时复制一行即剪贴板全空,证明该修复真正起作用而非防御性冗余——外加 selection 目录 69/69 单测。这是维护者本人的上手证据,本次运行未重复执行;对 TUI 手势类改动这是最强确认,也补齐了作者 Linux 单测之外的 macOS 平台。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — clean re-review; both prior blockers are fixed and regression-tested, CI is green on the reviewed commit, and the only remaining nit is the cosmetic duplicate-clipboard-write that the verifying maintainer explicitly declined to block on.

Stepping back: this one earned its landing. The gesture gap was real — the base code plainly returns from the multi-click branch without entering drag mode — and it was verified the hard way, not just asserted: a maintainer drove a real pty with raw SGR mouse sequences and showed every drag-extension gesture is a no-op on the merge base. The implementation matches what I would have proposed independently (mode + anchor-span ref on top of the existing anchor/focus model, no parallel state machine), and the review process demonstrably worked — my last pass flagged that a single-cell no-drag double-click silently stopped copying, and the fix came back as exactly the mode-aware guard that was missing, with regression tests for both it and the streaming-repaint regression that only surfaced in a real terminal later. The diff is minimal (132 production lines, dead code removed rather than orphaned), the comments explain the non-obvious why (press-time copy, release-cell extension, click-chain preservation), and every new behavior has a test that would fail on the merge base.

The 4 rather than 5 is the remaining polish: plain multi-clicks now write to the clipboard twice (press and release), which leaves duplicate entries in clipboard-history tools. Content is always correct, the verifying maintainer flagged it as non-blocking with a concrete optional fix (skip the release copy when byte-identical), and I agree it belongs in a follow-up rather than holding this merge.

Approving, pinned to the reviewed commit. ✅ @qwen-code-dev-bot

中文说明

置信度:4/5 —— 复审干净:上一轮两个阻塞项均已修复并有回归测试,受审 commit 的 CI 全绿,唯一剩余的小问题是重复剪贴板写入(纯观感),且做验证的维护者已明确表示不以此阻塞。

整体来看:这个 PR 配得上合并。手势缺口真实存在——base 代码在多点点击分支直接返回、未进入拖动模式——而且是硬验证出来的,不是口头断言:维护者在真实 pty 里用原始 SGR 鼠标序列驱动,证明所有拖动扩展手势在 merge base 上无效。实现与我独立设想一致(在现有 anchor/focus 模型上加 mode + 锚点 span 引用,不建平行状态机);评审流程也确实起了作用——我上一轮指出单格无拖动双击会悄悄不再复制,回来的修复正是缺失的那个模式感知守卫,且连同后来只在真实终端暴露的流式重绘回归一起补了回归测试。diff 最小(132 行生产代码,死代码被删除而非遗留),注释解释的是不明显的「为什么」(press 时复制、释放格扩展、连击链保留),每个新行为都有在 merge base 上必失败的测试。

给 4 而非 5 是剩下的一点打磨:纯多点点击现在会写两次剪贴板(press 与 release),剪贴板历史工具会留下重复条目。内容始终正确,验证维护者已标记为非阻塞并给出具体可选修复(release 时与 press 内容逐字节相同则跳过),我同意放后续项而不是卡本次合并。

批准,锚定到受审 commit。✅

Qwen Code · qwen3.8-max

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Needs one focused fix — see my Stage 2 notes above. 🙏

Plain double-click on a single-character word (and triple-click on a one-cell line) no longer copies: the now-drag-capable word/line select flows through left-release, where a 1-cell span is collapsed and cleared before copySelection() runs. Suggested fix: only treat a collapsed release as a bare click in char mode (selection.isCollapsed && selection.mode === 'char'), plus a no-drag double-click regression test. Optional cleanup: selectSpan is now dead code, and the release-branch comment is stale.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🔀 Base updated: red check(s) [label] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [label] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@github-actions github-actions Bot added the review/self-reported The linked issue was opened by the PR author (self-reported) label Aug 8, 2026
@qwen-code-dev-bot

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

Copy link
Copy Markdown
Collaborator Author

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

中文说明

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

Drag-capable word/line selections moved the copy from press to release,
but the release path cleared any collapsed range before copying, so a
plain double-click on a single-character word (or triple-click on a
one-cell line) stopped copying. Only treat a collapsed release as a
bare click in char mode; in word/line mode a collapsed range is a real
single-cell span. Also drop the now-unused selectSpan helper and a
stale release-branch comment.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Autofix review round — PR #8739

Feedback points and dispositions

  1. [Required — correctness] Single-character word / one-cell line no longer copies on a plain multi-click (CHANGES_REQUESTED) — Fixed.
    • Verified root cause: this PR made word/line selections drag-capable and moved the copy from press time to left-release. For a 1-cell span, extendSpanDrag leaves anchor == focus, and the old if (selection.isCollapsed || selection.isEmpty) check cleared the selection before copySelection() ran — so a plain double-click on a single-character word (and a triple-click on a one-cell line) copied nothing.
    • Fix: a collapsed release is only treated as a bare click in char mode (selection.isCollapsed && selection.mode === 'char'), as suggested. In word/line mode a collapsed range is a real single-cell span and is now highlighted and copied. applyHighlight already highlights collapsed word/line spans (mode !== 'char'), so no other changes were needed.
  2. [Suggested] No-drag double-click regression test — Added copies a single-character word on a no-drag double-click to use-text-selection.test.tsx: press/release/press/release on a one-character word, asserting both the highlight range and the clipboard payload.
  3. [Optional cleanup] selectSpan is dead code — Confirmed zero callers (including tests) and removed it from SelectionState.
  4. [Optional cleanup] Stale release-branch comment — Removed "Word/line click-selects are not drags; leave them intact."; word/line multi-clicks now enter a dragging state, so the comment no longer described the guard.

Changed files

  • packages/cli/src/ui/selection/use-text-selection.tsx — collapse-on-release fix; stale comment removed
  • packages/cli/src/ui/selection/selection-state.ts — dead selectSpan removed
  • packages/cli/src/ui/selection/use-text-selection.test.tsx — regression test added

Commit: 99af051dd9fix(ui): copy single-cell word/line selections on release

Conflict notes

None (--conflict false; no merge performed).

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check on the three touched files — passed
  • npx vitest run src/ui/selection/use-text-selection.test.tsx src/ui/selection/selection-text.test.ts (in packages/cli) — 27 passed
  • npx vitest run src/ui/selection/ (in packages/cli, full selection module) — 5 files, 59 passed
  • Integration tests not run: the changed behavior (the mouse-selection hook) is fully exercised by the unit harness and is not only reachable through the bundled CLI.
中文说明

Autofix 审查轮次 — PR #8739

反馈点及处理结果

  1. 【必须 — 正确性】单个字符的单词 / 只有一个单元格的行在普通多次点击时不再被复制CHANGES_REQUESTED)— 已修复。
    • 已核实根因:本 PR 使单词/整行选择支持拖拽,并将复制操作从按下时移到了 left-release。对于只有一个单元格的选区,extendSpanDrag 会使 anchor 与 focus 重合,而旧的 if (selection.isCollapsed || selection.isEmpty) 判断会在 copySelection() 执行前清除选区 — 因此对单字符单词的普通双击(以及对只有一个单元格的行的三击)不会复制任何内容。
    • 修复方式:按建议,仅在字符模式下将收起(collapsed)的释放视为单纯点击(selection.isCollapsed && selection.mode === 'char')。在单词/整行模式下,收起的选区是真实的单单元格选区,现在会正常高亮并复制。applyHighlight 本已对收起的单词/整行选区(mode !== 'char')进行高亮,无需其他改动。
  2. 【建议】无拖拽双击回归测试 — 在 use-text-selection.test.tsx 中新增 copies a single-character word on a no-drag double-click:对单字符单词执行 按下/释放/按下/释放,同时断言高亮范围和剪贴板内容。
  3. 【可选清理】selectSpan 为死代码 — 确认无任何调用方(包括测试)后,已从 SelectionState 中删除。
  4. 【可选清理】释放分支中的过期注释 — 删除了 "Word/line click-selects are not drags; leave them intact.";单词/整行多次点击现在会进入拖拽状态,该注释已不再准确描述此守卫条件。

变更文件

  • packages/cli/src/ui/selection/use-text-selection.tsx — 修复释放时收起选区被清除的问题;删除过期注释
  • packages/cli/src/ui/selection/selection-state.ts — 删除死代码 selectSpan
  • packages/cli/src/ui/selection/use-text-selection.test.tsx — 新增回归测试

提交:99af051dd9fix(ui): copy single-cell word/line selections on release

冲突说明

无(--conflict false;未执行任何合并)。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • 对三个变更文件执行 npx prettier --check — 通过
  • npx vitest run src/ui/selection/use-text-selection.test.tsx src/ui/selection/selection-text.test.ts(在 packages/cli 中)— 27 个测试通过
  • npx vitest run src/ui/selection/(在 packages/cli 中,整个 selection 模块)— 5 个文件,59 个测试通过
  • 未运行集成测试:本次变更的行为(鼠标选择 hook)已由单元测试完整覆盖,并非只能通过打包后的 CLI 验证。

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

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


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

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

⚠️ This run could not certify that any of this diff was reviewed. Suggestions are inline. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite (real-terminal mouse behavior) did not run locally. Not reviewed: the executable-script lint — could not read the plan to check the gate. Not reviewed: coverage — the plan could not be used (ENOENT: no such file or directory, open '.qwen/tmp/qwen-review-pr-8739-fetch.json'), so this run cannot show that any of the diff was read. Not reviewed: verification — could not check that Step 4 and Step 5 ran (ENOENT: no such file or directory, open '.qwen/tmp/qwen-review-pr-8739-fetch.json'). ⚠️ The reverse-audit findings file could not be read at compose time, so this run cannot show its findings were verified.

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

Comment on lines +324 to +325
const spanDrag = spanDragRef.current;
spanDragRef.current = null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] Release-time word/line drag extension is dead code. In the left-release handler, spanDragRef.current is set to null before extendSpanDrag(...) is called, and extendSpanDrag's first statement re-reads the ref (const spanDrag = spanDragRef.current; if (!spanDrag) return;) — so the release cell's coordinates are never applied to a word/line drag.

Failure scenario: double/triple-click a word/line and drag, then release at a cell where the terminal emitted no final move event (SGR button tracking samples motion — fast flicks and coalesced events land here). The selection and copied text stop at the last processed move instead of the release point; with no move at all between the multi-click and the release, the range never extends past the clicked word/line. The char-drag path handles exactly this case and has a dedicated test ('includes the release cell when no move event is emitted'); the word/line path silently lacks the same protection, and the three new tests pass because each emits move at the release position first. Probe-verified at HEAD: release at grid 9 with no move yields ex: 2 / 'foo'; with a move at 6 then release at 9, ex: 6 / 'foo bar'; reordering the null after the call fixes both.

Suggested change
const spanDrag = spanDragRef.current;
spanDragRef.current = null;
const spanDrag = spanDragRef.current;
const mapped = mapEvent(event);
if (mapped) {
if (spanDrag) {
extendSpanDrag(clampToViewport(mapped.point, mapped.rect));
} else {
selection.extend(clampToViewport(mapped.point, mapped.rect));
}
}
spanDragRef.current = null;
中文说明

(严重) release 时的词/行拖动扩展是死代码:left-release 处理器先把 spanDragRef.current 置为 null,再调用 extendSpanDrag(...),而 extendSpanDrag 第一行又去读这个 ref(const spanDrag = spanDragRef.current; if (!spanDrag) return;)——因此释放点的坐标从未被应用到词/行拖动的选区上。

触发场景:双击/三击选中词/行后拖动,若终端在释放位置没有发出最后一个 move 事件(SGR 按钮追踪为采样式上报,快速甩动、事件合并都会命中此情形),选区与复制文本会停在最后一次 move 的位置而不是释放点;若多点点击与释放之间完全没有 move,选区根本不会扩展。字符拖动路径专门处理了该场景并有对应测试('includes the release cell when no move event is emitted'),词/行路径缺失同等保护;三个新测试都在释放前先发了 move,因此全部通过。已在 HEAD 用探针验证:无 move 直接释放到 grid 9 时选区止于 ex: 2(复制 'foo');先 move 到 6 再释放到 9 时止于 ex: 6(复制 'foo bar');把置空语句移到调用之后两处均修复。

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

Comment on lines +273 to +276
selection.mode = mode;
selection.anchor = { x: span.sx, y: span.sy };
selection.focus = { x: span.ex, y: span.ey };
selection.dragging = true;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The multi-click press now sets selection.dragging = true (the deleted selectSpan set it false), which exposes the multi-click chain to the move handler's lastClickRef.current = null. Any held-button drift now breaks the triple-click chain or extends a plain double-click's copy range.

Failure scenario: under SGR button tracking a move fires whenever the pointer crosses a cell while the button is held. Probe-verified: press1→release1→press2→move(3,1)→release2→press3→release3 yields a null final selection — a 1-cell drift move between press2 and release2 kills the triple-click (press3 computes count=1, char mode). The same mechanism extends a jittery plain double-click's copy range (e.g. 'foo' → 'foo bar'). The old code ignored moves after a multi-click select, so both were impossible.

中文说明

(建议) 多点点击按下时现在设置 selection.dragging = true(被删除的 selectSpan 设置的是 false),这使多点点击链条暴露在 move 处理器的 lastClickRef.current = null 之下:按住期间任何指针漂移都会破坏三击链条,或扩大普通双击的复制范围。

触发场景:SGR 按钮追踪下,按住按键期间指针每跨过一个单元格就会触发 move。探针已验证:press1→release1→press2→move(3,1)→release2→press3→release3 最终得到空选区——press2 与 release2 之间 1 格的漂移就破坏了三击(press3 计算 count=1,进入字符模式)。同样的机制会让抖动的普通双击复制范围扩大(如 'foo' 变成 'foo bar')。旧代码会忽略多点点击之后的 move,这两种情况都不会发生。

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

Comment on lines +202 to +207
? (wordSpanAt(frame, point.x, point.y) ?? {
sx: point.x,
sy: point.y,
ex: point.x,
ey: point.y,
})

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 whitespace fallback collapses focus to the single whitespace cell, so stopping a word/line drag over a gap puts whitespace inside the copied range.

Failure scenario: probe-verified — double-click 'foo' in 'foo bar baz' and drag to the space at grid x=3: selection becomes 0-3 and the clipboard gets 'foo ' with a trailing space; dragging left onto the space before the anchor word copies ' bar'. A natural gesture (stopping a word-drag on a gap) produces clipboard text the user must strip. The single-cell fallback is documented as deliberate, but the whitespace-in-clipboard harm is concrete.

中文说明

(建议) 空白回退会把焦点坍缩到单个空白单元格,导致词/行拖动停在空隙处时复制文本带上空白。

触发场景(探针已验证):在 'foo bar baz' 中双击 'foo' 并拖到 grid x=3 的空格处——选区变为 0-3,剪贴板得到带尾随空格的 'foo ';向左拖到锚点词前的空格则会复制出带前导空格的 ' bar'。在空隙处停住词拖动是自然手势,却产生需要用户手工清理的剪贴板内容。单格回退在注释中是有意为之,但空白进入复制范围的实际损害是具体的。

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Declined. The single-cell fallback when the cursor is over whitespace is documented intentional behavior of this feature (see the comment above extendSpanDrag), and it matches how mainstream editors handle word-drag onto a gap — the gap is included in the selection and thus in the copied text. Changing that would be a behavior/scope decision beyond issue #8738. The behavior is now pinned by a new test ('falls back to the cursor cell when a word drag lands on whitespace'), so any future change is a deliberate one rather than a silent regression.

中文说明

已拒绝。光标位于空白单元格时回退到单格是本特性文档中明确记载的有意行为(见 extendSpanDrag 上方的注释),也与主流编辑器按词拖动到空隙处的处理一致——空隙会被纳入选区,因而也会进入复制文本。修改该行为属于超出 issue #8738 范围的行为/范围决策。该行为现已由新测试('falls back to the cursor cell when a word drag lands on whitespace')钉住,未来任何改动都将是有意为之,而不是静默回归。

Comment on lines +273 to +276
selection.mode = mode;
selection.anchor = { x: span.sx, y: span.sy };
selection.focus = { x: span.ex, y: span.ey };
selection.dragging = true;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The multi-click path writes SelectionState's four fields directly, duplicating the existing start(point, mode) + extend(point) API — whose mode parameter has no other production caller.

Failure scenario: two code paths now perform the same state transition differently; a future invariant added to start() (validation, clamping, mode handling) silently never applies to word/line selections. The PR itself is the demonstrated cost: selectSpan was a copy of start()'s semantics that drifted one line (dragging = falsetrue) and had to be deleted, and the inline copy already carries that modified line.

Suggested change
selection.mode = mode;
selection.anchor = { x: span.sx, y: span.sy };
selection.focus = { x: span.ex, y: span.ey };
selection.dragging = true;
selection.start({ x: span.sx, y: span.sy }, mode);
selection.extend({ x: span.ex, y: span.ey });
中文说明

(建议) 多点点击路径直接写 SelectionState 的四个字段,重复实现了已有的 start(point, mode) + extend(point) API——而该 API 的 mode 参数在生产代码中没有其他调用方。

影响:两条代码路径以不同方式执行同一状态转换;未来加在 start() 上的不变量(校验、钳制、模式处理)将静默地不作用于词/行选择。本 PR 本身就是代价的证明:selectSpanstart() 语义的复制品,漂移了一行(dragging = falsetrue)最终被删除,而内联的复制已经带着这一行改动。

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

Comment on lines +244 to +245
handler(makeEvent('move', 6, 2)); // drag to line 1
handler(makeEvent('left-release', 6, 2));

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] Test gaps: the backward drag branch (cursorAfter === false) has zero coverage, and the triple-click line-drag test cannot discriminate line-snapping from plain char extension.

Failure scenario: the backward branch (anchor set to the span's end a.ex/a.ey, focus to the current span's start current.sx/current.sy) holds the most distinct logic in the diff; a regression there ships green — dragging a double-clicked 'baz' left to 'foo' would select 'foo' instead of 'foo bar baz'. Mutation-verified: de-wiring both extendSpanDrag call sites to selection.extend leaves this line-drag test green, so line-mode snapping could degrade to per-cell extension and the suite would not catch it.

中文说明

(建议) 测试缺口:向后拖动分支(cursorAfter === false)零覆盖;三击行拖动测试无法区分行吸附与普通字符扩展。

影响:向后分支(锚点取原 span 的终点 a.ex/a.ey、焦点取当前 span 的起点 current.sx/current.sy)是本 diff 中最独特的逻辑;该分支一旦回归,套件依然全绿——把双击选中的 'baz' 向左拖到 'foo' 时只会选中 'foo' 而不是 'foo bar baz'。变异验证:把两处 extendSpanDrag 调用替换为 selection.extend 后,本行拖动测试仍然通过,说明行模式吸附退化为逐格扩展也不会被套件发现。

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

Comment on lines +273 to +276
selection.mode = mode;
selection.anchor = { x: span.sx, y: span.sy };
selection.focus = { x: span.ex, y: span.ey };
selection.dragging = 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] Word/line copy moved to release is silently dropped whenever the selection is invalidated mid-hold: the frame-subscriber clearSelection() sets dragging = false, after which the release early-returns before copySelection().

Failure scenario: double-click a word (or triple-click a line) in the VP viewport while output is streaming. Press2 selects the word with dragging = true; the next rendered frame with new content runs the subscriber (sameViewportContent differs from baselineFrameRefclearSelection()dragging = false). The subsequent left-release hits if (!selection.dragging) { return; } — the release never reaches copySelection(). Probe-verified: firing a frame change between press2 and release yields 0 clipboard calls with the PR code, 1 call with copySelection() restored at press. The old code copied the word at press2, so the copy was guaranteed at selection time. The same drop occurs on any scroll/resize/isActive flip during the hold. (Distinct from the 'release never arrives' case: here the release arrives and is fully processed.)

中文说明

(建议) 词/行复制移到 release 后,若按住期间选区被失效清理(流式终端),复制会被静默丢弃:帧订阅者的 clearSelection()dragging 置为 false,随后的 release 在 copySelection() 之前就提前返回。

触发场景:输出流式滚动时在 VP 视口里双击选中一个词(或三击选中一行)。第 2 次按下以 dragging = true 选中词;下一帧新内容使订阅者触发(sameViewportContentbaselineFrameRef 不同 → clearSelection()dragging = false)。随后的 left-release 命中 if (!selection.dragging) { return; }——永远到不了 copySelection()。探针已验证:在 press2 与 release 之间触发一帧内容变化,PR 代码下剪贴板调用为 0 次,恢复按下时复制后为 1 次。旧代码在 press2 即复制,选区生成时复制即已保证。按住期间的滚动/缩放/isActive 翻转同样会触发此丢弃。(与『release 事件未送达』不同:此处 release 已到达且被完整处理。)

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Declined. Copy-on-release is this PR's documented design ("Copy happens on release, matching char drags", commit 99af051dd9), and with it an interrupted word/line drag behaves exactly like an interrupted char drag: the selection is cleared on streamed content/scroll/resize and nothing is copied. That clear-on-change behavior is the established B1 scope for all drags, not a regression introduced for word/line mode specifically. Restoring press-time copy also directly conflicts with this round's rc:3741007226 finding, which pins release-only copy as the intended semantic, and would write the clipboard even when the gesture is never completed. The release-only behavior is now pinned by toHaveBeenCalledTimes(1) assertions. If a maintainer prefers the pre-PR guarantee for multi-clicks interrupted mid-hold, it is a one-line change (copySelection() in the count >= 2 press branch) — flagging for maintainer preference.

中文说明

已拒绝。仅在释放时复制是本 PR 明确记载的设计("Copy happens on release, matching char drags",提交 99af051dd9),在此设计下,被打断的词/行拖动与被打断的字符拖动行为完全一致:流式内容/滚动/缩放时选区被清除,不产生复制。这种内容变化即清除的行为是 B1 范围内所有拖动的既定语义,并非词/行模式特有的新回归。恢复按下时复制还会与本轮 rc:3741007226 意见直接冲突——该意见要求把"仅释放时复制"钉住为预期语义,且按下即复制意味着手势尚未完成时就已写入剪贴板。仅释放时复制的行为现已由 toHaveBeenCalledTimes(1) 断言钉住。如果维护者更希望保留 PR 之前"按住期间被打断的多点点击也保证复制"的语义,只需一行改动(在 count >= 2 按下分支加回 copySelection())——已标注供维护者定夺。

Comment on lines +324 to +325
const spanDrag = spanDragRef.current;
spanDragRef.current = null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] Release-time word/line extension is a guaranteed no-op. The handler captures spanDragRef.current into the local spanDrag and then nulls the ref (these lines) before calling extendSpanDrag below; extendSpanDrag starts with const spanDrag = spanDragRef.current; if (!spanDrag) return; — it re-reads the same ref instead of receiving the caller's captured record, so at release time the call always early-returns and the release cell is never applied to a word/line selection. Independently flagged by 8 review agents; probe-verified at the reviewed commit.

Failure scenario: double-click foo in foo bar baz, hold, and release over baz with no move covering the release cell — terminals/tmux coalesce or drop button-tracked motion, and the char-mode sibling explicitly supports and tests this exact shape ('includes the release cell when no move event is emitted') → the selection stays at the anchor word and only foo is copied instead of foo bar baz. Even when moves do arrive, whenever the release cell differs from the last move cell the final word/line is silently dropped from the copied text. The three new tests pass only because each emits a move at the exact release cell.

Suggested fix — clear the ref after the extension (or pass the captured record into extendSpanDrag(point, spanDrag)), plus a word-mode release-without-move regression test mirroring the existing char-mode one:

const spanDrag = spanDragRef.current;
const mapped = mapEvent(event);
if (mapped) {
  if (spanDrag) {
    extendSpanDrag(clampToViewport(mapped.point, mapped.rect));
  } else {
    selection.extend(clampToViewport(mapped.point, mapped.rect));
  }
}
spanDragRef.current = null;
中文说明

[严重] 释放时的按词/按行扩展必然失效。handler 先把 spanDragRef.current 取到局部变量 spanDrag,随后(这几行)就把 ref 置空,之后才调用下面的 extendSpanDrag;而 extendSpanDrag 开头是 const spanDrag = spanDragRef.current; if (!spanDrag) return; —— 它重新读同一个 ref,而不是接收调用方已捕获的记录,因此释放时该调用必然提前返回,释放点永远不会应用到词/行选择上。8 个评审 agent 独立发现此问题,并已在被审提交上用探针测试验证。

失败场景:双击 foo bar baz 中的 foo,按住,在没有 move 事件覆盖释放单元格的位置释放——终端/tmux 会合并或丢弃按键拖动事件,字符模式的同类场景明确支持且有测试('includes the release cell when no move event is emitted')→ 选择停留在锚点词上,只复制了 foo 而不是 foo bar baz。即使有 move 事件到达,只要释放单元格与最后一个 move 单元格不同,最后一个词/行也会被悄悄丢出复制文本。三条新测试之所以通过,仅因为每条都在释放单元格处先发了一次 move

建议修复:在扩展之后再清空 ref(或把已捕获的记录传入 extendSpanDrag(point, spanDrag)),并仿照现有字符模式测试补一条词模式“无 move 释放”的回归测试:

const spanDrag = spanDragRef.current;
const mapped = mapEvent(event);
if (mapped) {
  if (spanDrag) {
    extendSpanDrag(clampToViewport(mapped.point, mapped.rect));
  } else {
    selection.extend(clampToViewport(mapped.point, mapped.rect));
  }
}
spanDragRef.current = null;

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

Comment on lines +328 to +332
if (spanDrag) {
extendSpanDrag(clampToViewport(mapped.point, mapped.rect));
} else {
selection.extend(clampToViewport(mapped.point, mapped.rect));
}

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 drag-extension dispatch block is pasted twice in this PR — here in the release handler and in the move handler (~lines 311-315) — and the two copies source the span-drag state differently: the move copy reads spanDragRef.current, this copy reads a captured local. That divergence is precisely what makes the release-side call a no-op (see the Critical above).

Concrete cost: any future change to drag-extension dispatch (a new selection mode, different clamping) must be applied to both copies and can silently diverge again — the drift already produced the release-path bug in this PR.

Suggested fix — extract one helper used by both handlers, with the release handler nulling the ref after the call:

const extendActiveDrag = (point: { x: number; y: number }) => {
  if (spanDragRef.current) extendSpanDrag(point);
  else selectionRef.current.extend(point);
};
中文说明

[建议] 拖动扩展分发块在本 PR 中贴了两份——释放 handler 这一份和 move handler(约 311-315 行)一份——且两份读取拖动状态的方式不同:move 那份读 spanDragRef.current,这一份读捕获的局部变量。正是这个分歧让释放侧调用成了空操作(见上面的严重问题)。

具体代价:未来任何对拖动扩展分发的改动(新的选择模式、不同的视口裁剪)都必须同时改两份,而且仍可能悄悄再次分叉——本次 PR 中这种分叉已经制造了释放路径的缺陷。

建议修复:抽取一个两处共用的辅助函数,由释放 handler 在调用之后再把 ref 置空:

const extendActiveDrag = (point: { x: number; y: number }) => {
  if (spanDragRef.current) extendSpanDrag(point);
  else selectionRef.current.extend(point);
};

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

Comment on lines +202 to +207
? (wordSpanAt(frame, point.x, point.y) ?? {
sx: point.x,
sy: point.y,
ex: point.x,
ey: point.y,
})

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 single-cell whitespace-fallback span literal is written verbatim in both arms of this ternary (word branch here, line branch ~lines 208-213); the arms differ only in the span function called. The sibling multi-click ternary in handleMouse uses the flat shape with no per-arm duplication.

Concrete cost: the fallback semantics — documented in the comment above extendSpanDrag — are encoded in two places; changing the fallback (e.g. snapping differently in line mode) requires editing both branches, and the copies can drift.

Suggested fix — hoist the fallback out of the ternary:

const current =
  (spanDrag.mode === 'word'
    ? wordSpanAt(frame, point.x, point.y)
    : lineSpanAt(frame, point.y)) ?? {
    sx: point.x,
    sy: point.y,
    ex: point.x,
    ey: point.y,
  };
中文说明

[建议] 单格空白回退 span 字面量在这个三元表达式的两个分支中逐字重复(词分支在此处,行分支约在 208-213 行),两个分支只有调用的 span 函数不同。handleMouse 中同类的多点点击三元表达式使用的是扁平写法,没有逐分支重复。

具体代价:extendSpanDrag 上方注释里明确记载的回退语义被写在两处;修改回退逻辑(例如行模式下采用不同吸附)必须同时编辑两个分支,两份副本可能逐渐分叉。

建议修复:把回退提到三元表达式之外:

const current =
  (spanDrag.mode === 'word'
    ? wordSpanAt(frame, point.x, point.y)
    : lineSpanAt(frame, point.y)) ?? {
    sx: point.x,
    sy: point.y,
    ex: point.x,
    ey: point.y,
  };

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

Comment on lines +273 to +276
selection.mode = mode;
selection.anchor = { x: span.sx, y: span.sy };
selection.focus = { x: span.ex, y: span.ey };
selection.dragging = 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] This block is the body of SelectionState.selectSpan — deleted by this same PR — copied inline with one field flipped (dragging = true instead of false). Char drags still transition through the class's methods (start/extend/finish) while span drags now poke four public fields directly, so selection transitions no longer have a single home.

Concrete cost: any invariant or behavior later added to SelectionState transitions (mode handling, validation, state resets) applies to the char path automatically but must be re-applied manually here; the split ref lifecycle already contributed to the release-path no-op flagged above.

Suggested fix: keep the transition on SelectionState, e.g. restore the method as startSpan(span, mode) (the old selectSpan body with this.dragging = true) and call it from the handler.

中文说明

[建议] 这个块就是被本 PR 删除的 SelectionState.selectSpan 方法体,被内联复制过来并翻转了一个字段(dragging = true 取代原来的 false)。字符拖动仍然通过类的方法(start/extend/finish)转换状态,而 span 拖动现在直接写四个公开字段,选择状态转换不再有唯一的归口。

具体代价:以后任何加在 SelectionState 状态转换上的不变量或行为(模式处理、校验、状态复位)都会自动作用于字符路径,却必须在这里手工再补一遍;上面指出的释放路径空操作就与这种被拆开的 ref 生命周期有关。

建议修复:把状态转换保留在 SelectionState 上,例如将方法恢复为 startSpan(span, mode)(即原 selectSpan 方法体但 this.dragging = true),由 handler 调用。

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

Comment on lines +217 to +219
selection.anchor = cursorAfter
? { x: a.sx, y: a.sy }
: { x: a.ex, y: a.ey };

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 backward-drag branch of extendSpanDrag (the cursorAfter === false assignments here and below) is executed by none of the three new tests — every test drags forward. A mutation swapping the two branches' anchor/focus values survives all current tests.

Failure scenario: double-click baz in foo bar baz (anchorSpan 8..10), drag left to foo and release. The correct code anchors at (10,0)/focuses (0,0) → normalized 0..10 → copies foo bar baz; the mutant anchors at (8,0)/focuses (2,0) → normalized 2..8 → copies o bar b — a truncated, wrong clipboard payload on every backward word/line drag, shipping green.

Suggested fix — add a mirror-image test: double-click at x=9 on makeFrame('foo bar baz'), move/release at x=1, expect setSelection last called with {sx: 0, sy: 0, ex: 10, ey: 0} and copyToClipboard with 'foo bar baz' (plus a line-wise backward variant).

中文说明

[建议] extendSpanDrag 的反向拖动分支(此处及下方 cursorAfter === false 的赋值)没有被三条新测试中的任何一条执行——所有测试都向前拖动。若把两个分支的 anchor/focus 取值互换,该变异能通过当前全部测试。

失败场景:双击 foo bar baz 中的 baz(anchorSpan 8..10),向左拖到 foo 后释放。正确代码锚定 (10,0)/聚焦 (0,0) → 归一化 0..10 → 复制 foo bar baz;变异体锚定 (8,0)/聚焦 (2,0) → 归一化 2..8 → 复制 o bar b —— 每次反向按词/按行拖动都会复制被截断的错误文本,而 CI 全绿。

建议修复:补一条镜像测试——在 makeFrame('foo bar baz') 上于 x=9 双击,在 x=1 处 move/释放,断言 setSelection 最后一次调用为 {sx: 0, sy: 0, ex: 10, ey: 0}copyToClipboard 收到 'foo bar baz'(再加一条按行反向变体)。

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

Comment on lines +208 to +213
: (lineSpanAt(frame, point.y) ?? {
sx: point.x,
sy: point.y,
ex: point.x,
ey: point.y,
});

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 whitespace fallback (wordSpanAt ?? single cell ~line 202 and, here, lineSpanAt ?? single cell) is never exercised by a test, even though a word-drag crosses a space cell on every drag between words.

Failure scenario: surviving mutations — (a) replacing the fallback with spanDrag.anchorSpan: double-click foo, drag to the space at x=3 and release; correct code extends to 0..3 (copies foo ), the mutant silently stops at 0..2 (copies foo); (b) dropping the fallback entirely: current becomes null whenever the pointer is over whitespace (word mode) or a blank row (line mode), and current.ex throws during an ordinary drag across a word boundary.

Suggested fix — add a test: double-click foo (x=1) in makeFrame('foo bar baz'), move/release on the space cell x=3, pin the expected range/text (e.g. ex: 3, copy 'foo '), plus optionally a line-mode drag onto a blank row.

中文说明

[建议] 空白回退(约 202 行的 wordSpanAt ?? 单格,以及此处的 lineSpanAt ?? 单格)没有任何测试覆盖,尽管按词拖动在词与词之间拖动时必然经过空格单元格。

失败场景:可存活的变异——(a) 把回退换成 spanDrag.anchorSpan:双击 foo,拖到 x=3 的空格并释放;正确代码扩展到 0..3(复制 foo ),变异体悄悄停在 0..2(复制 foo);(b) 完全去掉回退:指针位于空白(词模式)或空行(行模式)时 current 变为 null,一次普通的跨词拖动就会在 current.ex 上抛错。

建议修复:补一条测试——在 makeFrame('foo bar baz') 上双击 foo(x=1),在空格单元格 x=3 处 move/释放,钉住预期范围/文本(如 ex: 3、复制 'foo '),可再加一条拖到空行的按行变体。

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

ex: 10,
ey: 0,
});
expect(copyToClipboard).toHaveBeenCalledWith('foo bar baz');

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 tests never pin that the copy happens only on release — the central behavior change of this PR (the diff deletes copySelection() from the multi-click press path). toHaveBeenCalledWith passes regardless of call count or timing.

Failure scenario: a mutant that re-adds copySelection() after applyHighlight() in the count >= 2 press branch passes every assertion (press copies foo, release copies foo bar baz, toHaveBeenCalledWith matches). Observable cost: the clipboard is written at double-click time even when the user never completes the gesture (double-click then scroll away), silently restoring the pre-PR behavior the diff's own comment declares removed.

Suggested change
expect(copyToClipboard).toHaveBeenCalledWith('foo bar baz');
expect(copyToClipboard).toHaveBeenCalledWith('foo bar baz');
expect(copyToClipboard).toHaveBeenCalledTimes(1);
中文说明

[建议] 测试没有钉住“复制只发生在释放时”这一行为——而这正是本 PR 的核心行为变更(diff 从多点点击的按下分支删掉了 copySelection())。toHaveBeenCalledWith 不关心调用次数和时机,怎么调用都能通过。

失败场景:在 count >= 2 按下分支 applyHighlight() 之后重新加回 copySelection() 的变异可以通过全部断言(按下复制 foo,释放复制 foo bar baztoHaveBeenCalledWith 依然匹配)。可观察的代价:用户即使没有完成手势(双击后滚走),剪贴板也已在双击时被写入——悄悄恢复了 diff 注释宣称已移除的旧行为。

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

Comment on lines 280 to 282
recordBaseline();
applyHighlight();
copySelection();
return;

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] Removing the press-time copySelection() drops the guarantee that a completed double/triple-click always reaches the clipboard. Holding the multi-click is now the user-invited entry to the new word/line drag, so the pre-release window is deliberately long; any selection-clearing event (streamed frame update, wheel scroll) landing in it leaves nothing copied — the eventual release early-returns on !selection.dragging. A/B-verified against the merge base: the base tree copies the word at press time under this sequence; this PR copies nothing.

Failure scenario: a user double-clicks a word in an actively streaming session and holds the second press to drag by word; a streamed frame update changes viewport content before release → clearSelection() runs and the clipboard never receives the word. Before this diff a clear could drop the highlight but never the copy. The deferral is intentional ("matching char drags"), but the held window is new and user-invited.

Suggested change
recordBaseline();
applyHighlight();
copySelection();
return;
copySelection();
recordBaseline();
applyHighlight();
return;

A stationary click then re-copies the same text on release (harmless/idempotent), and a drag copies the extended range. Alternative: copy the completed span in clearSelection when mode !== 'char'.

中文说明

[建议] 删除按下时的 copySelection() 使得“一次完成的双击/三击必然进剪贴板”不再成立。按住多点点击现在是启动按词/按行拖动的用户操作入口,释放前的窗口被有意拉长;任何落在该窗口内的选择清除事件(流式帧更新、滚轮滚动)都会导致什么都不复制——最终的释放会因 !selection.dragging 提前返回。已对 merge base 做 A/B 验证:该序列下 base 在按下时就复制了该词,本 PR 则什么都不复制。

失败场景:用户在流式输出的会话中双击一个词并按住第二次点击准备按词拖动;释放前一帧流式更新改变了视口内容 → clearSelection() 执行,剪贴板永远收不到这个词。在本 diff 之前,清除可以抹掉高亮,但不会抹掉复制。复制到释放的延迟是有意的(“与字符拖动一致”),但按住窗口是新的,且由用户操作主动拉长。

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Declined, for the same reasons recorded on rc:3740996254: copy-on-release is this PR's documented design and makes interrupted word/line drags behave exactly like interrupted char drags (cleared, no copy) — the established B1 semantic for all drags. Restoring press-time copy conflicts with this round's rc:3741007226 finding, which pins release-only copy, and would write the clipboard even for gestures that never complete. The A/B-verified difference versus the merge base is real but is the documented, intentional convergence of multi-click and drag semantics; the behavior is now pinned by toHaveBeenCalledTimes(1) assertions. If a maintainer prefers the base-tree guarantee for multi-clicks interrupted mid-hold, it is a one-line change (copySelection() in the count >= 2 press branch) — flagging for maintainer preference.

中文说明

已拒绝,理由与 rc:3740996254 上的记录相同:仅在释放时复制是本 PR 明确记载的设计,它使被打断的词/行拖动与被打断的字符拖动行为完全一致(清除选区、不复制)——这是 B1 范围内所有拖动的既定语义。恢复按下时复制与本轮 rc:3741007226 意见冲突(该意见要求钉住"仅释放时复制"),且会导致从未完成的手势也写入剪贴板。A/B 验证出的与 merge base 的差异确实存在,但那是多点点击与拖动语义有意收敛的、文档中记载的结果;该行为现已由 toHaveBeenCalledTimes(1) 断言钉住。如果维护者更希望保留 base 分支上"按住期间被打断的多点点击也保证复制"的语义,只需一行改动(在 count >= 2 按下分支加回 copySelection())——已标注供维护者定夺。

The release handler cleared the span-drag record before extending the
selection, so the release cell never applied to a word/line drag when
no move event covered it. Extend first and clear after, dispatch
move/release extension through one shared helper, and keep the click
record across a held multi-click so pointer drift cannot break the
triple-click chain. Multi-click transitions now go through
SelectionState start/extend instead of direct field writes. Adds
backward-drag, release-without-move, whitespace-fallback, and
release-only-copy test coverage.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Review feedback addressed — round summary

One commit on this branch: fix(ui): apply release cell to word/line drags, keep multi-click chain.

Critical findings — fixed

  • Release-time word/line extension was a guaranteed no-op (raised independently by two reviewers): the left-release handler nulled spanDragRef before calling extendSpanDrag, which re-reads that ref, so the release cell was never applied to a word/line drag when no move covered it. Fixed by extending first and clearing the ref afterwards; move/release now dispatch through one shared extendActiveDrag helper, removing the duplicated dispatch block whose divergence caused the bug. Added a word-mode "release without move" regression test mirroring the existing char-mode one (red before the fix, green after).
  • Pointer drift broke the triple-click chain: a move during a held double-click nulled the multi-click click record, so the third press computed count=1. Span drags now keep the click record (char drags still break the chain), with a regression test reproducing the exact probe sequence (red before the fix, green after).

Suggestions — implemented

  • Extracted one extendActiveDrag helper used by both the move and release handlers.
  • Multi-click transitions now go through the existing SelectionState.start(point, mode) + extend(point) API instead of writing the four public fields directly (keeps transitions in one home, no new method added).
  • Hoisted the duplicated single-cell whitespace-fallback literal out of the word/line ternary.
  • Added backward-drag coverage (word drag left, line drag up) — previously zero coverage of the cursorAfter === false branch.
  • Strengthened the line-drag test to drag into the middle of the target line so it discriminates line-snapping from plain char extension.
  • Added a whitespace-fallback test pinning the documented single-cell behavior.
  • Pinned release-only copy with toHaveBeenCalledTimes(1) in the three multi-click tests.

Suggestions — declined (recorded, threads left open)

  • Whitespace in clipboard when a word drag stops on a gap: declined — the single-cell fallback is documented intentional behavior, matches how mainstream editors select across gaps on word-drag, and is now pinned by a test.
  • Restore press-time copy (copy dropped when the selection is cleared mid-hold): declined — release-only copy is this PR's documented design ("Copy happens on release, matching char drags"), and an interrupted word/line drag now behaves exactly like an interrupted char drag, which has always cleared and not copied under B1 scope. Restoring press-time copy also directly conflicts with this round's finding that pins release-only copy. See the thread replies; flagged for maintainer preference.

Conflicting findings note

This round contained two mutually exclusive suggestions from the automated reviewer: one asked to pin that copy happens only on release, the other asked to restore the pre-PR press-time copy. The PR's documented design and the char-drag precedent support release-only copy, so that side was implemented and the press-time restoration was declined with the reasoning above. Separately, the start()+extend() suggestion was implemented instead of the proposed new startSpan method — same goal (single home for transitions) with no new API.

The top-level note that one review run could not certify coverage of the diff is informational; nothing actionable.

Verification

Commands actually run (repo root unless noted), all after the final code state:

  • npx vitest run src/ui/selection/ (in packages/cli) — 5 files, 64/64 tests passed (was 2 failed against the pre-fix code: the release-without-move and drift-chain regression tests)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check on both touched files — passed
  • Integration tests: not run — the touched behavior (mouse selection inside the TUI) is covered by the unit suite and is not exercised through the bundled CLI or integration harness
  • Settings schema: not applicable — no settings source changed
中文说明

本轮评审意见处理摘要

本分支新增一个提交:fix(ui): apply release cell to word/line drags, keep multi-click chain

严重问题 — 已修复

  • 释放时的按词/按行扩展必然失效(两位评审者独立提出):left-release 处理器在调用 extendSpanDrag 之前就把 spanDragRef 置空,而该方法会重新读取这个 ref,因此当释放单元格没有 move 事件覆盖时,释放点永远不会应用到词/行选区。修复方式:先扩展、后置空;move/release 两处改为共用同一个 extendActiveDrag 辅助函数,消除了导致本缺陷的两份分叉的重复分发代码。并仿照现有字符模式测试补了一条词模式“无 move 释放”回归测试(修复前红、修复后绿)。
  • 指针漂移破坏三击链条:双击按住期间的 move 会把多点点击记录置空,导致第三次按下时 count=1。现在 span 拖动期间保留点击记录(字符拖动仍然断开链条),并新增一条复现探针序列的回归测试(修复前红、修复后绿)。

建议 — 已采纳

  • 抽取 move/release 两处共用的 extendActiveDrag 辅助函数。
  • 多点点击的状态转换改用现有 SelectionState.start(point, mode) + extend(point) API,不再直接写四个公开字段(状态转换归口一处,且不新增方法)。
  • 把词/行三元表达式两分支中重复的单格空白回退字面量提取到外层。
  • 补充向后拖动覆盖(词向左拖、行向上拖)——原先 cursorAfter === false 分支零覆盖。
  • 强化行拖动测试:拖到目标行的中间位置,使其能区分行吸附与普通逐格扩展。
  • 新增空白回退测试,钉住文档中记载的单格回退行为。
  • 在三个多点点击测试中用 toHaveBeenCalledTimes(1) 钉住“仅在释放时复制”。

建议 — 已拒绝(记录在案,线程保持打开)

  • 词拖动停在空隙处导致剪贴板带空白:拒绝——单格回退是文档中明确记载的有意行为,与主流编辑器按词拖动跨过空隙时的选择行为一致,且现已有测试钉住该行为。
  • 恢复按下时复制(按住期间选区被清理导致复制丢失):拒绝——仅在释放时复制是本 PR 明确记载的设计(“Copy happens on release, matching char drags”),被打断的词/行拖动现在与被打断的字符拖动行为完全一致,而字符拖动在 B1 范围内历来就是清除选区且不复制。恢复按下时复制还与本轮另一条钉住“仅释放时复制”的意见直接冲突。详见对应线程回复;已标注供维护者定夺。

意见冲突说明

本轮自动评审给出了两条互斥的建议:一条要求钉住复制只发生在释放时,另一条要求恢复 PR 之前的按下时复制。PR 的既定设计方向与字符拖动的先例都支持“仅释放时复制”,因此采纳了前者、拒绝了后者,理由已记录在上述线程中。另外,start()+extend() 建议被采纳,而没有按提议新增 startSpan 方法——目标相同(状态转换单一归口),但不引入新 API。

关于某次评审运行无法认证其覆盖了该 diff 的顶层说明:仅为信息性内容,无可操作项。

验证

实际执行的命令(除注明外在仓库根目录),均为最终代码状态下的结果:

  • npx vitest run src/ui/selection/(在 packages/cli 目录)——5 个文件,64/64 测试全部通过(修复前代码上有 2 条失败:无 move 释放与漂移链条两条回归测试)
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • 对两个改动文件执行 npx prettier --check —— 通过
  • 集成测试:未运行——改动的行为(TUI 内的鼠标选择)由单元测试覆盖,不经过打包后的 CLI 或集成测试框架执行
  • 设置 schema:不适用——未改动任何设置源

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

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

中文说明

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

@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 — no blockers. Suggestions are inline.

中文说明

已审查——无阻断问题。 建议见行内评论。

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

Comment on lines +103 to +106
const spanDragRef = useRef<{
mode: 'word' | 'line';
anchorSpan: { sx: number; sy: number; ex: number; ey: number };
} | null>(null);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] Span-drag lifecycle state duplicates SelectionState: this inline literal re-declares the span shape already exported as NormalizedSelection (the exact return type of wordSpanAt/lineSpanAt), spanDragRef.mode duplicates selection.mode, and the invariant "spanDragRef non-null ⟺ a word/line drag is active" is maintained by hand at four sites (span press, char press, clearSelection, release — with load-bearing ordering) — Concrete cost: a future selection-lifecycle path that updates SelectionState but forgets spanDragRef (Escape-to-clear, programmatic clear on dialog open) leaves a stale anchor span + mode, so the next drag silently extends word/line-wise against the stale span instead of char-extending. All current paths are covered today — this is maintenance cost, not a live bug. Minimal fix: use the shared type and drop the duplicated mode (dispatch on selection.mode); deeper fix: move the anchor span into SelectionState, reset by start()/clear().

import { SelectionState, type NormalizedSelection } from './selection-state.js';

const spanDragRef = useRef<{
  mode: 'word' | 'line';
  anchorSpan: NormalizedSelection;
} | null>(null);
中文说明

(建议) 词/行拖动的生命周期状态与 SelectionState 重复:此处内联字面量重新声明了已导出为 NormalizedSelection 的 span 形状(即 wordSpanAt/lineSpanAt 的确切返回类型);spanDragRef.modeselection.mode 重复;不变式「spanDragRef 非空 ⟺ 词/行拖动进行中」靠四处手工维护(词/行按下、字符按下、clearSelection、释放——其中释放处的置空顺序有讲究)。具体代价:未来任何更新 SelectionState 却忘记 spanDragRef 的选择生命周期路径(Escape 清除、打开对话框时程序化清除)都会留下陈旧的锚点 span 与 mode,下一次拖动将按词/行对着陈旧 span 静默扩展,而不是按字符扩展。当前所有路径均已覆盖——这是维护成本,不是现行缺陷。最小修复:改用共享类型,并用 selection.mode 分发以去掉重复的 mode;更彻底的做法:把锚点 span 移入 SelectionState,由 start()/clear() 统一重置。

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

Comment on lines +200 to +202
const current = (spanDrag.mode === 'word'
? wordSpanAt(frame, point.x, point.y)
: lineSpanAt(frame, point.y)) ?? {

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 mode→span-resolver dispatch is written twice: extendSpanDrag ternary-dispatches wordSpanAt/lineSpanAt here, and the multi-click press branch (~lines 270-273) carries a second ternary doing the same — that copy predates this PR (it fed the deleted selectSpan); this diff adds the second copy — Concrete cost: if span-resolution semantics change later (fallback adjusted, a new granularity added), both sites must change in lockstep; missing one yields a silently inconsistent selection where the multi-click anchor span resolves under different rules than the held-drag extension. This exact drift shape — pasted dispatch diverging between handlers — produced the release-path no-op Critical earlier in this PR's history. Extract one shared helper next to its constituents:

// selection-span.ts
export function spanAtForMode(
  frame: ReadonlyFrame | null,
  mode: 'word' | 'line',
  point: { x: number; y: number },
): NormalizedSelection | null {
  return mode === 'word'
    ? wordSpanAt(frame, point.x, point.y)
    : lineSpanAt(frame, point.y);
}
中文说明

(建议) mode→span 解析器的分发写了两份:extendSpanDrag 在此处用三元表达式分发 wordSpanAt/lineSpanAt,多点点击按下分支(约 270-273 行)还有一份相同的三元——那一份在本 PR 之前就存在(当时服务于已删除的 selectSpan),本 diff 新增了第二份。具体代价:未来 span 解析语义变化(回退行为调整、新增粒度)时两处必须同步修改;漏改其一会产生静默不一致的选区——多点点击锚点 span 与按住拖动的扩展按不同规则解析。本 PR 历史中释放路径空操作的那个严重问题正是这种「粘贴的分发悄悄分叉」造成的。建议在构成函数旁抽取一个共享辅助函数。

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

Comment on lines +237 to +239
it('extends a triple-click line selection line-wise on drag', () => {
frame = makeTwoLineFrame('hello', 'world!');
viewportRect = { x: 0, y: 0, width: 6, height: 2 };

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 line-wise drag tests only use single-word lines ('hello', 'world!'), where lineSpanAt and wordSpanAt return identical spans — probe-verified at HEAD: replacing lineSpanAt with wordSpanAt in extendSpanDrag's line branch keeps all 17 tests green, while a distinguishing multi-word probe test flips between the mutant and the correct code — Failure scenario: triple-click a multi-word line ('foo bar') and drag into 'baz' on the next line: line-wise must copy 'foo bar\nbaz qux', word-wise copies only 'foo bar\nbaz'; if a refactor regresses triple-click drags to word granularity, every test this PR adds stays green while users get truncated clipboard content. Add a line-drag test over multi-word lines — the drag must land on a word that does not touch the line end (landing on 'qux' does not kill the mutant):

it('extends a triple-click line selection across multi-word lines', () => {
  frame = makeTwoLineFrame('foo bar', 'baz qux');
  viewportRect = { x: 0, y: 0, width: 7, height: 2 };
  const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(1000);
  const handler = mount();
  handler(makeEvent('left-press', 2, 1));
  handler(makeEvent('left-press', 2, 1));
  handler(makeEvent('left-press', 2, 1)); // triple-click -> line 0
  handler(makeEvent('move', 2, 2)); // drag into 'baz' on line 1
  handler(makeEvent('left-release', 2, 2));
  nowSpy.mockRestore();

  expect(setSelection).toHaveBeenLastCalledWith({
    sx: 0,
    sy: 0,
    ex: 6,
    ey: 1,
  });
  expect(copyToClipboard).toHaveBeenCalledWith('foo bar\nbaz qux');
});
中文说明

(建议) 按行拖动的测试只使用单词行('hello'、'world!'),此时 lineSpanAtwordSpanAt 返回完全相同的 span——已在 HEAD 用探针验证:把 extendSpanDrag 行分支里的 lineSpanAt 换成 wordSpanAt,全部 17 条测试依旧通过;而一条可区分的多词行探针测试能在变异体与正确代码之间翻转结果。触发场景:三击选中多词行('foo bar')后拖到下一行的 'baz':按行应复制 'foo bar\nbaz qux',按词只会复制 'foo bar\nbaz';若未来重构把三击拖动退化为按词粒度,本 PR 新增的全部测试仍为绿色,用户却会复制到被截断的内容。建议补一条多词行的按行拖动测试——拖动落点必须选在不贴住行尾的词上(落在 'qux' 上杀不死该变异体)。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Autofix review-response summary (PR #8739, round 2)

All three automated-reviewer suggestions were addressed in one commit: refactor(ui): dedupe word/line drag state and span dispatch.

Feedback points and decisions

  1. [Suggestion] Span-drag lifecycle state duplicates SelectionState (use-text-selection.tsx:106) — Addressed (minimal fix).
    • The inline ref type now uses the shared NormalizedSelection type instead of re-declaring the span shape.
    • The duplicated mode field is removed; extendSpanDrag now dispatches on selection.mode. This is semantically identical: the ref is non-null only while a word/line drag is active, and every path that sets or clears one also sets or clears the other (multi-click press sets both, char press resets both, clearSelection nulls the ref and clear() resets the mode, release clears the ref only after the final extend).
    • With mode gone, the wrapper object had a single field left, so the ref is now a flat NormalizedSelection | null (anchorSpanRef); non-null still means "a word/line drag is active", documented with a two-line invariant comment.
    • The reviewer's "deeper fix" (moving the anchor span into SelectionState and resetting it in start()/clear()) was intentionally not taken: it would widen the SelectionState API and change the start() signature for no behavioral gain, against Simplicity First.
  2. [Suggestion] mode→span-resolver dispatch written twice (use-text-selection.tsx:202) — Addressed. Extracted spanAtForMode(frame, mode, point) next to wordSpanAt/lineSpanAt in selection-span.ts, and both dispatch sites (the drag extension and the multi-click press branch) now call it. One deliberate deviation from the proposed signature: the mode parameter is SelectionMode rather than 'word' | 'line' so the drag path can pass selection.mode without a cast; 'char' is unreachable at both call sites by the invariant above, so no extra handling was added.
  3. [Suggestion] Line-wise drag tests only use single-word lines (use-text-selection.test.tsx:239) — Addressed. Added the proposed multi-word test 'extends a triple-click line selection across multi-word lines' (triple-click 'foo bar', drag into 'baz' on the next line, expect the full 'foo bar\nbaz qux' range and clipboard payload). Mutant probe at this commit: replacing the line-mode resolution with wordSpanAt makes 2 tests fail (the new one included); restoring the correct code returns all 65 tests to green, so the test genuinely kills the mutant.

No findings were declined, deferred, or escalated this round.

Changes

  • packages/cli/src/ui/selection/selection-span.ts — new spanAtForMode helper (+ type imports).
  • packages/cli/src/ui/selection/use-text-selection.tsxspanDragRefanchorSpanRef: NormalizedSelection | null, mode dispatch moved to selection.mode, both ternaries replaced by the shared helper (net −26/+30 lines including the test).
  • packages/cli/src/ui/selection/use-text-selection.test.tsx — one new multi-word line-drag test.

No conflict resolution was needed (--conflict false).

Verification

  • npx vitest run src/ui/selection/ (packages/cli, touched) — 65 passed (5 files), including the new test
  • Mutant probe: mutated spanAtForMode to always resolve word-wise → 2 tests failed (mutant killed); restored → green again
  • npx prettier --check on the three touched files — passed (after one --write fix to the import line)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed

Integration tests were not run: the touched behavior is fully exercised by the package-level Vitest suite, not only through the bundled CLI. No settings source changed, so no schema regeneration was needed.

中文说明

Autofix 审查回应摘要(PR #8739,第 2 轮)

三条自动审查建议已在一次提交中全部处理:refactor(ui): dedupe word/line drag state and span dispatch

反馈点与处理决定

  1. [建议] 词/行拖动生命周期状态与 SelectionState 重复(use-text-selection.tsx:106)——已处理(最小修复)
    • 内联 ref 类型改用共享的 NormalizedSelection 类型,不再重复声明 span 结构。
    • 删除重复的 mode 字段;extendSpanDrag 改为基于 selection.mode 分发。语义完全等价:ref 非空仅当词/行拖动进行中,且所有设置/清除其一的路径同时也设置/清除另一个(多点按下同时设置两者、字符按下同时重置两者、clearSelection 置空 ref 且 clear() 重置 mode、释放在最后一次扩展之后才置空 ref)。
    • 去掉 mode 后包装对象只剩一个字段,因此 ref 扁平化为 NormalizedSelection | nullanchorSpanRef);非空仍表示「词/行拖动进行中」,并用两行注释记录该不变式。
    • 审查者提出的「更彻底的修复」(把锚点 span 移入 SelectionState,由 start()/clear() 重置)有意不采纳:那会扩大 SelectionState 的 API 并改变所有 start() 调用方的签名,却没有行为收益,违背 Simplicity First 原则。
  2. [建议] mode→span 解析分发写了两份(use-text-selection.tsx:202)——已处理。在 selection-span.tswordSpanAt/lineSpanAt 旁抽取 spanAtForMode(frame, mode, point),两处分发点(拖动扩展与多点按下分支)均改为调用它。相对建议签名有一处刻意偏差:mode 参数类型为 SelectionMode 而非 'word' | 'line',以便拖动路径直接传入 selection.mode 而无需类型断言;按上述不变式,两个调用点都不可能取到 'char',故未添加任何额外处理。
  3. [建议] 按行拖动测试只使用单词行(use-text-selection.test.tsx:239)——已处理。新增建议中的多词测试 'extends a triple-click line selection across multi-word lines'(三击选中 'foo bar',拖到下一行的 'baz',期望完整范围与剪贴板内容为 'foo bar\nbaz qux')。在当前提交上做了变异探针验证:把按行解析替换为 wordSpanAt 后有 2 条测试失败(含新增测试);恢复正确代码后全部 65 条测试恢复绿色,证明该测试确实能杀死该变异体。

本轮没有拒绝、推迟或升级任何反馈点。

变更内容

  • packages/cli/src/ui/selection/selection-span.ts —— 新增 spanAtForMode 辅助函数(含类型导入)。
  • packages/cli/src/ui/selection/use-text-selection.tsx —— spanDragRefanchorSpanRef: NormalizedSelection | null,mode 分发改为基于 selection.mode,两处三元分发替换为共享辅助函数(含测试在内净变化 −26/+30 行)。
  • packages/cli/src/ui/selection/use-text-selection.test.tsx —— 新增一条多词行按行拖动测试。

无需解决冲突(--conflict false)。

验证

  • npx vitest run src/ui/selection/(packages/cli,受影响包)—— 65 条通过(5 个文件),含新增测试
  • 变异探针:将 spanAtForMode 变异为始终按词解析 → 2 条测试失败(变异体被杀死);恢复后重新全绿
  • 对三个改动文件运行 npx prettier --check —— 通过(导入行经一次 --write 修正)
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过

未运行集成测试:受影响行为已由包级 Vitest 套件完整覆盖,并非只能通过打包后的 CLI 验证。未改动任何 settings 源,无需重新生成 schema。

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline.

中文说明

已审查——无阻断问题。 建议见行内评论。

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

Comment on lines +329 to +334
// A collapsed range is a real single-cell span in word/line mode,
// but only a bare click in char mode.
if (
selection.isEmpty ||
(selection.isCollapsed && selection.mode === 'char')
) {

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 "a collapsed range is a real selection only in word/line mode" policy is now encoded twice in this file — here and in applyHighlight (~line 132: normalized && (!selection.isCollapsed || selection.mode !== 'char')) as its hand-negated complement. The two are logically equivalent today (verified), but the rule now lives in two places. — Failure scenario: if the policy changes (a new selection mode is added, or single-cell selections stop being copyable) and only one site is updated, highlight and copy diverge — a range visibly highlighted but not copied, or copied with no highlight. Suggested fix: hoist the policy onto SelectionState and use it in both places:

// in SelectionState
get isBareClick(): boolean {
  return this.isCollapsed && this.mode === 'char';
}

then selection.isEmpty || selection.isBareClick here and normalized && !selection.isBareClick in applyHighlight.

中文说明

(建议)「折叠选区仅在 word/line 模式下才算真实选区」这一策略现在在本文件中编码了两次——此处一处,applyHighlight(约第 132 行:normalized && (!selection.isCollapsed || selection.mode !== 'char'))一处,两者互为手工取反。已验证当前两处逻辑等价,但同一规则现在存在于两个位置。触发场景:若策略变更(新增选择模式、或单格选区不再可复制)而只更新了一处,高亮与复制就会脱节——出现有高亮却没复制、或无高亮却复制了的情况。建议修复:把策略提升到 SelectionState 上(getter 同上),此处用 selection.isEmpty || selection.isBareClickapplyHighlightnormalized && !selection.isBareClick

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

Comment on lines +81 to +85
export function spanAtForMode(
frame: ReadonlyFrame | null,
mode: SelectionMode,
point: Point,
): NormalizedSelection | null {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] spanAtForMode accepts the full SelectionMode union but only implements two of its three values: 'char' is silently routed to lineSpanAt (a whole-line span), contradicting the doc comment ("word/line selection mode"). The multi-click call site is statically safe (literal 'word' | 'line'), but extendSpanDrag passes selection.mode through un-narrowed, guarded only by the comment-documented invariant that anchorSpanRef non-null implies word/line mode. — Failure scenario: a future caller forwarding selection.mode from a char-mode path (e.g. lifting the anchorSpanRef guard while simplifying, or reusing this helper for a new snap feature) gets a whole-line span for a char-mode selection with zero compiler diagnostics — a character-level operation silently selects and copies an entire line. Suggested fix: narrow the parameter to Exclude<SelectionMode, 'char'>; extendSpanDrag then has to narrow selection.mode at the call site, surfacing the invariant at compile time instead of in a comment.

中文说明

(建议) spanAtForMode 接受完整的 SelectionMode 联合类型,但只实现了其中两个值:'char' 会被静默路由到 lineSpanAt(整行 span),与文档注释("word/line selection mode")矛盾。多点点击调用点是静态安全的(字面量 'word' | 'line'),但 extendSpanDrag 未收窄就传入 selection.mode,仅靠注释记载的不变式(anchorSpanRef 非空 ⟹ word/line 模式)保护。触发场景:未来若有调用方从 char 模式路径转发 selection.mode(例如简化时移除 anchorSpanRef 守卫,或为新吸附功能复用此 helper),char 模式选区会拿到整行 span 且编译器零报错——字符级操作会静默选中并复制整行。建议修复:把参数收窄为 Exclude<SelectionMode, 'char'>extendSpanDrag 就必须在调用点显式收窄 selection.mode,让不变式由编译器而不是注释来保证。

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

Comment on lines +295 to +299
// A held multi-click keeps its click record so pointer drift cannot
// break a triple-click; char drags still break the chain.
if (!anchorSpanRef.current) {
lastClickRef.current = null;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The char-mode half of this guard ("char drags still break the chain") lost its only effective test when copy moved from press to release: does not treat a click after a drag as a double-click only presses after the drag and asserts clipboard call counts, which no longer discriminates. Probe-verified at HEAD: replacing the guard with if (false) keeps the whole suite green (18/18). — Failure scenario: user char-drags to copy, then clicks again near the drag start within 400 ms — with the guard gone the click counts as a double-click, selecting and copying a word instead of being a bare click. A probe that releases after the near click fails under the mutant (2 copy calls) and passes with the guard restored. Suggested fix: in that test, follow the second press with a release and keep the count assertion:

handler(makeEvent('left-release', 1));
expect(copyToClipboard).toHaveBeenCalledTimes(1);
中文说明

(建议) 该守卫的 char 模式半边("字符拖动仍会打断连击链")在复制从按下移到释放后失去了唯一的有效测试:does not treat a click after a drag as a double-click 在拖动后只按下不释放、仅断言剪贴板调用次数,已不再具备判别力。已在 HEAD 用探针验证:把守卫替换为 if (false),整套测试仍 18/18 全绿。触发场景:用户字符拖动复制后,400ms 内在拖动起点附近再点一次——若守卫失效,这次点击会被计为双击,选中并复制一个词,而不是作为普通单击。在近似点击后补一次释放的探针在变异体下失败(复制 2 次)、在守卫恢复后通过。建议修复:在该测试的第二次按下后补一次释放并保留次数断言(代码同上)。

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

expect(copyToClipboard).toHaveBeenCalledTimes(1);
});

it('extends a triple-click line selection line-wise on drag', () => {

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 line-mode collapsed branch of the new release condition has no test: nothing ever produces a collapsed line selection (triple-click on a one-character line). Probe-verified at HEAD: the mutant selection.mode === 'char'selection.mode !== 'word' changes only that case (collapsed line cleared without copying) and the suite stays green. — Failure scenario: triple-click a line whose only content is one cell (a y answer, a single digit) — lineSpanAt returns a collapsed 'line'-mode range that must still copy; a refactor of the condition could silently drop the copy with no test failing. Suggested fix: add a sibling of the single-char-word test:

it('copies a one-cell line on a no-drag triple-click', () => {
  frame = makeFrame('x');
  viewportRect = { x: 0, y: 0, width: 1, height: 1 };
  const nowSpy = vi.spyOn(Date, 'now').mockReturnValue(1000);
  const handler = mount();
  handler(makeEvent('left-press', 1));
  handler(makeEvent('left-press', 1));
  handler(makeEvent('left-press', 1)); // triple-click -> selects the line
  handler(makeEvent('left-release', 1));
  nowSpy.mockRestore();

  expect(setSelection).toHaveBeenLastCalledWith({
    sx: 0,
    sy: 0,
    ex: 0,
    ey: 0,
  });
  expect(copyToClipboard).toHaveBeenLastCalledWith('x');
});
中文说明

(建议) 新释放条件的 line 模式折叠分支没有测试:没有任何测试产生过折叠的 line 选区(对单字符行三击)。已在 HEAD 用探针验证:变异体 selection.mode === 'char'selection.mode !== 'word' 只影响该情形(折叠的 line 选区被清除而不复制),测试套件仍全绿。触发场景:三击只有一个单元格的行(如 y 回答、单个数字)——lineSpanAt 返回 'line' 模式的折叠选区,仍应复制;重构该条件时可能静默丢掉这次复制而无测试失败。建议修复:仿照单字符词测试补一条(代码同上)。

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

Comment on lines +272 to 278
selection.start({ x: span.sx, y: span.sy }, mode);
selection.extend({ x: span.ex, y: span.ey });
anchorSpanRef.current = span;
dragScrollTopRef.current =
propsRef.current.getScrollState().scrollTop;
recordBaseline();
applyHighlight();

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] No test pins that a multi-click selection is highlighted at press time, before any move or release: all new tests assert only the last setSelection call after release, and the release path re-applies the highlight. Probe-verified at HEAD: deleting applyHighlight() from this span press branch keeps the suite green (18/18). — Failure scenario: double-click and hold without moving — the exact starting posture of this PR's hold-and-drag feature — would then show no highlight until the pointer moves or releases, instead of highlighting the word immediately on the second press. Suggested fix: in one of the double-click tests, assert the highlight right after the second press, before any move/release:

expect(setSelection).toHaveBeenLastCalledWith({
  sx: 0,
  sy: 0,
  ex: 2,
  ey: 0,
});
中文说明

(建议) 没有测试钉住多点点击在按下时(任何移动/释放之前)就高亮选区:所有新测试只断言释放后最后一次 setSelection 调用,而释放路径会再次应用高亮。已在 HEAD 用探针验证:删除该 span 按下分支中的 applyHighlight(),套件仍全绿(18/18)。触发场景:双击后按住不动——正是本 PR 按住拖动功能的起始姿势——将不会显示任何高亮,直到指针移动或释放,而不是在第二次按下时立即高亮该词。建议修复:在某个双击测试中,第二次按下后、任何移动/释放前断言高亮(代码同上)。

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

Comment on lines +242 to +246
handler(makeEvent('left-press', 2, 1));
handler(makeEvent('left-press', 2, 1));
handler(makeEvent('left-press', 2, 1)); // triple-click -> line 0
handler(makeEvent('move', 3, 2)); // drag into the middle of line 1
handler(makeEvent('left-release', 3, 2));

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 triple-click tests emit three consecutive left-press events with no intervening releases, but SGR button tracking always delivers press/release pairs — this stream cannot occur in production. Probe-verified with a realistic press/release ×3 stream: copyToClipboard is called twice (word, then line, e.g. ['foo'], ['foo bar baz']) — A/B-verified identical at the merge base, so the double copy is pre-existing behavior this PR inherits rather than introduces; the in-scope problem is that toHaveBeenCalledTimes(1) passes only under the synthetic no-release stream, so the suite asserts one-copy-per-gesture for an impossible event sequence. — Failure scenario: on a real triple-click the intermediate release copies the word before the third click selects the line: clipboard managers record a spurious intermediate entry, and if the final copy fails (clipboard contention; the failure is only debug-logged) the clipboard silently retains the word instead of the line. Suggested fix: emit realistic press/release pairs in the triple-click tests and assert the final payload (toHaveBeenLastCalledWith) instead of a write count of 1.

中文说明

(建议) 三击测试连发三个 left-press 事件、中间没有释放,但 SGR 按键追踪总是成对上报 press/release——该事件流在生产中不可能出现。已用真实的 press/release ×3 事件流探针验证:copyToClipboard 被调用两次(先词后行,如 ['foo']['foo bar baz'])——并经 A/B 验证与合并基点完全一致,因此双写复制是本 PR 继承的既有行为而非新引入;范围内的问题是 toHaveBeenCalledTimes(1) 只在合成的无释放事件流下通过,即套件对一个不可能出现的事件序列断言了"每次手势只复制一次"。触发场景:真实三击时,中间那次释放会先复制词,第三击才选中行——剪贴板管理器会记录多余的中间条目;若最后一次复制失败(剪贴板被占用,失败仅记录 debug 日志),剪贴板会静默停留在词而不是行。建议修复:三击测试改用真实的 press/release 成对事件,并断言最终内容(toHaveBeenLastCalledWith)而不是复制次数为 1。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Round 4 — review feedback addressed

All six round-3 suggestions from the automated reviewer are addressed in one commit (refactor(ui): dedupe collapsed-range policy and pin multi-click tests). No base-conflict resolution was needed (--conflict false).

Findings and dispositions

  • R3-1 — collapsed-range policy encoded twice (implemented). Added an isBareClick getter to SelectionState ("collapsed + char mode is a bare click, not a selection") and now use it in both the release path (selection.isEmpty || selection.isBareClick) and applyHighlight (normalized && !selection.isBareClick). The two hand-negated encodings and their duplicated policy comments are gone, so highlight and copy can no longer diverge when the policy changes.
  • R3-2 — spanAtForMode accepts 'char' silently (implemented). Narrowed the parameter to Exclude<SelectionMode, 'char'>. To make the invariant compile-time instead of comment-documented, the anchor-span ref now carries the drag mode alongside the span ({ span, mode } typed with 'word' | 'line'), and extendSpanDrag reads that mode instead of the un-narrowed selection.mode. A char-mode caller can no longer reach the line-span fallback without a compiler error, and no dead runtime guard was added.
  • R3-3 — char-drag chain-break guard lost its discriminating test (implemented). does not treat a click after a drag as a double-click now releases after the post-drag press, so the copy-count assertion discriminates again. Mutation probe at this commit: replacing the guard with if (false) fails exactly this test with 2 clipboard calls, matching the reviewer's predicted signature.
  • R3-4 — collapsed line-mode release branch untested (implemented). Added copies a one-cell line on a no-drag triple-click, a sibling of the single-char-word test, written with realistic press/release pairs. Mutation probe: the mode === 'char'mode !== 'word' mutant now fails exactly this test (collapsed line cleared without copying, setSelection(null) as the last call).
  • R3-5 — press-time multi-click highlight not pinned (implemented). The word-wise drag test now asserts the foo span is highlighted immediately after the second press, before any move or release. Mutation probe: deleting applyHighlight() from the span press branch now fails exactly this test.
  • R3-6 — triple-click tests used an impossible no-release event stream (implemented, in scope). All three triple-click tests now emit realistic press/release pairs and assert the final payload with toHaveBeenLastCalledWith instead of a write count of 1; the intermediate release copying the word is documented inline. The double-copy on a real triple-click itself is pre-existing behavior (reviewer A/B-verified identical at the merge base, where multi-clicks copied on press), and changing multi-click copy timing is a behavior change beyond this drag-selection PR's scope, so it is deliberately left untouched here.

Conflict notes

None — the branch was already up to date with the base; no merge was performed.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx vitest run src/ui/selection/ src/ui/components/MainContent.test.tsx (in packages/cli, covering all touched files plus the only external consumer) — 6 files, 88 tests passed
  • npx prettier --check on the four changed files — passed
  • Mutation probes (each applied, run, and reverted): chain-break-guard removal → 1 failed test (R3-3 test); collapse-policy mode !== 'word' → 1 failed test (R3-4 test); press-time applyHighlight() removal → 1 failed test (R3-5 assertion). The restored tree is fully green.
中文说明

第 4 轮 — 已处理的评审反馈

自动化评审者第 3 轮提出的全部六条建议均已在一次提交中处理(refactor(ui): dedupe collapsed-range policy and pin multi-click tests)。无需解决与基线的冲突(--conflict false)。

各条反馈及处理

  • R3-1 — 折叠选区策略被编码了两次(已实现)。SelectionState 上新增 isBareClick getter(「折叠 + char 模式即为裸点击,不是选区」),并在释放路径(selection.isEmpty || selection.isBareClick)与 applyHighlightnormalized && !selection.isBareClick)两处统一使用。两处手工取反的编码及其重复的策略注释均已移除,策略未来变更时高亮与复制不会再脱节。
  • R3-2 — spanAtForMode 静默接受 'char'(已实现)。 参数收窄为 Exclude<SelectionMode, 'char'>。为让不变式由编译器而非注释保证,锚点 span ref 现在同时携带拖动模式({ span, mode },类型限定为 'word' | 'line'),extendSpanDrag 读取该模式而非未收窄的 selection.mode。char 模式调用方不再可能无声地落入整行 span 分支,且未添加任何不可能执行的运行时守卫。
  • R3-3 — char 拖动断链守卫失去判别性测试(已实现)。 does not treat a click after a drag as a double-click 现在在拖动后的按下之后补了一次释放,剪贴板次数断言重新具备判别力。在本提交上做变异探针:把守卫替换为 if (false) 恰好使该测试以 2 次剪贴板调用失败,与评审者预测的特征一致。
  • R3-4 — line 模式折叠释放分支无测试(已实现)。 新增 copies a one-cell line on a no-drag triple-click,作为单字符词测试的姊妹用例,采用真实的 press/release 成对事件。变异探针:mode === 'char'mode !== 'word' 变异体恰好使该测试失败(折叠 line 选区被清除而未复制,最后一次调用为 setSelection(null))。
  • R3-5 — 多点点击按下时高亮未被钉住(已实现)。 word 拖动测试现在在第二次按下后、任何移动/释放之前断言 foo 选区已被高亮。变异探针:删除 span 按下分支中的 applyHighlight() 恰好使该测试失败。
  • R3-6 — 三击测试使用了不可能出现的无释放事件流(已实现范围内部分)。 三个三击测试现在都发出真实的 press/release 成对事件,并用 toHaveBeenLastCalledWith 断言最终内容,不再断言复制次数为 1;中间释放复制词的行为已在测试中注明。真实三击产生的双写复制本身是既有行为(评审者已 A/B 验证与合并基点一致,基点上多点点击在按下时复制),改变多点点击的复制时机属于超出本拖动选择 PR 范围的行为变更,故此处刻意不处理。

冲突说明

无 — 分支已与基线同步,未执行合并。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx vitest run src/ui/selection/ src/ui/components/MainContent.test.tsx(在 packages/cli 下运行,覆盖全部改动文件及唯一外部使用方)— 6 个文件、88 个测试全部通过
  • 对四个改动文件运行 npx prettier --check — 通过
  • 变异探针(逐一应用、运行并回滚):移除断链守卫 → 恰好 1 个测试失败(R3-3 测试);折叠策略改为 mode !== 'word' → 恰好 1 个测试失败(R3-4 测试);移除按下时的 applyHighlight() → 恰好 1 个测试失败(R3-5 断言)。恢复后的代码树全部绿色。

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline. Not explored to full depth (tool budget reached): This PR extends VP-mode mouse text selection: dragging af...: did not run the PR's vitest suite (worktree has no node_modules; rather than installing the monorepo I verified the tests by hand-tracing).; This PR extends VP-mode mouse text selection: dragging af...: did not empirically verify ink's highlight rendering for multi-row selections; read the patch compositor only.; This PR extends VP-mode mouse text selection: dragging af...: did not execute the PR's vitest suite — the review worktree has no node_modules ; new tests were verified by hand-tracing instead of running.; This PR extends VP-mode mouse text selection: dragging af...: did not verify ink's highlight rendering for multi-row selections empirically; only read the patch compositor's cell/selection code..

中文说明

已审查。 建议见行内评论。 未探索到全部深度(达到工具调用预算):This PR extends VP-mode mouse text selection: dragging af...:did not run the PR's vitest suite (worktree has no node_modules; rather than installing the monorepo I verified the tests by hand-tracing).;This PR extends VP-mode mouse text selection: dragging af...:did not empirically verify ink's highlight rendering for multi-row selections; read the patch compositor only.;This PR extends VP-mode mouse text selection: dragging af...:did not execute the PR's vitest suite — the review worktree has no node_modules ; new tests were verified by hand-tracing instead of running.;This PR extends VP-mode mouse text selection: dragging af...:did not verify ink's highlight rendering for multi-row selections empirically; only read the patch compositor's cell/selection code.

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

Comment on lines +136 to +138
getBuffer()?.setSelection(
normalized && !selection.isBareClick ? normalized : null,
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The highlight-suppression branch of isBareClick in applyHighlight is unpinned by any test — the one-line mutation normalized && !selection.isBareClick ? normalized : nullnormalized survives the entire suite (verified by applying the mutation and running this file: 19/19 pass). No test performs a bare char-mode click and asserts the highlight stays off: the drag tests only assert the final post-move/post-release range (toHaveBeenLastCalledWith), and the modified click-after-drag test asserts only copyToClipboard counts. The release-path use of isBareClick (~line 333) IS pinned — mutating it fails two tests — so the gap is exactly the highlight half of the getter's contract. Failure scenario: a future change that drops the !selection.isBareClick guard (or inlines the condition incorrectly during a refactor) → every plain click paints a persistent single-cell highlight until the next interaction, and the suite stays green. Suggested fix — assert that a bare char click does not highlight, e.g. a new test:

const handler = mount();
handler(makeEvent('left-press', 1));
handler(makeEvent('left-release', 1));
expect(setSelection).toHaveBeenLastCalledWith(null);
中文说明

(建议) applyHighlightisBareClick 的“抑制高亮”分支没有任何测试锁定——单行变异 normalized && !selection.isBareClick ? normalized : nullnormalized 能通过整个测试套件(已实际应用该变异并运行本文件验证:19/19 通过)。没有测试执行一次纯字符模式点击并断言高亮保持关闭:拖动测试只断言 move/release 之后的最终范围(toHaveBeenLastCalledWith),修改后的“拖动后点击不视为双击”测试只断言 copyToClipboard 的调用次数。释放路径对 isBareClick 的使用(约第 333 行)是有测试锁定的——变异它会导致两个测试失败——缺口恰好是该 getter 契约中的高亮半边。触发场景:未来某次修改删掉了 !selection.isBareClick 守卫(或重构时错误地内联了该条件)→ 每次普通点击都会画出一个持久的单格高亮,直到下一次交互才消失,而测试套件仍然全绿。建议修复——断言纯字符点击不高亮,例如新增测试(代码见上)。

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

Comment on lines +215 to +217
selection.focus = cursorAfter
? { x: current.ex, y: current.ey }
: { x: current.sx, y: current.sy };

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] Line-mode drags spanning multiple rows copy inconsistently trimmed rows. getSelectedText end-trims only the LAST row (to the selection's ex, which lineSpanAt set to the last non-space column); the first and intermediate rows are extracted to row.length - 1 (selection-text.ts:33) and keep written trailing spaces. Probe-verified at this commit: triple-click line 0 of a 3-line frame whose rows end in selectable spaces, drag to line 2, release → clipboard payload "aaa \nbbb \nccc" (first two rows keep trailing spaces, last row trimmed). Pre-PR, multi-row selections only arose from char drags where ex is the drag endpoint rather than a trim, so this inconsistency is newly reachable via line-mode multi-row drags. Impact is cosmetic (trailing whitespace in copied text). Failure scenario: triple-click a line and drag down two or more rows over content with written trailing whitespace (e.g. a rendered code block that preserves trailing spaces) → per-row trimming inside one copied payload is inconsistent. Suggested fix: trim consistently — e.g. in getSelectedText, use the last non-space column as endX for every row fully covered by the selection — or deliberately accept and pin the current behavior with a test.

中文说明

(建议) 跨多行的按行拖动会复制出修剪不一致的行。getSelectedText 只对最后一行做行尾修剪(修剪到选区的 ex,即 lineSpanAt 设定的最后一个非空格列);首行和中间行按 row.length - 1 提取(selection-text.ts:33),保留了已写入的行尾空格。已在被审提交上用探针验证:对三行帧(行尾带可选中的空格)三击第 0 行并拖到第 2 行后释放 → 剪贴板内容为 "aaa \nbbb \nccc"(前两行保留行尾空格,最后一行被修剪)。此 PR 之前多行选区只能来自字符拖动(ex 是拖动终点而非修剪结果),因此该不一致是按行多行拖动新引入的。影响为外观层面(复制文本中的行尾空格)。触发场景:三击某行后向下拖动两行以上,内容含已写入的行尾空格(如保留行尾空格的代码块渲染)→ 同一份复制内容中各行的修剪不一致。建议修复:统一修剪——例如在 getSelectedText 中对每个被选区完整覆盖的行使用最后一个非空格列作为 endX——或有意接受现状并用测试锁定。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Address-review summary — PR #8739 (round 5)

Two inline suggestions from the automated reviewer; both resolved in code (test-only round, no production-code changes). Commit: b5cbd2fd5d test(ui): pin bare-click highlight and multi-row line-drag copy (#8739).

Feedback points and decisions

1. [Suggestion] rc:3741997816 — bare-click highlight suppression is unpinned (use-text-selection.tsx:138)

Decision: addressed. Confirmed the reviewer's analysis: the release path clears the highlight via clearSelection() regardless of the isBareClick guard, so only the press-time call in applyHighlight exercises the suppression branch, and no existing test asserted it — the normalized && !selection.isBareClick ? normalized : nullnormalized mutation survived the suite.

Added does not highlight a bare char-mode click, which asserts setSelection was last called with null immediately after the press (and stays null after release, with no clipboard call). One note on the finding's suggested snippet: asserting only after the release would not kill the mutation, because the release path's clearSelection() also calls setSelection(null) — the assertion must sit between press and release, which is what the new test does.

Mutation-verified: applied the exact one-line mutation, the new test failed (1/21) while all others passed; restored the source file from HEAD and the full selection suite is green.

2. [Suggestion] rc:3741997820 — multi-row line drags copy inconsistently trimmed rows (use-text-selection.tsx:217)

Decision: addressed via the finding's second option — deliberately accept the current behavior and pin it with a test. The inconsistency is real (first/intermediate rows keep written trailing spaces; the final row is trimmed because ex comes from lineSpanAt's last-content-column), but the suggested "trim every fully covered row in getSelectedText" fix conflicts with an existing pinned contract: selection-text.test.tspreserves selectable source whitespace asserts 'hi \nbye' for exactly a multi-row selection whose first row is covered to its end. Unifying would therefore require either breaking that whitespace-preservation contract for char drags or threading the selection mode through getSelectedText (API growth) — neither is worth it for a cosmetic trailing-whitespace difference (AGENTS.md: Simplicity First).

Added keeps covered-row trailing spaces in a multi-row line drag: triple-click on a row ending in a selectable space, drag down one row, release, and assert both the highlight span ({sx:0, sy:0, ex:2, ey:1}) and the exact clipboard payload 'aaa \nbbb'. Any future change that trims covered rows (or stops trimming the final row) now fails loudly instead of silently shifting copy behavior.

No conflict resolution needed (--conflict false); origin/main was not merged.

Verification

  • cd packages/cli && npx vitest run src/ui/selection/use-text-selection.test.tsx src/ui/selection/selection-text.test.ts — passed (36 tests: 21 + 15)
  • Mutation check for point 1: applied the applyHighlight mutation → does not highlight a bare char-mode click failed (1/21), all others passed; file restored from HEAD
  • cd packages/cli && npx vitest run src/ui/selection/ — passed (68 tests across 5 files, final state)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check packages/cli/src/ui/selection/use-text-selection.test.tsx — passed
  • Settings schema regeneration — not applicable (no settings source changed)
  • Integration tests after npm run bundle — not applicable (test-only change; the touched behavior is exercised by unit tests, not only through the bundled CLI)
中文说明

处理审查意见总结 — PR #8739(第 5 轮)

自动化审查器提出两条行内建议;均已在代码中解决(本轮仅改测试,无生产代码变更)。提交:b5cbd2fd5d test(ui): pin bare-click highlight and multi-row line-drag copy (#8739)

反馈点与决定

1. 【建议】rc:3741997816 — 纯点击的高亮抑制分支没有测试锁定(use-text-selection.tsx:138)

决定:已处理。 确认了审查器的分析:释放路径无论如何都会通过 clearSelection() 清除高亮,因此只有按压时 applyHighlight 中的调用才会走到该抑制分支,而现有测试没有对其断言——变异 normalized && !selection.isBareClick ? normalized : nullnormalized 能通过整个测试套件。

新增测试 does not highlight a bare char-mode click:断言按压之后 setSelection 最后一次被调用时传入 null(释放后仍为 null,且不触发剪贴板调用)。对建议中的示例代码有一点说明:只在释放之后断言无法杀死该变异,因为释放路径的 clearSelection() 同样会调用 setSelection(null)——断言必须位于按压与释放之间,新测试正是这样做的。

已做变异验证:实际应用该单行变异后,新测试失败(1/21),其余全部通过;随后从 HEAD 恢复源文件,selection 目录测试全绿。

2. 【建议】rc:3741997820 — 按行多行拖动复制出的行修剪不一致(use-text-selection.tsx:217)

决定:采用该建议给出的第二个选项——有意接受当前行为并用测试锁定。 不一致确实存在(首行/中间行保留已写入的行尾空格;最后一行被修剪,因为 ex 来自 lineSpanAt 的最后一个非空格列),但建议中"在 getSelectedText 里对每个完整覆盖的行做修剪"的修法与一条已有的锁定契约冲突:selection-text.test.ts 中的 preserves selectable source whitespace 恰好对一个首行被完整覆盖的多行选区断言了 'hi \nbye'。统一修剪要么破坏字符拖动保留空白字符的既有契约,要么需要把选区模式参数传入 getSelectedText(API 膨胀)——为了一个外观层面的行尾空格差异,两者都不值得(AGENTS.md:简单优先)。

新增测试 keeps covered-row trailing spaces in a multi-row line drag:对行尾带可选空格的一行三击,向下拖动一行后释放,同时断言高亮范围({sx:0, sy:0, ex:2, ey:1})与精确的剪贴板内容 'aaa \nbbb'。未来任何修剪覆盖行(或不再修剪末行)的改动都会显著失败,而不是悄悄改变复制行为。

无需解决冲突(--conflict false);未合并 origin/main

验证

  • cd packages/cli && npx vitest run src/ui/selection/use-text-selection.test.tsx src/ui/selection/selection-text.test.ts — 通过(36 个测试:21 + 15)
  • 针对第 1 点的变异检查:应用 applyHighlight 变异 → does not highlight a bare char-mode click 失败(1/21),其余通过;文件已从 HEAD 恢复
  • cd packages/cli && npx vitest run src/ui/selection/ — 通过(5 个文件共 68 个测试,最终状态)
  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx prettier --check packages/cli/src/ui/selection/use-text-selection.test.tsx — 通过
  • 设置 schema 重新生成 — 不适用(未改动设置源)
  • npm run bundle 后的集成测试 — 不适用(仅测试变更;所涉行为由单元测试覆盖,并非只经由打包后的 CLI 行使)

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline.

中文说明

已审查——无阻断问题。 建议见行内评论。

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

Comment on lines +275 to +277
// press too: a streaming repaint before release clears the
// selection, skipping the release copy. Release copies again when
// the drag grew the range.

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 release copy is unconditional — the "when the drag grew the range" condition in this comment is not implemented anywhere in the release path. Pre-PR a multi-click produced exactly one copy (the release early-returned because selectSpan left dragging = false); now every no-drag double/triple-click copies the identical text twice. Probe-verified at HEAD: a no-drag double-click on foo records copyToClipboard calls [['foo'], ['foo']], and the new test 'copies a single-character word on a no-drag double-click' pins toHaveBeenCalledTimes(2).

Failure scenario: user double-clicks a word and releases without dragging (the common case) → two clipboard subprocess spawns with identical content: one redundant process spawn per multi-click, duplicate entries in clipboard-history tools, and on clipboard-less machines the whole failing fallback chain (wl-copyxclipxsel → OSC 52) plus its Failed to copy selected text debug-log warnings runs twice.

Suggested fix: make the release copy conditional on growth — compare the normalized selection at release against the press span (still available in anchorSpanRef before it is cleared) and skip copySelection() when unchanged, or track the last-copied normalized range in a ref and copy only on change. (Alternatively, fix the comment to say release always copies again.)

// in the release path, before clearing anchorSpanRef:
const grew = selectionIsGrownBeyond(selection.normalized(), anchorSpanRef.current?.span);
if (grew) {
  copySelection();
}
中文说明

(建议) release 复制是无条件的——这条注释里"当拖动扩大了范围时"的条件在 release 路径中并未实现。PR 之前多点点击只复制一次(因 selectSpan 保持 dragging = false,release 提前返回);现在每次不拖动的双击/三击都会把相同文本复制两遍。已在 HEAD 用探针验证:不拖动双击 foocopyToClipboard 的调用记录为 [['foo'], ['foo']],新测试 'copies a single-character word on a no-drag double-click' 也固定了 toHaveBeenCalledTimes(2)

触发场景:用户双击一个词后不拖动直接释放(最常见情形)→ 以相同内容启动两个剪贴板子进程:每次多点点击多一次进程开销、剪贴板历史工具出现重复条目;在没有剪贴板的机器上,整条失败的 fallback 链(wl-copyxclipxsel → OSC 52)及其 Failed to copy selected text 调试日志警告会执行两遍。

建议修复:让 release 复制以"范围扩大"为条件——在释放时把 normalized 选区与按下时的 span(清空前的 anchorSpanRef 中仍可取到)比较,未变化则跳过 copySelection();或用 ref 记录上次复制的范围,仅变化时复制。(或者把注释改为"release 总是再复制一次"。)

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

Comment on lines +270 to 272
const mode = count === 2 ? 'word' : 'line';
const span = spanAtForMode(frame, mode, point);
if (span) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The rewritten multi-click branch's span == null fall-through has no test. wordSpanAt returns null on a whitespace cell and lineSpanAt null on a blank row, so a double-click on the gap between words takes this untested fall-through into a bare char press with no copy.

Failure scenario: if a follow-up change inverted the if (span) guard or hoisted copySelection() out of it, double-clicking a gap would write a stray space/character to the clipboard and highlight a bogus span, and the whole suite stays green. Probe-verified at HEAD: hoisting a copy out of the guard makes only the proposed probe fail, so the test has teeth.

Suggested fix:

it('falls back to a bare char press when double-clicking whitespace', () => {
  // double-click the gap between 'foo' and 'bar'; assert
  // setSelection was last called with null and copyToClipboard was not called
});

optionally plus the triple-click-on-blank-row analogue.

中文说明

(建议) 重写后的多点点击分支中 span == null 的回退路径没有测试。wordSpanAt 在空白单元格上返回 null,lineSpanAt 在空行上返回 null,因此在词间空隙上双击会走这条未测试的回退路径——退化为无复制的普通字符按压。

触发场景:若后续改动反转了 if (span) 守卫,或把 copySelection() 提到守卫之外,在空隙上双击就会把一个多余的空格/字符写入剪贴板并高亮一个错误的 span,而整套测试仍然全绿。已在 HEAD 用探针验证:把复制调用提到守卫外只会让所建议的这条探针测试失败,说明该测试有效。

建议修复:新增测试——双击 'foo' 与 'bar' 之间的空隙,断言 setSelection 最后一次被调用时参数为 null 且 copyToClipboard 未被调用;可选再加上"空行上三击"的对应测试。

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

Comment on lines +278 to +279
selection.start({ x: span.sx, y: span.sy }, mode);
selection.extend({ x: span.ex, y: span.ey });

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] No test pins that a released multi-click selection no longer extends on move — an invariant this diff changed from structural to behavioural. Pre-PR selectSpan set dragging = false, so a completed multi-click could never react to moves by construction; now the press enters a real drag and only the release handler's finish() demotes it, with the sole guard being if (!selection.dragging) return; in the move path.

Failure scenario: if finish() were skipped or the release path reordered, gliding the mouse (no button held) after double-clicking foo would silently grow the selection and overwrite the clipboard with foo bar baz. Probe-verified at HEAD: deleting selection.finish() from the release path makes only the proposed probe fail.

Suggested fix: extend e.g. 'copies a single-character word on a no-drag double-click' with a move event after the final release and assert setSelection/copyToClipboard call counts are unchanged.

中文说明

(建议) 没有测试固定"释放后的多点点击选区不再随 move 扩展"——这一不变量在本 diff 中从结构性保证变成了行为性保证。PR 之前 selectSpandragging = false,完成的多点点击按构造就不可能响应 move;现在按下时进入真实拖动,只有 release 处理器的 finish() 将其降级,唯一守卫是 move 路径里的 if (!selection.dragging) return;

触发场景:若 finish() 被漏掉或 release 路径被重排,双击 foo 后不按按键滑动鼠标就会悄悄扩大选区,并把剪贴板覆盖为 foo bar baz。已在 HEAD 用探针验证:删除 release 路径中的 selection.finish() 只会让所建议的这条探针测试失败。

建议修复:在诸如 'copies a single-character word on a no-drag double-click' 的测试中,于最终释放后再发一个 move 事件,断言 setSelection/copyToClipboard 的调用次数不变。

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

Comment on lines +204 to +209
const current = spanAtForMode(frame, mode, point) ?? {
sx: point.x,
sy: point.y,
ex: point.x,
ey: point.y,
};

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] A line-mode drag that ends on a blank row silently degrades from line granularity to a single cell. lineSpanAt returns null for a blank row, so this fallback yields the single cursor cell for line mode as well — but a whole-row span is what "line-wise" promises.

Failure scenario (probe-verified at HEAD against real ink frames): triple-click a content line, drag down onto a blank separator row (common between chat messages) and release there → the highlight stops at the cursor's column mid-blank-row, and on whitespace-only content rows the copied text is truncated at the release column (release-column-dependent payload); releasing one row lower on content includes the same blank row fully with its newline. Word-mode's analogous fallback is documented and tested ('falls back to the cursor cell when a word drag lands on whitespace'); the line-mode shape is neither.

Suggested fix: when mode === 'line' and spanAtForMode returns null, fall back to a whole-row span (e.g. { sx: 0, sy: point.y, ex: <last column of the frame row>, ey: point.y }) instead of the single cursor cell, and add a test pinning a line drag released on a blank row.

中文说明

(建议) 以空行为终点的按行拖动会从行粒度悄悄退化为单单元格。lineSpanAt 对空行返回 null,于是此回退对 line 模式也只给出光标所在的单个单元格——但"按行扩展"承诺的是整行 span。

触发场景(已在 HEAD 用真实 ink frame 探针验证):三击选中一个内容行,向下拖到空白分隔行(聊天消息之间很常见)并在那里释放 → 高亮停在空白行中间光标所在的列;对于仅含空白字符的内容行,复制的文本会在释放列处被截断(复制结果依赖于释放列);而在再往下一行的内容上释放时,同一个空行却会连同换行符被完整包含。词模式的同类回退有文档且有测试('falls back to the cursor cell when a word drag lands on whitespace');行模式的这一形态两者皆无。

建议修复:当 mode === 'line'spanAtForMode 返回 null 时,回退为整行 span(如 { sx: 0, sy: point.y, ex: <该行最后一列>, ey: point.y })而非单个光标单元格,并新增测试固定"在空行上释放的按行拖动"。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Autofix review round: no action taken

This round has no actionable feedback:

  • Reviews: none newer than the last evaluation.
  • Inline comments: none.
  • Issue-level comments: none.
  • Failed checks: none.
  • Still-red checks: none.
  • Base conflicts: none reported (--conflict false); no merge performed.

Critical-only mode is active for this PR (after 5 change-producing rounds). The feedback listed under Deferred non-Critical feedback is the workflow's audit record of that transition, not work for this round: per the workflow rules, no code changes, thread resolutions, or comment replies were made for those items. They remain open for human follow-up; a maintainer can bring any of them back into scope explicitly.

No commits were made this round.

中文说明

Autofix 评审轮次:本轮未执行任何操作

本轮没有需要处理的反馈:

  • 评审(Reviews): 自上次评估后没有新的评审。
  • 行内评论(Inline comments): 无。
  • Issue 级评论(Issue-level comments): 无。
  • 失败的检查(Failed checks): 无。
  • 持续失败的检查(Still-red checks): 无。
  • 与基础分支的冲突(Base conflicts): 未报告(--conflict false);未执行任何合并。

本 PR 已进入仅处理 Critical 的模式(在 5 个产生改动的轮次之后)。Deferred non-Critical feedback(已延后的非 Critical 反馈)中列出的内容是工作流对该模式切换的审计记录,不属于本轮的工作范围:按照工作流规则,本轮未对这些条目进行任何代码修改、线程解决或评论回复。这些条目保持开放,留待人工跟进;维护者可以明确地将其中任何一条重新纳入处理范围。

本轮未产生任何提交。

Deferred non-Critical feedback

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

中文说明

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

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

中文说明

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

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

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⚠️ Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x). Reviewed.

中文说明

⚠️ 已从批准降级为评论:CI failing: Test (ubuntu-latest, Node 22.x)。 已审查。

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

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

⚠️ Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x). Reviewed.

中文说明

⚠️ 已从批准降级为评论:CI failing: Test (ubuntu-latest, Node 22.x)。 已审查。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

🤖 Investigated the still-red check — no code-level defect found; no changes this round. Why, with evidence: · 已排查持续失败的检查——未发现代码层面缺陷;本轮未做改动。依据如下:

Autofix review round — still-red check investigation (PR #8739)

Actionable feedback this round

The only actionable item was the still-red check: Test (ubuntu-latest, Node 22.x) (FAILURE in CI run 31486077556 at head d5999edfba, completed 2026-08-11T11:38:50Z). All other actionable sections were empty (no new reviews, inline comments, issue-level comments, or newly failed checks). The deferred non-Critical items (two automated-reviewer reviews) were left untouched per the Critical-only rules. There is no GitHub credential on this runner, so the failing step inside the job could not be read from the CI log; instead the Test job's gates were reproduced locally.

Local reproduction of the Test job (all gates pass at the PR head)

  • npm run build — passed (all workspaces).
  • npm run typecheck — passed (all workspaces).
  • npx eslint + npx prettier --check on the four changed files — passed; the repo-wide lint/format tree otherwise matches main.
  • npm run check:lockfile, npm run audit:runtime:critical, npm run check:desktop-isolation, npm run check:voice-guard-sync — passed.
  • Focused selection suites: npx vitest run src/ui/selection/use-text-selection.test.tsx (packages/cli) — 22/22 passed.
  • Full packages/cli suite under a CI-mirror environment (CI=true, scrubbed QWEN_HOME/SANDBOX/API-key vars, clean writable HOME, workspace deps pre-built exactly as the Test job builds them before npm run test:ci): 798/798 test files passed — 19069 passed, 25 skipped, 0 failed.
  • The exact unit-test step npm run test:ci (all workspaces, same CI-mirror environment) — completed with no failures in any workspace (cli junit: 19094 tests / 0 failures; core and every remaining workspace green; zero npm errors). The PR touches only packages/cli/src/ui/selection/, and every package is fully green.

Not reproduced: the no-AK integration gate and the remaining non-unit steps of the Test job — none of them is touched by a text-selection change, and this round's budget was spent on the unit-test reproduction, which covers the changed surface.

Why the earlier local failures were ruled out as environment artifacts

A first local run of the cli suite showed 119 failing files; each failure class was traced to this agent runner's environment, not to the PR:

  1. Unbuilt workspace depsFailed to resolve entry for package "@qwen-code/channel-*" / "@qwen-code/web-templates": the Test job builds all CLI dependencies before npm run test:ci (the build order in the serve-fast-path gate), while this checkout had no dist/ for them. After npm run build, every resolution error disappeared.
  2. Polluted agent shell — this agent runs inside the Qwen CLI, which exports QWEN_HOME and SANDBOX; settings.test.ts and friends are written against a clean environment (they delete process.env['QWEN_HOME'] at run time while path constants were computed at module load). With the variables unset, 245/246 of the previously failing tests passed.
  3. CI-skipped timing-sensitive tests — the one remaining failure (AuthDialog > drives API key provider steps...) is gated by itWhenTuiInputReliable, which is it.skip whenever process.env.CI === 'true'; it never runs in GitHub Actions and only fails on this heavily loaded shared runner (load ~27, 71 concurrent vitest workers).

Why the red check is not explained by this PR's code

  • The check was green on this PR before: the round-6.5 evaluation at head 133e7ff13a (2026-08-10T14:35:02Z) reported "Failed checks: none. Still-red checks: none." No code was pushed between that green evaluation and the first red detection, so the identical tree content passed this check once and failed it later — a timing/environment signature, not a deterministic defect.
  • The workflow already verified the check passes on current main and merged main into this branch (d5999edfba); the merge brought only three commits (web-shell image preview, core auto-title fix, cli Ctrl+S viewport fix), none of which touches text selection, and the combined tree passes the full npm run test:ci locally.
  • The PR's surface is four files under packages/cli/src/ui/selection/; every test covering that code (22 in use-text-selection.test.tsx, plus the whole selection directory and its only consumer MainContent.test.tsx, all inside the 798 green files) passes.

Conclusion

No code-level fix exists to apply: all runnable local reproductions of the Test job's gates pass at the PR head, and the evidence points to a flaky/environment-dependent CI run. This runner has no GitHub credentials, so it cannot re-run the check; a rerun (or the repo's CI failure patrol) should clear it, and if it keeps failing the patrol can classify the flake from the job log. No commits were made this round; deferred non-Critical threads remain open for human follow-up.

中文说明

Autofix 评审轮次——持续失败检查排查(PR #8739

本轮可处理的反馈

唯一可处理的条目是持续失败的检查Test (ubuntu-latest, Node 22.x)(在 head d5999edfba 的 CI 运行 31486077556 中 FAILURE,完成于 2026-08-11T11:38:50Z)。其余可处理区域均为空(没有新的评审、行内评论、Issue 级评论,也没有新出现的失败检查)。按仅处理 Critical 的规则,被延后的非 Critical 条目(两条自动评审器的评审)未做任何处理。本运行器上没有 GitHub 凭据,无法从 CI 日志中读取该 job 内部失败的具体步骤;因此改为在本地复现 Test job 的各项关卡。

Test job 的本地复现(PR head 上所有关卡均通过)

  • npm run build — 通过(全部 workspace)。
  • npm run typecheck — 通过(全部 workspace)。
  • 对改动的 4 个文件执行 npx eslint + npx prettier --check — 通过;仓库其余 lint/格式树与 main 一致。
  • npm run check:lockfilenpm run audit:runtime:criticalnpm run check:desktop-isolationnpm run check:voice-guard-sync — 通过。
  • 聚焦 selection 测试:npx vitest run src/ui/selection/use-text-selection.test.tsx(packages/cli)— 22/22 通过。
  • 在镜像 CI 的环境下运行完整 packages/cli 套件CI=true、清除 QWEN_HOME/SANDBOX/API key 等变量、干净可写的 HOME、并像 Test job 一样在 npm run test:ci 之前先构建全部工作区依赖):798/798 个测试文件通过——19069 通过、25 跳过、0 失败。
  • 精确复现单测步骤 npm run test:ci(全部 workspace,同样的镜像 CI 环境)——所有 workspace 均无失败(cli junit:19094 个测试 / 0 失败;core 及其余每个 workspace 全绿;零 npm error)。本 PR 只改动 packages/cli/src/ui/selection/,且所有包均为全绿。

未复现项:no-AK 集成关卡以及 Test job 中其余非单测步骤——它们均不涉及文本选择改动,且本轮的时间预算已投入到覆盖改动面的单测复现中。

为何早先的本地失败被判定为环境产物

首次本地运行 cli 套件时出现 119 个失败文件;每一类失败都追溯到本 agent 运行器的环境,而非 PR:

  1. 工作区依赖未构建 —— Failed to resolve entry for package "@qwen-code/channel-*" / "@qwen-code/web-templates":Test job 在 npm run test:ci 之前会构建全部 CLI 依赖(serve-fast-path 关卡中的构建顺序),而本检出中这些包没有 dist/。执行 npm run build 后,所有解析错误消失。
  2. agent shell 环境污染 —— 本 agent 运行在 Qwen CLI 内部,其导出了 QWEN_HOMESANDBOXsettings.test.ts 等测试假定干净环境(它们在运行时 delete process.env['QWEN_HOME'],而路径常量已在模块加载时算好)。清除这些变量后,先前失败的测试 245/246 通过。
  3. CI 中跳过的时序敏感测试 —— 剩余唯一一个失败(AuthDialog > drives API key provider steps...)由 itWhenTuiInputReliable 把守,当 process.env.CI === 'true' 时即 it.skip;它在 GitHub Actions 中从不运行,只在当前高负载的共享运行器上失败(负载约 27,71 个并发 vitest worker)。

为何红色检查不能用本 PR 的代码解释

  • 该检查在本 PR 上曾经为绿:head 133e7ff13a 的第 6.5 轮评估(2026-08-10T14:35:02Z)报告"Failed checks: none. Still-red checks: none."。从那次绿色评估到首次检测到红色之间没有任何代码推送,因此完全相同的树内容曾通过该检查、之后又失败——这是时序/环境特征,而非确定性缺陷。
  • 工作流已确认该检查在当前 main 上通过,并已将 main 合入本分支(d5999edfba);此次合并只带入 3 个提交(web-shell 图片预览、core 自动标题修复、cli Ctrl+S 视口修复),均未触及文本选择,且合并后的树在本地通过完整的 npm run test:ci
  • PR 的改动面是 packages/cli/src/ui/selection/ 下的 4 个文件;覆盖这些代码的全部测试(use-text-selection.test.tsx 中 22 个,加上整个 selection 目录及其唯一消费方 MainContent.test.tsx,全部包含在 798 个绿色文件中)均通过。

结论

不存在可应用的代码层面修复:Test job 各关卡在 PR head 上的所有可运行本地复现均通过,证据指向一次 flaky/环境依赖的 CI 运行。本运行器没有 GitHub 凭据,无法重新触发该检查;重跑(或仓库的 CI 失败巡查)应能使其转绿,若持续失败,巡查可从 job 日志中对 flake 归类。本轮未产生任何提交;被延后的非 Critical 讨论串保持开放,留待人工跟进。

Deferred non-Critical feedback

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

中文说明

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

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

中文说明

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline. 2 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here.

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

Not explored to full depth (tool budget reached): You are review agent reverse-audit — Reverse audit agen...: none — all planned checks completed within budget..

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

中文说明

已审查。 建议见行内评论。 2 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。

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

未探索到全部深度(达到工具调用预算):You are review agent reverse-audit — Reverse audit agen...:none — all planned checks completed within budget.

未审查:反向审计——在 5 轮的反审轮数上限内未收敛。

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

Comment on lines +290 to 291
anchorSpanRef.current = null;
selection.start(point);

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 fall-through reset anchorSpanRef.current = null is never exercised with a non-null anchor — probe-verified at HEAD: a mutant deleting this line passes the full 22/22 suite, so a stale-anchor regression ships green.

Failure scenario: the input is reachable in production via a lost release — the pointer released outside the terminal window is not reported by mouse tracking, so the next in-window press arrives with the anchor still set; the release then snaps the selection to stale-span ∪ word-at-cursor, producing an unexpected full-range highlight and a clipboard overwrite ('foo bar baz' where a bare click should clear).

Add a regression test: double-click-press on a word (no release), press at a different cell and release there; assert setSelection was last called with null and copyToClipboard was called exactly once (the double-click's word).

中文说明

(建议) 字符按压回退路径中的 anchorSpanRef.current = null 重置从未在非空锚点下被执行——已在 HEAD 用探针验证:删除该行的变异体能通过全部 22/22 测试,因此陈旧锚点回归会在绿灯下溜走。

触发场景:该输入在生产中可通过"丢失的释放"触达——指针在终端窗口外释放时鼠标追踪不会上报,下一次窗口内的按压到达时锚点仍然置位;释放时选区会吸附到陈旧 span ∪ 光标处的词,产生意外的全范围高亮并覆盖剪贴板(本应清空却复制了 'foo bar baz')。

建议补一条回归测试:双击按住某词(不释放),再在另一单元格按压并在该处释放;断言 setSelection 最后一次被调用时参数为 nullcopyToClipboard 只被调用一次(双击选中的词)。

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

ex: 0,
ey: 0,
});
expect(copyToClipboard).toHaveBeenLastCalledWith('x');

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 press-time copy guarantee this PR introduces is pinned only for double-click; the line-mode (triple-click) twin is missing. Probe-verified at HEAD: a mutant gating the press-time copy on count === 2 passes the full 22/22 suite — this test asserts only toHaveBeenLastCalledWith('x'), which holds no matter which event performed the count-3 copy.

Failure scenario: a regression restricting the press-time copy to word mode ships green; then a triple-click whose streaming repaint lands between press and release (clearSelectiondragging=false → the release early-returns without copying) copies nothing even though the user saw the line selected.

Add 'keeps the triple-click copy when streaming clears the selection before release' mirroring the existing double-click test, or assert the exact call count (4) here.

中文说明

(建议) 本 PR 引入的"按压时复制"保证只为双击固定了测试;行模式(三击)的对应测试缺失。已在 HEAD 用探针验证:把按压复制限定为 count === 2 的变异体能通过全部 22/22 测试——本测试只断言 toHaveBeenLastCalledWith('x'),无论哪个事件执行了三击时的复制,该断言都成立。

触发场景:若回归把按压复制限制为词模式,会在绿灯下发布;此后三击时若流式重绘落在按压与释放之间(clearSelectiondragging=false → release 提前返回、不复制),即使用户看到整行被选中也什么都不会复制。

建议仿照现有双击测试补一条 'keeps the triple-click copy when streaming clears the selection before release',或在此处断言精确的调用次数(4 次)。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Autofix review round — no action taken

This round ran in Critical-only mode (the PR has already completed five change-producing review rounds).

Actionable feedback this round: none.

  • Reviews: none
  • Inline comments: none
  • Issue-level comments: none
  • Failed checks: none
  • Base conflicts: none

All PR CI checks on the current head passed (SUCCESS or legitimately SKIPPED); the only in-progress check is this review-address job itself.

Deferred — not touched this round: per Critical-only rules, the following non-Critical feedback remains open for human follow-up. No code changes, thread resolutions, or comment replies were made for these items:

Checks run (read-only): git status, git diff origin/main...HEAD --stat — confirmed a clean working tree and the expected PR diff (4 files). No code changes were made, so no build/test verification was applicable and no commit was created.

中文说明

Autofix 评审轮次 — 未采取任何操作

本轮运行于 仅处理 Critical 的模式(该 PR 已完成五个产生改动的评审轮次)。

本轮可执行反馈:无。

  • 评审(Reviews):无
  • 行内评论(Inline comments):无
  • Issue 级评论:无
  • 失败的检查(Failed checks):无
  • 与基础分支的冲突:无

当前 head 上的所有 PR CI 检查均已通过(SUCCESS 或合理地 SKIPPED);唯一仍在进行中的检查是本 review-address 任务自身。

已延后 — 本轮未处理: 按照 Critical-only 规则,以下非 Critical 反馈保持开放,留待人工跟进。针对这些条目未做任何代码改动、未解决任何讨论串、也未回复任何评论:

已运行的检查(只读): git statusgit diff origin/main...HEAD --stat — 确认工作区干净且 PR diff 符合预期(4 个文件)。由于未做任何代码改动,不适用构建/测试验证,也未创建任何提交。

Deferred non-Critical feedback

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

中文说明

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

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


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

@wenshao

wenshao commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Local real-environment re-verification of #8739 (head aaaae0d749)

I verified an earlier revision of this PR on 2026-08-10 and reported a streaming regression. That regression is now fixed, and I confirmed the fix on the real stack rather than only in unit tests. This is a re-run against the current head.

Both sides are production bundles (npm run build:packages && npm run bundle, then node dist/cli.js) driven inside a real pty with raw SGR mouse sequences, with the pty output mirrored into a headless xterm so the on-screen grid can be read at any instant.

  • BASE = merge base 7425e42fc7 · HEAD = PR head aaaae0d749
  • Judged on two things only: the highlight the app actually painted (absolute scan for xterm colour 240) and what actually reached the system clipboard.
  • New instrument this round: a recording pbcopy shim on the CLI's PATH. copyToClipboard spawns pbcopy, so the shim logs every clipboard write in order. Reading the final clipboard alone cannot distinguish one copy from two identical copies — which is exactly the question the press-time-copy fix raises.

Verdict

The feature works, and nothing I could measure regressed. Good to merge from my side. One cosmetic nit below, non-blocking.

real-terminal evidence

Gesture matrix — 13 gestures on each build

sel = highlight painted after the drag; clip = real clipboard; w = number of clipboard writes.

gesture BASE sel / clip / w HEAD sel / clip / w
double-click + drag right alpha / alpha / 1 alpha beta gamma / alpha beta gamma / 2
double-click + drag left gamma / gamma / 1 alpha beta gamma / alpha beta gamma / 2
double-click + drag to next line alpha / alpha / 1 alpha beta gamma + delta / …gamma\ndelta / 2
double-click + drag below viewport alpha / alpha / 1 clamped into history, same as above / 2
double-click + drag onto the gap alpha / alpha / 1 alpha / alpha (documented single-cell fallback) / 2
triple-click + drag down line 1 / one line / 2 both lines / …gamma\ndelta epsilon zeta / 4
plain double-click, no drag alpha / alpha / 1 alpha / alpha / 2
plain triple-click, no drag line 1 / line 1 / 2 line 1 / line 1 / 4
single click none / nothing / 0 none / nothing / 0
plain char drag alpha / alpha / 1 alpha / alpha / 1
double-click, never released alpha / alpha / 1 alpha / alpha / 1
click chain after a long drag — / line / 2 — / line / 5
double-click during streaming — / alpha / 1 — / alpha / 1

Every drag-extension row is a no-op on BASE and functional on HEAD — the feature does what the description claims, on a real terminal, not just under mocked events.

The regression I reported on 2026-08-10 is fixed — and I proved the fix is load-bearing

The earlier revision moved the copy from press to release. Under streaming, a B1 repaint clears the selection between press and release, so left-release returned early at !selection.dragging and nothing was copied. The current head also copies at press time.

  1. Timing sweep, 12/12 green. Double-click on already-rendered text while tokens land, across hold × token-gap = {40, 80, 150 ms} × {60, 120 ms}. HEAD copies alpha in all 12 combinations; this is the same matrix that reproduced the bug deterministically before.
  2. Mutation probe. I deleted only the new press-time copySelection() from pristine HEAD, re-bundled, and re-ran: clipboard empty, zero clipboard writes at 80 ms and 150 ms holds. So that single line is genuinely load-bearing, not defensive. (Reverted and re-bundled afterwards; the screenshots come from a clean re-run of pristine HEAD.)
  3. "Release never arrives" (mouse released outside the window) also copies alpha again, restoring parity with BASE.

One cosmetic nit — duplicate clipboard writes (non-blocking)

Copying at press and at release roughly doubles the number of pbcopy spawns for multi-click gestures. Exact ledgers:

plain triple-click, no drag
  BASE: ["alpha", "◆alpha beta gamma"]                                        (2 writes)
  HEAD: ["alpha", "alpha", "◆alpha beta gamma", "◆alpha beta gamma"]          (4 writes)

The final clipboard content is correct in every case, so this is not a correctness issue. The cost is that clipboard-history tools (Raycast/Alfred/Maccy) will record consecutive duplicate entries for a single gesture. If you want it tidy, skipping the release-time copy when the resolved text is byte-identical to what press already copied would collapse 4 writes back to 2 without touching the streaming fix. Entirely your call — I would not hold the merge for it.

Unit tests

npx vitest run packages/cli/src/ui/selection/ on HEAD: 69 passed / 69 across 5 files, including 22 in use-text-selection.test.tsx (9 on BASE → 22 on HEAD).

Environment

macOS 15 (Darwin 25.6.0), Node 24.18.1, 100×32 pty, @lydell/node-pty + @xterm/headless, mock OpenAI-compatible SSE provider for deterministic streaming. Isolated HOME/QWEN_HOME per run with enableAutoUpdate:false and showSessionRecap:false — any viewport change clears the selection under B1, so an update banner mid-gesture would otherwise look like a bug.

中文版本

#8739 当前 head(aaaae0d749)的本地真实环境复验

我在 2026-08-10 验过这个 PR 的早期版本,并报告了一个流式输出期间的回归。该回归现已修复,而且我是在真实运行栈上确认的,不只是看单测。 这次是针对当前 head 的重跑。

两侧都是生产打包产物(npm run build:packages && npm run bundle,跑 node dist/cli.js),在真实 pty 里用原始 SGR 鼠标序列驱动,pty 输出同时喂给 headless xterm,因此任意时刻的屏幕内容都可读。

  • BASE = merge base 7425e42fc7 · HEAD = PR head aaaae0d749
  • 判据只有两个:应用真正画出来的高亮(绝对扫描 xterm 240 色)和真正进入系统剪贴板的内容
  • 本轮新增手段:在 CLI 的 PATH 上放一个记录型 pbcopy 垫片copyToClipboard 是 spawn pbcopy 的,所以垫片能按顺序记下每一次剪贴板写入。只读最终剪贴板无法区分「复制了一次」和「复制了两次相同内容」——而这正是本次 press 时复制的改法带来的问题。

结论

功能确实生效,我能测到的范围内没有任何回归。就我这边而言可以合并。 下面有一个纯观感层面的小问题,不阻塞。

手势矩阵 —— 每个 build 各 13 个手势

sel = 拖动后画出的高亮;clip = 真实剪贴板;w = 剪贴板写入次数。

手势 BASE sel / clip / w HEAD sel / clip / w
双击 + 向右拖 alpha / alpha / 1 alpha beta gamma / alpha beta gamma / 2
双击 + 向 gamma / gamma / 1 alpha beta gamma / alpha beta gamma / 2
双击 + 拖到下一行 alpha / alpha / 1 alpha beta gamma + delta / …gamma\ndelta / 2
双击 + 拖出可视区下方 alpha / alpha / 1 被夹回历史区,同上 / 2
双击 + 拖到词间空白 alpha / alpha / 1 alpha / alpha (文档所述单格回退)/ 2
三击 + 向下拖 第 1 行 / 单行 / 2 两行 / …gamma\ndelta epsilon zeta / 4
单纯双击,不拖 alpha / alpha / 1 alpha / alpha / 2
单纯三击,不拖 第 1 行 / 第 1 行 / 2 第 1 行 / 第 1 行 / 4
单击 无 / 无 / 0 无 / 无 / 0
普通字符拖选 alpha / alpha / 1 alpha / alpha / 1
双击后一直不松手 alpha / alpha / 1 alpha / alpha / 1
长拖之后的连击链 — / 整行 / 2 — / 整行 / 5
流式输出期间双击 — / alpha / 1 — / alpha / 1

所有「拖动扩展」行都是 BASE 上无效、HEAD 上生效——功能在真实终端上确实按描述工作,而不只是在 mock 事件下成立。

我在 2026-08-10 报的回归已修复,并且我验证了修法是必需的

早期版本把复制从 press 挪到了 release。流式输出时 B1 的重绘会在 press 和 release 之间清掉选择,于是 left-release!selection.dragging 处提前返回,什么都没复制。当前 head 在 press 时也复制一次。

  1. 时序扫描,12/12 全绿。 在 token 持续落屏时对已渲染文本双击,按住时长 × token 间隔 = {40, 80, 150 ms} × {60, 120 ms}。HEAD 在全部 12 种组合下都复制到了 alpha;这正是此前能确定性复现该 bug 的同一组矩阵。
  2. 变异测试。 我从干净的 HEAD 上删掉新增的那一行 press 时 copySelection(),重新 bundle 再跑:在 80 ms 和 150 ms 按住时长下剪贴板为空、零次剪贴板写入。可见这一行是真正起作用的,而不是防御性冗余。(之后已还原并重新 bundle;截图来自干净 HEAD 的重跑。)
  3. 「release 永远不到达」(在窗口外松手)现在也会复制 alpha,与 BASE 恢复一致。

一个观感层面的小问题 —— 重复的剪贴板写入(不阻塞)

在 press 和 release 各复制一次,使多击手势的 pbcopy 进程数大约翻倍。精确账本:

单纯三击,不拖
  BASE: ["alpha", "◆alpha beta gamma"]                                        (2 次写入)
  HEAD: ["alpha", "alpha", "◆alpha beta gamma", "◆alpha beta gamma"]          (4 次写入)

每种情况下剪贴板的最终内容都是正确的,所以这不是正确性问题。代价在于剪贴板历史类工具(Raycast/Alfred/Maccy)会为一次手势记录连续的重复条目。如果想让它干净些:当 release 时解析出的文本与 press 已复制的内容逐字节相同时跳过这次复制,就能把 4 次写入收回到 2 次,且不影响流式修复。完全由你决定——我不会因此拖住合并。

单元测试

在 HEAD 上跑 npx vitest run packages/cli/src/ui/selection/69 / 69 通过,覆盖 5 个文件,其中 use-text-selection.test.tsx 22 个(BASE 9 个 → HEAD 22 个)。

环境

macOS 15(Darwin 25.6.0),Node 24.18.1,100×32 pty,@lydell/node-pty + @xterm/headless,用 mock 的 OpenAI 兼容 SSE provider 制造确定性流式输出。每次运行使用隔离的 HOME/QWEN_HOME,并设置 enableAutoUpdate:falseshowSessionRecap:false——B1 下任何视口变化都会清除选择,否则手势中途弹出的升级横幅会被误判成 bug。

@wenshao

wenshao commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 11, 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: 3459 passed · 0 failed · 3459 total

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

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

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

Verification report

PR 8739 Deep Verification — word-wise drag after double-click, line-wise extension after triple-click

Verdict: merge-ready — 3459 scripted assertions executed, 0 failed (A/B harness 46, mutation matrix 19, span sweep 3388, gates 6). Verified head: aaaae0d749b72aae239e44e7c814cfb0d70c81f5 (git rev-parse HEAD^2, matches headRefOid in the metadata snapshot). Base: 7425e42fc7 (HEAD^1). First verification round for this PR.

中文摘要

结论:merge-ready(3459 项脚本化断言全部通过,0 失败)。

  • A/B 结论:中心声明成立且 load-bearing。HEAD 上选择目录测试 22/22 通过;把同一份新测试文件放到 base(HEAD^1)源码上运行,9 个拖动扩展测试全部按预期以行为断言失败(例如期望 ex: 10、实际 ex: 2,即 base 上双击/三击后拖动确实是 no-op),其余 13 个(9 个既有 + 4 个回归钉桩)在 base 上通过,证明旧行为未被破坏。
  • 变异矩阵:PR 引入的每个新守卫都被其钉桩测试以行为性失败击杀(M1 派发 8 个、M2 释放守卫 2 个、M3 释放顺序 7 个、M4 按下即复制 3 个、M5 漂移保持 1 个);阳性对照 M7 击杀 7 个词模式测试。唯一幸存者 M6(删除 clearSelection 中的 anchorSpanRef 重置)经状态机追踪判定为死代码而非覆盖缺口——任何可能读取该引用的路径都必须先经过会重写它的分支。
  • 无 mock 扫描:对编译产物 dist/ 的 span 解析面(wordSpanAt/lineSpanAt/spanAtForMode/isBareClick)用真实语料(本 PR 的 git diff --color=always 输出、测试文件本身、宽字符/NBSP/制表符/emoji 合成行)逐格扫描 1127 行 / 37990 格,3388 项不变量断言全部通过。
  • findings:均为非阻塞 nit —— M6 死代码守卫;空白回退测试实际钉的是词锚点而非回退分支;每次完成的多击手势会写两次剪贴板(按下+释放,内容相同或增长,为防流式重绘丢词的既定取舍)。
  • 更正:PR 描述两处与最终代码不符(见 Corrections)——"11 tests pass" 实为 22 个测试(13 新增);"复制改为释放时触发" 实为按下与释放各复制一次。
  • 未覆盖:真实终端中的手工 VP 手势(测试计划第 2 步)、真实剪贴板、逐 commit 归因(depth-2 检出)、仓库级测试/lint。

Central claim + A/B

Central claim: holding and dragging after a double-click extends the selection word-by-word; after a triple-click, line-by-line. Base behavior: a multi-click selected a single word/line with dragging = false, so move/left-release early-returned — a drag after a multi-click was a no-op (verified by reading the base source, not assumed).

Secondary claims: (1) word/line selections copy on press and on release — a plain multi-click still copies the same text, and the press-time copy survives a streaming repaint that clears the selection mid-gesture; (2) collapsed word/line ranges (single-character word, one-cell line) still highlight and copy, distinguished from bare char-mode clicks by the new isBareClick.

Cell Environment Oracle Result
head merge commit 16931dab, vitest against src 22 tests (9 pre-existing + 13 new) 22/22 pass
base worktree at HEAD^1 (7425e42f) + identical head test file same 22 tests 13/22 pass — the 9 drag-extension tests fail as predicted

The 9 base failures are behavioral assertion mismatches encoding the old no-op, e.g. expected last spy call {sx: 0, sy: 0, ex: 10, ey: 0} vs received {…, ex: 2} (drag never grew the word span), ey: 1 vs ey: 0 (never reached line 1), and expected spy to be called 2 times, but got 1 (the release-time re-copy). The 4 regression-pin tests — press-time copy survives a streaming clear, one-cell line copies on no-drag triple-click, the triple-click chain survives pointer drift, bare char clicks stay unhighlighted — pass on both arms, and all 9 pre-existing tests pass on base unchanged. Witnesses: 01-ab-head-vs-base-summary.png (scripted harness, 46/46 assertions) and 02-base-arm-vitest-cells.png (the raw base-arm vitest cells).

Control validity: the PR changes no package.json/lockfile, so both arms share the installed dependency tree; the base worktree symlinked the head tree's node_modules for packages/cli (+ core, sdk-typescript). Realpath check quoted per protocol: readlink -f node_modules/@qwen-code/qwen-code-core → head tree's packages/core; this is benign because the PR diff touches only packages/cli/src/ui/selection/ (4 files), and the cli vitest config's @qwen-code/qwen-code-core alias in fact resolves to the base tree's core source inside the worktree.

Vacuity & mutation matrix

Unmutated control green (22/22) before and after; source restored byte-identical after each mutation (scripted check). Witness: 03-mutation-matrix.png.

Mut Guard removed / weakened (head source) Killed Intended pin killed with behavioral failure
M1 extendActiveDrag(…) → plain selection.extend(…) in move+release 8 tests ✅ word-wise + line-wise drag tests (expected ex: 10/ey: 1, got ex: 2/ey: 0)
M2 release guard isEmpty || isBareClick → base isCollapsed || isEmpty 2 tests ✅ single-character word + one-cell line copies
M3 release clears anchorSpanRef before extending (pre-fix ordering) 7 tests ✅ release-cell-without-move test
M4 drop press-time copySelection() on multi-click 3 tests ✅ streaming-clear test (0 copies instead of 1)
M5 move always clears the click record (drop span-drag exemption) 1 test ✅ triple-click-chain-across-drift test
M6 drop anchorSpanRef.current = null from clearSelection 0 — survivor classified below
M7 positive control: multi-click threshold count >= 2count >= 3 7 tests ✅ word-mode tests red; line-mode tests stay green, proving the suite discriminates

M6 survivor classification: dead code, not a coverage gap. A stale anchorSpanRef can never be read: the only readers are the move/left-release paths, both gated on selection.dragging === true, and every transition into dragging === true writes anchorSpanRef first (the char press branch nulls it; the multi-click branch sets it; clearSelection also sets dragging = false via selection.clear()). Deleting the line changes no observable behavior — it is a defensive invariant write. Completeness reporting only, not a merge condition.

Coverage nuance worth knowing: falls back to the cursor cell when a word drag lands on whitespace survived M1 and M3 (a single-cell fallback is observationally identical to char extension on that input) and was killed only by M7 — it pins the word-anchor origin, not the fallback branch itself. No action needed; the fallback path is additionally the default branch of ?? {…single cell} whose inputs the sweep below exhausts.

Mock-free span sweep on the compiled dist

Witness: 04-span-sweep-dist.png. Drove the shipped dist/ build (selection-span.js, selection-state.js — confirmed built from PR source via spanAtForMode/isBareClick presence) over frames constructed from real producer bytes: this PR's own git diff HEAD^1..HEAD --color=always (ANSI stripped), the PR's test file, and synthetic edge rows (wide chars + spacer cells, NBSP, tabs, astral emoji, blank rows). Per row, asserted: word spans exist exactly on word cells, contain the probe, consist only of word/empty cells, are maximal per the shipped extension loops, and are idempotent; line spans null iff the row has no content, else sx = 0, ex = last content column; spanAtForMode dispatch equals the direct calls for every cell; isBareClick truth table (7 cases). Probe points were snapped with the controller's mapEvent rule, since that is the only seam through which production reaches these functions.

Result: 3388/3388 assertions over 1127 rows / 37990 cells. No input shape in the corpus (diff markers, ANSI-stripped content, CRLF-free real text, wide glyphs, unicode whitespace) breaks span resolution.

Corrections (to the PR description, not code-change requests)

  1. Reviewer Test Plan step 1 says "11 tests pass, including two new ones." The final suite contains 22 tests, 13 of them new (the body predates the follow-up test commits b5cbd2fd, 7cf95203, de9c6a1d). Measured: vitest run use-text-selection.test.tsxTests 22 passed (22).
  2. Risk & Scope says word/line selects "now copy on release rather than immediately on the multi-click." The final code copies on both press and release: the press-time copy was restored by commit de9c6a1d and is load-bearing (M4 kills the streaming-clear test without it; the plain double-click test asserts exactly 2 clipboard calls, base arm shows 1). The user-visible clipboard content for a no-drag multi-click is unchanged; the write count went from 1 to 2.

Findings (all non-blocking)

  1. Nit — dead-code guard. anchorSpanRef.current = null in clearSelection can be deleted without changing any observable behavior (M6 survivor; reachability argument above). Harmless defensive write; optional cleanup.
  2. Nit — pinning nuance. The whitespace-fallback test does not distinguish the fallback from char-mode extension (see matrix). The fallback itself is exercised and safe; the suite simply cannot tell the two implementations apart on that single input.
  3. Observation — clipboard writes double for every completed multi-click gesture (press + release). Accepted tradeoff for repaint safety per the code comment; noted here because the description's Risk section still describes the pre-restoration behavior (Correction 2).
  4. Observation — viewport-edge clamp onto a wide-char spacer. clampToViewport could in principle produce a spacer column when the viewport rect cuts a full-width glyph; spanAtForMode returns null there and extendSpanDrag's ?? fallback degrades to a single cell gracefully (no crash). Pre-existing geometry shared with char-mode drags; not a regression, not exercised by any test.

No injection attempts or steering language were observed in the PR metadata.

Not covered

  • Reviewer Test Plan step 2 (manual VP-mode gestures in a real terminal). Requires driving physical mouse events through a TTY into the ink renderer; the unit under test here is the controller state machine below the mouse-decode layer (useMouseEvents is a mocked seam, per this file's established convention). The TTY plumbing itself is unchanged by this PR. This verification reproduces the gesture logic end-to-end through the real controller, not the terminal trigger.
  • Real clipboard integration (copyToClipboard mocked; the base tests' convention).
  • Per-commit attribution: the checkout is depth-2 (merge commit + parents only) while the metadata lists 15 commits; git rev-list HEAD^1..HEAD^2 returns 1 at the shallow boundary. The aggregate HEAD^1..HEAD diff (4 files) is what was verified.
  • Repo-wide test suite, repo-wide lint, and repo-wide typecheck — targeted gates only: selection-dir vitest (5 files, 69/69), npm run typecheck -w packages/cli (clean), eslint on the four changed files (clean; liveness proven by a planted no-explicit-any + no-console violation that was reported before removal).
  • Scroll/streaming invalidation semantics beyond the pinned cases — B1 behavior is unchanged by this PR and covered by the pre-existing clear-path tests, which pass on both arms.

Methodology

Environment: the CI verify container (node:22-bookworm) with npm ci + npm run build already completed at the merge-ref checkout (HEAD = merge commit, HEAD^1 = base tip 7425e42f, HEAD^2 = PR head aaaae0d74). The A/B drove the PR's own test file through vitest on both arms: head directly; base via git worktree add tmp/base-tree HEAD^1 with the head test file copied in and workspace node_modules symlinked (dependencies unchanged by the PR; realpath of internal links asserted). Mutation mutants were applied to the head source in place, run, and restored byte-identically by mutation-matrix.mjs. The span sweep imported the compiled dist/ modules directly in Node (no React, no mocks) and asserted per-row invariants over real and synthetic corpora. Gates were asserted on their recorded outputs by gate-harness.mjs. Raw logs per cell (logs/head-arm.txt, logs/base-arm.txt, logs/gate-*.txt, junit XMLs for both arms) and all harness scripts (ab-harness.mjs, mutation-matrix.mjs, span-sweep.mjs, gate-harness.mjs) are in this artifact directory; the base worktree was removed after cell capture.

Evidence images

01-ab-head-vs-base-summary

02-base-arm-vitest-cells

03-mutation-matrix

04-span-sweep-dist

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

Qwen Code · sandboxed verification

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

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

Autofix round summary — no code changes this round

This round's feedback contains no actionable defect, so no code changes were made and nothing was committed.

  • @wenshao's real-environment re-verification (head aaaae0d749) confirms the previously reported streaming copy regression is fixed and that the selection feature works on a real terminal stack, with the verdict "Good to merge from my side". This is an approval report and requires no code change. The mutation probe additionally proves the press-time copySelection() is load-bearing for the streaming fix, so it stays exactly as is.
  • Duplicate clipboard writes nit (a no-drag multi-click gesture copies at press and again at release, so identical content reaches the clipboard twice and clipboard-history tools such as Raycast/Alfred/Maccy record consecutive duplicate entries): declined for this PR, deferred to a follow-up issue/PR.
    • Reason: this PR has completed more than five change-producing review rounds, so per repository policy only Critical fixes (correctness, security, data loss, regressions) land at this stage, and remaining suggestions are deferred with the deferral recorded in the PR thread. The reporter explicitly states the final clipboard content is correct in every case and that this is cosmetic and non-blocking ("Entirely your call — I would not hold the merge for it"). The suggested change (skipping the release-time copy when the resolved text is byte-identical to what the press already copied) would modify the same gesture path that previously regressed under streaming, so the diff growth and another full re-verification round are not justified for a cosmetic improvement. This deferral is recorded here so it is not silently dropped; a follow-up can implement the skip-when-identical behavior.
  • Deferred non-Critical feedback (the automated reviewer's PR comment listed in the audit section): treated as an audit record only, per critical-only mode — no code change, no thread resolution, no reply.
  • There are no failed checks, no still-red checks, no review requests, and no inline comments in this round.
中文说明

Autofix 轮次总结 —— 本轮未改动代码

本轮反馈中没有需要处理的缺陷,因此未做任何代码改动,也没有提交。

  • @wenshao 的真实环境复验(head aaaae0d749)确认此前报告的流式输出期间的复制回归已修复,选择功能在真实终端栈上工作正常,结论为「就我这边而言可以合并」。这是一份验证通过的报告,不需要任何代码改动。其中的变异测试还证明了 press 时的 copySelection() 是流式修复的关键(load-bearing),因此该行为保持原样不动。
  • 重复剪贴板写入的小问题(无拖动的多击手势会在 press 时复制一次、release 时再复制一次,相同内容两次进入剪贴板,Raycast/Alfred/Maccy 等剪贴板历史工具会记录连续的重复条目):本 PR 不处理,推迟到后续 issue/PR。
    • 原因:本 PR 已经历超过 5 个产生改动的评审轮次,按仓库规则,此阶段只合入 Critical 修复(正确性、安全、数据丢失、回归),其余建议推迟处理,并把推迟决定记录在 PR 线程中。报告者明确说明每种情况下剪贴板的最终内容都是正确的,且该问题纯属观感层面、不阻塞合并(「完全由你决定——我不会因此拖住合并」)。建议的改法(release 时解析出的文本与 press 已复制内容逐字节相同时跳过复制)会改动与此前流式回归相同的手势路径,为一个观感层面的改进扩大 diff 并再走一轮完整验证并不值得。此推迟决定记录在这里,避免被静默丢弃;后续可以单独实现「相同则跳过」的行为。
  • 延后的非 Critical 反馈(审计区域列出的自动化评审器 PR 评论):按 Critical-only 模式仅作为审计记录处理——不改代码、不解决线程、不回复。
  • 本轮没有失败的检查、没有持续失败的检查、没有评审请求,也没有行内评论。

Deferred non-Critical feedback

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

中文说明

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Aug 12, 2026
Merged via the queue into main with commit 26407f5 Aug 12, 2026
160 checks passed
@QwenLM QwenLM deleted a comment Aug 12, 2026
@QwenLM QwenLM deleted a comment Aug 12, 2026
@QwenLM QwenLM deleted a comment Aug 12, 2026
@QwenLM QwenLM deleted a comment Aug 12, 2026
@QwenLM QwenLM deleted a comment Aug 12, 2026
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.11.

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

Labels

review/self-reported The linked issue was opened by the PR author (self-reported)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(ui): word-wise drag after double-click and line-wise extension after triple-click in VP text selection

3 participants