Skip to content

feat(core): add NotebookEdit tool for Jupyter notebooks#3900

Merged
zhangxy-zju merged 13 commits into
mainfrom
feature/notebook-edit-2816
May 20, 2026
Merged

feat(core): add NotebookEdit tool for Jupyter notebooks#3900
zhangxy-zju merged 13 commits into
mainfrom
feature/notebook-edit-2816

Conversation

@zhangxy-zju

@zhangxy-zju zhangxy-zju commented May 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #2816.
Partially addresses #351.

Qwen Code already has structured notebook reading through read_file: .ipynb files are parsed and rendered as ordered notebook cells with cell IDs, source, and outputs. This PR builds on that existing read path and adds the missing write/edit side:

  • Adds a dedicated notebook_edit / NotebookEdit tool for safe cell-level .ipynb edits.
  • Reuses and extends notebook utilities for JSON parsing, source serialization, deterministic cell id generation, displayed cell lookup, and ambiguous cell id detection.
  • Integrates NotebookEdit into tool registration, bare mode defaults, Claude tool conversion, filesystem path extraction, and permission/rule handling.
  • Updates read-file cache semantics so truncated notebook renders are not treated as full prior reads.
  • Keeps raw .ipynb mutation out of generic text Edit / WriteFile paths while allowing structured NotebookEdit operations after a fresh full notebook read.
  • Supports IDE/inline modification of the full proposed notebook diff via ModifiableDeclarativeTool.
  • Records AI-originated NotebookEdit writes with CommitAttributionService.
  • Adds CLI integration coverage that runs the real bundled CLI, verifies read_file precedes notebook_edit, and checks the final notebook JSON.

Existing notebook read support

The current codebase already detects .ipynb as a notebook file type and routes it through the notebook reader. That reader parses the JSON notebook and returns a model-friendly representation instead of exposing raw notebook JSON. The rendered form includes:

  • notebook language and cell count in the header,
  • ordered cell blocks,
  • stable target identifiers from real notebook cell IDs or rendered cell-N fallbacks,
  • cell type and source,
  • summarized outputs with truncation markers when needed.

That behavior is intentionally read-only today. It gives the model enough context to understand and reference notebook cells, but it does not provide a structured mutation primitive. Using the existing text Edit / WriteFile tools on raw .ipynb JSON is unsafe because a notebook is a structured document: editing the JSON text directly can corrupt cell metadata, outputs, execution counts, source array formatting, or notebook-level invariants.

Design

This PR closes that gap by making NotebookEdit the structured counterpart to the existing notebook read path.

The intended workflow is:

  1. The model calls read_file on a .ipynb file.
  2. read_file returns the existing structured notebook rendering with cell IDs.
  3. The model calls notebook_edit, targeting one rendered cell by real cell id or displayed cell-N fallback.
  4. NotebookEdit reloads the notebook JSON, applies a cell-level operation, normalizes the affected cell, writes valid notebook JSON back, and returns a diff for confirmation/display.

The tool supports three edit modes:

  • replace: replace an existing cell's source and optionally convert its type.
  • insert: insert a new cell after a target cell, or at the beginning when no target is provided.
  • delete: remove an existing cell.

NotebookEdit performs notebook-aware normalization during writes:

  • Code cell edits clear stale outputs and reset execution_count.
  • Markdown/raw final cells drop code-only fields.
  • Replaced cells preserve the existing source representation where possible.
  • Inserted cells infer the notebook's existing source style.
  • nbformat 4.5+ inserted cells receive deterministic non-conflicting qwen-cell-N ids, avoiding collisions with rendered cell-N fallback ids.
  • Existing file metadata such as BOM, encoding, and line endings is preserved through FileSystemService.

Review feedback fixes

Latest follow-up review fixes:

  • read_file now normalizes an empty pages parameter to unset and rejects non-empty pages for .ipynb files, so notebook reads cannot be cached as partial merely because a PDF-only parameter was supplied.
  • parseNotebook() now strips a leading UTF-8 BOM before JSON.parse, allowing BOM-prefixed notebooks to be read and used as the prior-read basis for NotebookEdit.

This update addresses the requested changes from review:

  • Cell targeting now matches the exact IDs rendered by read_file. A fallback-like real id such as cell-1 no longer also makes cell-0 target the first cell by position.
  • Ambiguous rendered IDs are rejected before editing. If a real cell id collides with a fallback cell-N display id, NotebookEdit returns INVALID_TOOL_PARAMS instead of guessing.
  • Generated notebook cell ids now use the qwen-cell-N namespace and avoid all rendered display ids, so they cannot collide with positional fallback ids.
  • Structural edits invalidate the prior-read cache when fallback ids can shift. Follow-up edits must re-read unless all cells have stable real ids before and after the edit.
  • NotebookEdit now implements ModifiableDeclarativeTool, so IDE/inline changes to the proposed notebook diff are applied instead of silently discarded.
  • Successful AI-originated NotebookEdit writes call CommitAttributionService.recordEdit; user-modified proposals follow the existing Edit/WriteFile behavior and skip AI attribution.
  • Bare-mode config tests now include notebook_edit in the expected default toolset.

Prior-read and cache behavior

Notebook edits still need the same safety guarantee as text edits: the model should only mutate a file it has already read. However, the existing notebook reader returns a structured rendering, not the exact raw JSON bytes, so generic text edit prior-read semantics are too broad.

This PR keeps those concerns separated:

  • Generic Edit and WriteFile continue to reject notebooks as non-cacheable structured payloads.
  • NotebookEdit has a notebook-specific prior-read check that accepts a fresh full notebook read.
  • Truncated notebook reads do not satisfy the prior-read requirement, because the model may not have seen the target cell or later notebook state.
  • After NotebookEdit writes, the cache is refreshed as a non-cacheable structured write only when displayed cell identifiers remain stable. If structural edits can shift rendered fallback ids, the cache is invalidated and the next NotebookEdit requires a fresh full read.

This preserves the existing read behavior while adding a controlled write path that matches the representation the model actually saw.

Testing

Latest unit-test coverage update (1eaf0112a):

npm test --workspace=packages/core -- --run src/tools/notebook-edit.test.ts
npm test --workspace=packages/core -- --run src/tools/notebook-edit.test.ts src/tools/read-file.test.ts src/utils/notebook.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.test.ts packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.test.ts packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts
git diff --check
npm run build --workspace=packages/core

Latest follow-up validation (af0303a28):

npm test --workspace=packages/core -- --run src/tools/read-file.test.ts src/utils/notebook.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts
git diff --check
npm run build --workspace=packages/core

Latest docs-update validation (8b1d7ebdd):

./node_modules/.bin/prettier --check docs/developers/tools/file-system.md docs/users/configuration/settings.md docs/users/features/approval-mode.md docs/developers/sdk-typescript.md packages/sdk-typescript/README.md docs/developers/sdk-java.md packages/sdk-java/qwencode/README.md packages/sdk-java/qwencode/QWEN.md
git diff --check

Latest review-update validation (d0e8e9adc):

npm test --workspace=packages/core -- --run src/utils/notebook.test.ts src/tools/notebook-edit.test.ts src/utils/readManyFiles.test.ts src/tools/edit.test.ts src/tools/write-file.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts
git diff --check
npm run build --workspace=packages/core

Latest review-update validation (d3de6e005):

npm test --workspace=packages/core -- --run src/tools/notebook-edit.test.ts src/utils/readManyFiles.test.ts src/tools/edit.test.ts src/tools/write-file.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts
npm run build --workspace=packages/core

Latest review-update validation (5ad5cb4b2):

npm test --workspace=packages/core -- --run src/utils/notebook.test.ts src/tools/notebook-edit.test.ts src/tools/read-file.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/tools/read-file.ts packages/core/src/tools/read-file.test.ts packages/core/src/tools/tool-error.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/tools/read-file.ts packages/core/src/tools/read-file.test.ts packages/core/src/tools/tool-error.ts
npm run build --workspace=packages/core

Earlier validation retained below.

Validated locally with:

npx prettier --write packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/config/config.test.ts
npx eslint packages/core/src/config/config.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts
npx vitest run packages/core/src/utils/notebook.test.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/services/fileReadCache.test.ts packages/core/src/tools/read-file.test.ts packages/core/src/core/coreToolScheduler.test.ts
npx vitest run packages/core/src/config/config.test.ts
npm run typecheck --workspace=packages/core
npm run build
npm run bundle
QWEN_SANDBOX=false npx vitest run --root ./integration-tests cli/notebook-edit.test.ts --poolOptions.threads.minThreads 1 --poolOptions.threads.maxThreads 1
git diff --check

Also ran npm run test --workspace=packages/core. The original config.test.ts failures are fixed. The full parallel run later hit two unrelated 5s timeout flakes in grep.test.ts and background-agent-resume.test.ts; both timed-out tests passed when rerun individually:

npx vitest run packages/core/src/tools/grep.test.ts -t "only reports result paths for matches visible before character truncation"
npx vitest run packages/core/src/agents/background-agent-resume.test.ts -t "passes the sidechain transcript path to SubagentStop hooks on resume"

Also ran npx tsc --noEmit -p integration-tests/tsconfig.json; it currently fails on existing integration-test baseline type errors outside this new test file, including channel-plugin.test.ts, write_file.test.ts, @lydell/node-pty typings, and terminal-capture DOM globals.

Review focus / test areas

  • NotebookEdit as the write counterpart to the existing notebook read_file rendering.
  • Permission rule behavior for NotebookEdit, including Edit meta-category matching.
  • Prior-read behavior for fresh full notebook reads versus stale or truncated reads.
  • Cache behavior after structural edits on notebooks with stable ids versus rendered fallback ids.
  • Preventing generic text Edit / WriteFile from mutating notebook JSON directly.
  • Cell targeting by real notebook ids and rendered cell-N ids, including ambiguous fallback-like ids.
  • IDE/inline modified proposed notebook content.
  • Code to markdown/raw conversion and clearing stale code outputs.
  • Claude compatibility through NotebookEdit tool conversion.
  • CLI E2E behavior with real model/tool telemetry for replace, insert, and delete notebook operations.

@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 76.96% 76.96% 79.65% 79.88%
Core 79.6% 79.6% 82.26% 82.84%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   76.96 |    79.88 |   79.65 |   76.96 |                   
 src               |   75.94 |     69.2 |   81.08 |   75.94 |                   
  gemini.tsx       |   68.69 |    66.66 |   77.77 |   68.69 | ...29,946-949,961 
  ...ractiveCli.ts |   80.23 |     68.3 |   78.57 |   80.23 | ...1054,1092,1195 
  ...liCommands.ts |   74.51 |    73.17 |     100 |   74.51 | ...41-265,290,391 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   61.97 |    65.24 |   78.12 |   61.97 |                   
  acpAgent.ts      |   63.32 |    65.35 |   83.05 |   63.32 | ...2112,2126-2134 
  authMethods.ts   |   12.19 |      100 |       0 |   12.19 | 11-31,34-38,41-50 
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   68.65 |    83.33 |   66.66 |   68.65 |                   
  filesystem.ts    |   68.65 |    83.33 |   66.66 |   68.65 | ...32,77-94,97-98 
 ...ration/session |   75.88 |    72.05 |   86.25 |   75.88 |                   
  ...ryReplayer.ts |   67.34 |     75.6 |   81.81 |   67.34 | ...54-269,282-283 
  Session.ts       |   74.93 |    70.81 |   88.46 |   74.93 | ...2658,2664-2667 
  ...entTracker.ts |   90.85 |    84.84 |      90 |   90.85 | ...35,199,251-260 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   84.21 |    77.77 |     100 |   84.21 | ...37-153,209-211 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ssion/emitters |   96.01 |    90.75 |    92.3 |   96.01 |                   
  BaseEmitter.ts   |   76.92 |    66.66 |      80 |   76.92 | 23-24,39-40,55-56 
  ...ageEmitter.ts |     100 |    89.47 |     100 |     100 | 109,111           
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   98.06 |     92.3 |     100 |   98.06 | 227-228,327,335   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |   90.36 |    87.83 |   94.11 |   90.36 |                   
  LlmRewriter.ts   |      81 |       84 |     100 |      81 | ...,88-89,155-159 
  ...Middleware.ts |   95.83 |    85.71 |     100 |   95.83 | 119,127-129       
  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/auth          |    97.7 |    94.81 |   95.45 |    97.7 |                   
  allProviders.ts  |     100 |      100 |     100 |     100 |                   
  ...iderConfig.ts |    97.6 |    95.04 |     100 |    97.6 | ...61,411,433-434 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/auth/install  |   98.57 |    88.88 |     100 |   98.57 |                   
  ...nstallPlan.ts |   98.57 |    88.88 |     100 |   98.57 | 80,93             
 ...viders/alibaba |   96.96 |    66.66 |   66.66 |   96.96 |                   
  ...baStandard.ts |     100 |      100 |     100 |     100 |                   
  codingPlan.ts    |   93.67 |    66.66 |   66.66 |   93.67 | 83,87-89,94       
  tokenPlan.ts     |     100 |      100 |     100 |     100 |                   
 ...oviders/custom |     100 |      100 |     100 |     100 |                   
  ...omProvider.ts |     100 |      100 |     100 |     100 |                   
 ...roviders/oauth |    91.5 |    77.03 |   97.05 |    91.5 |                   
  openrouter.ts    |   84.37 |    33.33 |     100 |   84.37 | 43-48             
  ...outerOAuth.ts |    91.9 |    79.06 |   96.87 |    91.9 | ...53-655,699-701 
 ...ers/thirdParty |     100 |      100 |     100 |     100 |                   
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/commands      |   47.93 |    85.71 |   43.47 |   47.93 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   94.73 |      100 |      50 |   94.73 | 28                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
  serve.ts         |    7.74 |      100 |       0 |    7.74 | ...51-147,149-230 
 ...mmands/channel |   39.25 |    79.45 |      50 |   39.25 |                   
  ...l-registry.ts |    8.57 |      100 |       0 |    8.57 | 6-21,24-42        
  config-utils.ts  |      92 |      100 |   66.66 |      92 | 21-26             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   30.98 |       52 |   69.23 |   30.98 | ...72-475,484-486 
  status.ts        |   17.85 |      100 |       0 |   17.85 | 15-26,32-76       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |    84.5 |    88.95 |   81.81 |    84.5 |                   
  consent.ts       |   71.65 |    89.28 |   42.85 |   71.65 | ...85-141,156-162 
  disable.ts       |     100 |      100 |     100 |     100 |                   
  enable.ts        |     100 |      100 |     100 |     100 |                   
  install.ts       |    75.6 |    66.66 |   66.66 |    75.6 | ...39-142,145-153 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |      100 |     100 |     100 |                   
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  uninstall.ts     |    37.5 |      100 |   33.33 |    37.5 | 23-45,57-64,67-70 
  update.ts        |   96.32 |      100 |     100 |   96.32 | 101-105           
  utils.ts         |   60.24 |    28.57 |     100 |   60.24 | ...81,83-87,89-93 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 src/commands/mcp  |   92.29 |    86.08 |   88.88 |   92.29 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 293               
  list.ts          |   91.22 |    80.76 |      80 |   91.22 | ...19-121,146-147 
  reconnect.ts     |   76.72 |    71.42 |   85.71 |   76.72 | 35-48,153-175     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   11.57 |      100 |       0 |   11.57 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   11.32 |      100 |       0 |   11.32 | ...41-153,155-156 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 src/config        |   92.79 |    84.88 |   88.09 |   92.79 |                   
  auth.ts          |   86.98 |    80.32 |     100 |   86.98 | ...26-227,243-244 
  config.ts        |   87.96 |    84.36 |      80 |   87.96 | ...1856,1858-1866 
  keyBindings.ts   |   96.55 |       50 |     100 |   96.55 | 193-196           
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  settings.ts      |   85.76 |    87.25 |   89.18 |   85.76 | ...1148,1153-1156 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.22 |       94 |     100 |   96.22 | ...88-190,205-206 
 ...nfig/migration |   94.89 |    78.94 |   83.33 |   94.89 |                   
  index.ts         |   94.87 |    88.88 |     100 |   94.87 | 91-92             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.74 |       96 |     100 |   94.74 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.19 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   63.09 |    64.51 |   55.55 |   63.09 |                   
  ...tputBridge.ts |   62.94 |    65.51 |   56.25 |   62.94 | ...22-323,331-334 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   81.47 |    75.94 |   65.71 |   81.47 |                   
  index.ts         |   63.68 |    69.56 |   53.84 |   63.68 | ...70-271,281-286 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,184   
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |   72.57 |    71.12 |   74.07 |   72.57 |                   
  session.ts       |   76.64 |     69.4 |   85.71 |   76.64 | ...23-824,833-843 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...80-581,584-585 
 ...active/control |   77.04 |    88.23 |      80 |   77.04 |                   
  ...rolContext.ts |    7.14 |        0 |       0 |    7.14 | 49-84             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...54-372,388,391 
  ...rolService.ts |       8 |        0 |       0 |       8 | 46-179            
 ...ol/controllers |    7.03 |       80 |   13.33 |    7.03 |                   
  ...Controller.ts |   19.32 |      100 |      60 |   19.32 | 81-118,127-210    
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    3.94 |      100 |   11.11 |    3.94 | ...63-381,391-496 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |    5.21 |      100 |       0 |    5.21 | ...21-433,442-471 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   97.98 |     93.7 |   95.18 |   97.98 |                   
  ...putAdapter.ts |   97.89 |    92.82 |   98.07 |   97.89 | ...1303,1398-1399 
  ...putAdapter.ts |      96 |     90.9 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.28 |      100 |      90 |   98.28 | 81-82,122-123     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |    79.3 |     78.8 |   92.85 |    79.3 |                   
  auth.ts          |   88.49 |    88.63 |     100 |   88.49 | ...49-150,153-155 
  capabilities.ts  |     100 |     90.9 |     100 |     100 | 264               
  ...usProvider.ts |   67.01 |    51.42 |     100 |   67.01 | ...40-245,278-286 
  debugMode.ts     |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  envSnapshot.ts   |    92.3 |       84 |     100 |    92.3 | 108-111,170-177   
  eventBus.ts      |     100 |      100 |     100 |     100 |                   
  httpAcpBridge.ts |   79.62 |    78.84 |   96.38 |   79.62 | ...4246,4277-4318 
  ...oryChannel.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-106             
  loopbackBinds.ts |     100 |      100 |     100 |     100 |                   
  runQwenServe.ts  |   73.98 |    87.83 |   55.55 |   73.98 | ...94-710,735-737 
  server.ts        |   86.18 |    82.94 |   90.62 |   86.18 | ...2478,2543-2552 
  status.ts        |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...paceAgents.ts |   64.87 |    70.45 |    90.9 |   64.87 | ...1306,1316-1326 
  ...paceMemory.ts |   87.13 |    78.46 |     100 |   87.13 | ...54-361,421-428 
 src/serve/auth    |   86.54 |    78.75 |   93.75 |   86.54 |                   
  deviceFlow.ts    |   96.33 |    79.51 |    97.5 |   96.33 | ...1526,1630,1700 
  ...owProvider.ts |   45.23 |    74.07 |      75 |   45.23 | ...90-359,375,379 
 src/serve/fs      |   84.85 |    79.75 |     100 |   84.85 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 201               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.82 |    77.08 |     100 |   77.82 | ...64,493-497,510 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...FileSystem.ts |   83.55 |    76.22 |     100 |   83.55 | ...1859,1886-1887 
 src/serve/routes  |   89.41 |       70 |     100 |   89.41 |                   
  ...ceFileRead.ts |   94.41 |    76.92 |     100 |   94.41 | ...28-329,390-392 
  ...eFileWrite.ts |    82.1 |    60.52 |     100 |    82.1 | ...42-244,247-249 
 src/services      |   91.67 |    91.21 |   97.56 |   91.67 |                   
  ...mandLoader.ts |     100 |    93.75 |     100 |     100 | 93                
  ...killLoader.ts |     100 |    96.15 |     100 |     100 | 47                
  ...andService.ts |    98.7 |      100 |     100 |    98.7 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.84 |    80.64 |   83.33 |   75.84 | ...10-211,277-278 
  ...mandLoader.ts |     100 |      100 |     100 |     100 |                   
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.21 |    96.66 |     100 |   98.21 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |    85.9 |    85.61 |   90.47 |    85.9 |                   
  DataProcessor.ts |   85.63 |     85.6 |   92.85 |   85.63 | ...1122,1126-1133 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...teRenderer.ts |   45.45 |      100 |       0 |   45.45 | 13-51             
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.35 |    83.07 |     100 |   97.35 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.45 |       70 |     100 |   92.45 | ...22,144,151,160 
  tipRegistry.ts   |     100 |    95.23 |     100 |     100 | 33                
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/test-utils    |   93.75 |    83.33 |      80 |   93.75 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   65.28 |    73.08 |   60.34 |   65.28 |                   
  App.tsx          |     100 |      100 |     100 |     100 |                   
  AppContainer.tsx |   63.38 |    64.68 |      50 |   63.38 | ...3156,3160-3164 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.05 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...inePresets.ts |   98.17 |    88.88 |     100 |   98.17 | ...12,239,387-389 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   55.06 |    51.13 |   35.48 |   55.06 |                   
  AuthDialog.tsx   |   64.26 |    44.44 |   16.66 |   64.26 | ...59,366-388,392 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |    39.5 |       32 |   38.46 |    39.5 | ...69,472,478,481 
  useAuth.ts       |   76.63 |    68.29 |     100 |   76.63 | ...48,493-499,560 
  ...rSetupFlow.ts |   44.61 |    33.33 |      50 |   44.61 | ...57-378,395-438 
 src/ui/commands   |   73.39 |    81.12 |   81.61 |   73.39 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.04 |    81.25 |     100 |   89.04 | 91-92,94-99       
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...91-596,681-689 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   95.59 |    71.42 |     100 |   95.59 | 72,154-159        
  bugCommand.ts    |   81.13 |    71.42 |     100 |   81.13 | 60-69             
  clearCommand.ts  |      92 |    76.47 |     100 |      92 | 43-44,72-73,91-92 
  ...essCommand.ts |    64.7 |       50 |      75 |    64.7 | ...48-149,163-166 
  ...extCommand.ts |   34.78 |    22.22 |   45.45 |   34.78 | ...86-521,532-533 
  copyCommand.ts   |   98.28 |    94.89 |     100 |   98.28 | ...80,280,321,327 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |     87.5 |     100 |     100 | ...61,224-225,238 
  ...ryCommand.tsx |   68.09 |    77.77 |   77.77 |   68.09 | ...56-261,315-323 
  docsCommand.ts   |     100 |    88.88 |     100 |     100 | 25                
  doctorCommand.ts |   95.06 |    88.28 |     100 |   95.06 | ...92-293,320-321 
  dreamCommand.ts  |      75 |    66.66 |   66.66 |      75 | 22-27,44-47       
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   48.66 |     90.9 |   63.63 |   48.66 | ...05-109,159-211 
  forgetCommand.ts |   26.82 |      100 |      50 |   26.82 | 18-51             
  goalCommand.ts   |   91.25 |    83.33 |      90 |   91.25 | ...83-186,198-201 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |    20.4 |       40 |      40 |    20.4 | ...48-180,204-205 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  initCommand.ts   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |   74.56 |    68.42 |     100 |   74.56 | ...31-245,250-273 
  ...ageCommand.ts |   92.17 |    82.69 |     100 |   92.17 | ...43,164,173-183 
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   75.09 |    78.18 |      75 |   75.09 | ...20-225,262-267 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...berCommand.ts |   32.43 |      100 |      50 |   32.43 | 23-57             
  renameCommand.ts |   85.71 |    86.04 |     100 |   85.71 | ...02-209,216-221 
  ...oreCommand.ts |    92.3 |    87.87 |     100 |    92.3 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |      80 |      100 |      50 |      80 | 19-21             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |   15.04 |      100 |      25 |   15.04 | ...90-106,109-136 
  statsCommand.ts  |   88.19 |    84.21 |     100 |   88.19 | ...,58-61,143-146 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.46 |      100 |      50 |    6.46 | 31-329            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
 src/ui/components |   62.86 |    74.64 |   65.25 |   62.86 |                   
  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    |   89.39 |       75 |     100 |   89.39 | 35,37-42,44       
  ...odeDialog.tsx |     9.7 |      100 |       0 |     9.7 | 35-47,50-182      
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   13.04 |      100 |       0 |   13.04 | 18-61             
  ...TextInput.tsx |   77.01 |       76 |     100 |   77.01 | ...20,234-236,263 
  Composer.tsx     |    81.6 |     64.7 |     100 |    81.6 | ...90,108,160,173 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.99 |      100 |       0 |   11.99 | 66-517            
  DiffDialog.tsx   |    2.47 |      100 |       0 |    2.47 | 68-732            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   76.59 |    48.64 |     100 |   76.59 | ...35-136,175-180 
  ...ngSpinner.tsx |   68.42 |       80 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   76.19 |    81.81 |     100 |   76.19 | 24-30,46-50       
  Header.tsx       |   98.62 |    94.28 |     100 |   98.62 | 162,164           
  Help.tsx         |   98.32 |    89.88 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |    61.7 |       36 |     100 |    61.7 | ...42,345,348-354 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   83.01 |    79.78 |   83.33 |   83.01 | ...1399,1531,1581 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |     100 |    91.42 |     100 |     100 | 65,74             
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   81.75 |       75 |     100 |   81.75 | ...70-274,282-286 
  ...elsDialog.tsx |   71.05 |    69.11 |   72.72 |   71.05 | ...77,590,601-603 
  MemoryDialog.tsx |    55.1 |    54.54 |   57.14 |    55.1 | ...56,368,381-383 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   80.12 |    63.55 |     100 |   80.12 | ...39-555,612-616 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   41.26 |    61.53 |   71.42 |   41.26 | ...74-472,476-520 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   92.42 |    84.37 |     100 |   92.42 | ...,70-71,143-145 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...ngsDialog.tsx |   66.27 |    71.16 |      75 |   66.27 | ...12-820,826-827 
  ...ionDialog.tsx |    87.8 |      100 |   33.33 |    87.8 | 36-39,44-51       
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |      28 |      100 |       0 |      28 | 18-40             
  ...ionPicker.tsx |   17.59 |      100 |       0 |   17.59 | 55-172            
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ineDialog.tsx |   93.69 |    83.92 |     100 |   93.69 | ...11,273,293-295 
  ...yTodoList.tsx |   94.17 |       80 |     100 |   94.17 | 56-57,131-134     
  ...nsDisplay.tsx |   87.25 |       64 |     100 |   87.25 | ...45-147,154-156 
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
 ...nts/agent-view |   38.33 |    70.83 |   36.36 |   38.33 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |    9.95 |      100 |       0 |    9.95 | 57-308            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.8 |    27.27 |     100 |    87.8 | ...,85,98-106,124 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.72 |    70.53 |   60.86 |   45.72 |                   
  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 |   10.15 |      100 |       0 |   10.15 | 27-161            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   75.63 |    84.44 |   85.29 |   75.63 |                   
  ...sksDialog.tsx |   70.92 |    80.39 |   76.19 |   70.92 | ...1118,1194-1196 
  ...TasksPill.tsx |   63.75 |    86.95 |     100 |   63.75 | 44,86-106,114-122 
  ...gentPanel.tsx |   99.53 |    93.18 |     100 |   99.53 | 123               
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.88 |    94.23 |   66.66 |   54.88 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 17-128            
  ...nListStep.tsx |   88.43 |    94.73 |      80 |   88.43 | 52-53,59-72,106   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   68.67 |    69.07 |   69.56 |   68.67 |                   
  ...etailStep.tsx |   74.68 |    66.66 |   66.66 |   74.68 | ...71-184,188-201 
  ...etailStep.tsx |    87.4 |    73.68 |     100 |    87.4 | 41-42,99-113,119  
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   34.51 |    47.05 |   42.85 |   34.51 | ...78,482-495,499 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   20.98 |    86.36 |   83.33 |   20.98 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |    3.64 |      100 |       0 |    3.64 | 41-717            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-30              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   95.83 |    88.88 |     100 |   95.83 | 16,20,109-110     
 ...ents/mcp/steps |   26.74 |    54.54 |   42.85 |   26.74 |                   
  ...icateStep.tsx |    5.88 |      100 |       0 |    5.88 | 40-55,58-296      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.26 |      100 |       0 |    5.26 | 31-247            
  ...rListStep.tsx |   75.18 |    59.37 |     100 |   75.18 | ...53-158,169-173 
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |   69.02 |       50 |     100 |   69.02 | ...22,125,134-143 
 ...nents/messages |   82.44 |    79.55 |    72.6 |   82.44 |                   
  ...ionDialog.tsx |   80.84 |     77.6 |    62.5 |   80.84 | ...98,516,534-536 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.72 |     100 |   97.67 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   79.06 |      100 |      70 |   79.06 | ...51-264,268-280 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   55.67 |       40 |   28.57 |   55.67 | ...20-125,133-145 
  ...ryMessage.tsx |   14.28 |      100 |       0 |   14.28 | 23-62             
  ...onMessage.tsx |   81.02 |    69.23 |   33.33 |   81.02 | ...24-426,433-435 
  ...upMessage.tsx |      84 |    93.61 |     100 |      84 | ...56-383,405-420 
  ToolMessage.tsx  |   88.84 |    75.71 |    92.3 |   88.84 | ...44-749,776-778 
 ...ponents/shared |   85.36 |    78.48 |   95.77 |   85.36 |                   
  ...ctionList.tsx |   99.03 |    95.65 |     100 |   99.03 | 85                
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   83.01 |    86.25 |   88.88 |   83.01 | ...12-513,618-619 
  MultiSelect.tsx  |   84.31 |    74.19 |     100 |   84.31 | ...37,193-195,205 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  TextInput.tsx    |   77.01 |    48.78 |      80 |   77.01 | ...08-212,224-230 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  text-buffer.ts   |   83.68 |    78.55 |   97.61 |   83.68 | ...2270-2272,2368 
  ...er-actions.ts |   86.71 |    67.79 |     100 |   86.71 | ...07-608,809-811 
 ...ents/subagents |   30.87 |        0 |       0 |   30.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   10.95 |      100 |       0 |   10.95 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |   21.51 |    59.52 |   27.27 |   21.51 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   42.16 |    69.23 |   21.42 |   42.16 |                   
  ContextUsage.tsx |     4.7 |      100 |       0 |     4.7 | ...52-167,170-456 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   77.34 |    78.06 |   80.35 |   77.34 |                   
  ...ewContext.tsx |    64.7 |    85.71 |      50 |    64.7 | ...22-225,231-241 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   95.18 |    67.56 |      50 |   95.18 | ...94-195,222-226 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   82.31 |    82.84 |     100 |   82.31 | ...1153,1159-1161 
  ...owContext.tsx |   89.28 |       80 |   66.66 |   89.28 | 34,47-48,60-62    
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   43.28 |     62.5 |    62.5 |   43.28 | ...56-259,263-266 
  ...gsContext.tsx |   83.33 |       50 |     100 |   83.33 | 17-18             
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...nsContext.tsx |   88.23 |       50 |     100 |   88.23 | 120-121           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 195-196           
  ...deContext.tsx |   76.08 |    72.72 |     100 |   76.08 | 47-48,52-59,77-78 
 src/ui/daemon     |   90.76 |    73.73 |   95.45 |   90.76 |                   
  ...TuiAdapter.ts |   90.76 |    73.73 |   95.45 |   90.76 | ...53,771-772,858 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |   82.14 |    82.17 |   86.69 |   82.14 |                   
  ...dProcessor.ts |   83.12 |    82.56 |     100 |   83.12 | ...88-389,408-435 
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...dProcessor.ts |    94.8 |    70.58 |     100 |    94.8 | ...76-277,282-283 
  ...dProcessor.ts |   75.59 |    62.58 |   61.53 |   75.59 | ...88,912,931-935 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...ationFrame.ts |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   19.81 |    66.66 |      25 |   19.81 | 57-175            
  ...Completion.ts |   92.77 |    89.09 |     100 |   92.77 | ...86-187,220-223 
  ...ifications.ts |   92.07 |    96.29 |     100 |   92.07 | 116-124           
  ...tIndicator.ts |   83.49 |    70.96 |     100 |   83.49 | ...60,168,170-178 
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   94.21 |    76.08 |     100 |   94.21 | 122-126,213,219   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   94.36 |    74.35 |     100 |   94.36 | ...60,168-169,209 
  ...ompletion.tsx |   95.95 |    82.75 |     100 |   95.95 | ...22-223,225-226 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   76.92 |       50 |     100 |   76.92 | 55,68,71-75,88-96 
  ...eteCommand.ts |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...ialogClose.ts |   13.33 |      100 |     100 |   13.33 | 91-182            
  useDiffData.ts   |   11.62 |      100 |       0 |   11.62 | 44-87             
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |     97.7 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |   54.47 |       50 |   33.33 |   54.47 | ...69-171,193-194 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   89.15 |     62.5 |      50 |   89.15 | ...22-124,149-150 
  ...miniStream.ts |    77.7 |    74.93 |   91.66 |    77.7 | ...2497,2510-2518 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   93.15 |    93.75 |     100 |   93.15 | 44,107-110        
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   63.15 |       75 |      50 |   63.15 | 42-52,64-67       
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...derUpdates.ts |   86.38 |    77.19 |     100 |   86.38 | ...22,281-293,341 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |    84.7 |    93.33 |     100 |    84.7 | ...71-276,372-382 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   97.08 |    83.33 |     100 |   97.08 | 103-104,133       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   96.98 |    95.69 |     100 |   96.98 | ...83-184,238-241 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...Completion.ts |   82.67 |    85.41 |   94.73 |   82.67 | ...68-670,678-714 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   96.09 |    90.37 |     100 |   96.09 | ...62-365,450-457 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...tification.ts |     100 |    85.71 |     100 |     100 | 47                
  ...alProgress.ts |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       75 |     100 |   93.75 | 44-45,87          
  vim.ts           |   83.77 |    80.31 |     100 |   83.77 | ...55,759-767,776 
 src/ui/layouts    |   89.72 |     87.5 |     100 |   89.72 |                   
  ...AppLayout.tsx |   89.88 |     87.5 |     100 |   89.88 | 51-53,93-98       
  ...AppLayout.tsx |   89.47 |     87.5 |     100 |   89.47 | 58-63             
 ...i/manageModels |   93.61 |       48 |     100 |   93.61 |                   
  manageModels.ts  |   93.61 |       48 |     100 |   93.61 | ...63-166,179,209 
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |   14.28 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |   14.28 |     100 |                   
 src/ui/state      |   94.91 |    81.81 |     100 |   94.91 |                   
  extensions.ts    |   94.91 |    81.81 |     100 |   94.91 | 68-69,88          
 src/ui/themes     |   98.53 |    70.58 |     100 |   98.53 |                   
  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   |     100 |      100 |     100 |     100 |                   
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   87.98 |    82.89 |     100 |   87.98 | ...48-357,362-363 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   83.98 |    82.97 |   92.61 |   83.98 |                   
  ...Colorizer.tsx |   79.53 |    83.78 |     100 |   79.53 | ...51-152,249-275 
  ...nRenderer.tsx |   68.83 |    70.14 |      50 |   68.83 | ...52-254,274-293 
  ...wnDisplay.tsx |   86.01 |    87.41 |     100 |   86.01 | ...87,704,729-754 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.08 |    80.45 |      95 |   92.08 | ...76-679,723-728 
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   59.61 |    58.82 |     100 |   59.61 | ...,86-88,107-149 
  commandUtils.ts  |    95.9 |    88.42 |     100 |    95.9 | ...62,164-165,289 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   88.37 |    72.22 |     100 |   88.37 | 23,25,29,31,33    
  formatters.ts    |   95.23 |    98.27 |     100 |   95.23 | 117-120           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    94.28 |     100 |     100 | 35,57             
  historyUtils.ts  |   94.11 |       94 |     100 |   94.11 | 94-97             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |    89.47 |     100 |     100 | 81,110            
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |   98.66 |    96.77 |     100 |   98.66 | 48-49             
  ...geRenderer.ts |   86.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  osc8.ts          |   94.71 |    87.41 |     100 |   94.71 | ...43,428,432-433 
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |   98.98 |    97.05 |     100 |   98.98 | 98                
  ...storyUtils.ts |   61.89 |    69.87 |      90 |   61.89 | ...76,424,429-451 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.61 |    94.84 |   92.85 |   97.61 | ...50-251,386-387 
  todoSnapshot.ts  |   89.11 |    93.33 |     100 |   89.11 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |   56.77 |     40.8 |   79.41 |   56.77 |                   
  collect.ts       |   55.92 |    50.58 |   86.36 |   55.92 | ...25-640,642-647 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   57.47 |    20.51 |      80 |   57.47 | ...09-310,324-359 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   76.51 |    89.55 |      94 |   76.51 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.72 |    97.14 |     100 |   96.72 | 165-168           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   87.17 |     90.9 |     100 |   87.17 | 64-73             
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   71.06 |       75 |     100 |   71.06 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   94.28 |       88 |     100 |   94.28 | 28-29,125-126     
  errors.ts        |   98.67 |    96.36 |     100 |   98.67 | 67-68             
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |   90.76 |    93.33 |   88.88 |   90.76 | 103-114           
  ...lationInfo.ts |     100 |      100 |     100 |     100 |                   
  languageUtils.ts |   97.89 |    96.42 |     100 |   97.89 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.79 |    93.28 |     100 |   96.79 | ...76-477,575,588 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   98.07 |    76.92 |     100 |   98.07 | 70                
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-1047            
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.89 |    90.67 |   89.47 |   82.89 | ...52-663,670-678 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |   98.46 |    94.52 |     100 |   98.46 | 130-131,305       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   95.12 |    89.06 |     100 |   95.12 | ...43-244,249-253 
  ...InfoFields.ts |   87.61 |       65 |     100 |   87.61 | ...22-123,144-145 
  ...iffPreview.ts |   94.11 |    83.33 |     100 |   94.11 | 13                
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |   63.15 |    81.25 |     100 |   63.15 | 93,118-157        
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |    79.6 |    82.84 |   82.26 |    79.6 |                   
 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        |   87.58 |    78.93 |   91.76 |   87.58 |                   
  ...transcript.ts |   92.25 |    85.71 |     100 |   92.25 | ...87,306-307,438 
  ...ent-resume.ts |   82.53 |    71.28 |   77.41 |   82.53 | ...1045-1049,1052 
  ...ound-tasks.ts |    95.4 |    86.48 |     100 |    95.4 | ...55-756,827-828 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |   76.54 |    66.87 |   78.72 |   76.54 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.37 |    63.37 |   78.26 |   75.37 | ...1860,1866-1867 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   76.29 |    86.15 |   73.04 |   76.29 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.25 |    90.62 |   86.66 |   91.25 | ...94,249-269,328 
  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 |   81.15 |     76.7 |   71.42 |   81.15 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   76.51 |    72.35 |   60.86 |   76.51 | ...1609,1636-1683 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   81.19 |    71.73 |   60.86 |   81.19 | ...98-399,402-403 
  ...nteractive.ts |   79.71 |    79.62 |      75 |   79.71 | ...54,456,458,461 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   78.38 |    81.98 |   65.78 |   78.38 |                   
  config.ts        |   76.21 |    80.77 |   61.16 |   76.21 | ...3730,3741-3753 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   95.01 |     90.9 |   90.47 |   95.01 | ...71-372,375-376 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   86.07 |    82.57 |   90.04 |   86.07 |                   
  baseLlmClient.ts |   87.24 |    76.47 |    87.5 |   87.24 | ...82,484-494,503 
  client.ts        |   87.57 |     81.3 |   86.11 |   87.57 | ...1928,1967-1970 
  ...tGenerator.ts |    72.1 |    61.11 |     100 |    72.1 | ...63,365,372-375 
  ...lScheduler.ts |   80.28 |     80.7 |   93.47 |   80.28 | ...2568,2620-2624 
  geminiChat.ts    |   89.32 |     84.8 |   91.48 |   89.32 | ...1454,1521-1522 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | 34-42,45-49,52-87 
  logger.ts        |   87.33 |    87.02 |     100 |   87.33 | ...61-565,611-625 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   86.48 |    72.22 |     100 |   86.48 | ...97-198,212-221 
  ...issionFlow.ts |   98.59 |    94.73 |     100 |   98.59 | 93                
  prompts.ts       |   89.16 |    86.41 |   76.92 |   89.16 | ...-965,1168-1169 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...okTriggers.ts |   99.31 |    90.41 |     100 |   99.31 | 124,135           
  turn.ts          |   96.44 |    88.88 |     100 |   96.44 | ...08,421-422,470 
 ...ntentGenerator |   94.92 |    82.59 |   93.87 |   94.92 |                   
  ...tGenerator.ts |   96.48 |    84.28 |   92.59 |   96.48 | ...01,919-923,963 
  converter.ts     |   94.51 |    80.72 |     100 |   94.51 | ...06-607,617,823 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.53 |    71.64 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.96 |   92.85 |      90 | ...80-286,304-305 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   93.34 |    80.28 |   90.32 |   93.34 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   93.32 |    80.28 |   90.32 |   93.32 | ...01,911-912,940 
 ...ntentGenerator |   81.66 |    84.08 |    90.9 |   81.66 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   76.88 |    82.25 |    87.5 |   76.88 | ...1589,1610-1616 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   52.38 |    44.44 |      50 |   52.38 | ...77,81-85,89-93 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   93.67 |     84.9 |     100 |   93.67 | ...80-481,489,554 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   90.66 |    88.57 |     100 |   90.66 | ...15-319,349-350 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.83 |    89.55 |   95.65 |   96.83 |                   
  dashscope.ts     |   97.29 |    89.77 |   93.33 |   97.29 | ...81-282,358-359 
  deepseek.ts      |   95.55 |    90.56 |     100 |   95.55 | ...31-132,145-146 
  default.ts       |   95.79 |    89.65 |   88.88 |   95.79 | 122-123,193-195   
  index.ts         |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/extension     |   61.02 |     79.5 |    79.2 |   61.02 |                   
  ...-converter.ts |    65.2 |    49.58 |     100 |    65.2 | ...90-791,800-832 
  ...ionManager.ts |   47.04 |    82.06 |    65.9 |   47.04 | ...1398,1408-1427 
  ...onSettings.ts |   93.46 |    93.05 |     100 |   93.46 | ...17-221,228-232 
  ...-converter.ts |   54.88 |    94.44 |      60 |   54.88 | ...35-146,158-192 
  github.ts        |   44.94 |    88.52 |      60 |   44.94 | ...53-359,398-451 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.29 |    93.75 |     100 |   97.29 | ...64,184-185,274 
  npm.ts           |   48.66 |    76.08 |      75 |   48.66 | ...18-420,427-431 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-108,143-149    
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   55.57 |    84.14 |   81.25 |   55.57 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   95.06 |       84 |     100 |   95.06 | 78,108,122,133    
  speculation.ts   |   13.02 |      100 |   16.66 |   13.02 | 89-464,524-575    
  ...onToolGate.ts |     100 |    96.42 |     100 |     100 | 94                
  ...nGenerator.ts |    71.6 |    72.13 |   83.33 |    71.6 | ...88-246,316-318 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   89.57 |    83.45 |   94.44 |   89.57 |                   
  ...eGoalStore.ts |    85.1 |    95.45 |   84.61 |    85.1 | ...63-166,174-182 
  goalHook.ts      |   97.26 |    91.48 |     100 |   97.26 | 100-105           
  goalJudge.ts     |   84.33 |    74.28 |     100 |   84.33 | ...57-358,366-368 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   83.48 |    84.87 |   86.83 |   83.48 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |    96.4 |    90.78 |     100 |    96.4 | ...91,293-294,367 
  ...entHandler.ts |   94.56 |    83.78 |   93.33 |   94.56 | ...38,795-796,806 
  hookPlanner.ts   |   84.13 |    76.59 |      90 |   84.13 | ...38,144,162-173 
  hookRegistry.ts  |   90.17 |    83.33 |     100 |   90.17 | ...33,352,356,360 
  hookRunner.ts    |   58.56 |    71.26 |   66.66 |   58.56 | ...48-749,758-759 
  hookSystem.ts    |   84.57 |      100 |   65.85 |   84.57 | ...21-622,628-629 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   93.63 |    89.47 |      90 |   93.63 | ...45-353,427-428 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   96.66 |    91.66 |     100 |   96.66 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |       0 |        0 |       0 |       0 | 1-124             
  types.ts         |   91.21 |    92.04 |   85.71 |   91.21 | ...40-441,501-505 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   74.28 |    83.39 |   78.33 |   74.28 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |    64.2 |    81.48 |   66.66 |    64.2 | ...9-970,999-1007 
  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           |   41.24 |    52.14 |   51.42 |   41.24 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |   42.69 |    79.16 |      50 |   42.69 | ...62-413,419-436 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   25.31 |    62.06 |   41.66 |   25.31 | ...85-704,710-740 
  ...eLspClient.ts |   32.77 |       80 |   17.64 |   32.77 | ...84-288,294-295 
  ...LspService.ts |   48.49 |    67.16 |   65.71 |   48.49 | ...1352,1369-1379 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   78.69 |    75.34 |   75.92 |   78.69 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.62 |    97.72 |     100 |   98.62 | 87-88             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |    95.83 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.52 |    86.66 |   86.36 |   79.52 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   82.87 |    82.35 |   92.85 |   82.87 | ...63-173,181-182 
  ...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        |      68 |    76.27 |   66.66 |      68 |                   
  const.ts         |     100 |      100 |     100 |     100 |                   
  dream.ts         |   65.65 |    73.33 |      50 |   65.65 | 50,107-148        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   63.77 |    79.16 |      50 |   63.77 | ...72-180,183-189 
  extract.ts       |    95.2 |    79.16 |     100 |    95.2 | 81-86,125         
  ...entPlanner.ts |   63.08 |    65.71 |   41.17 |   63.08 | ...17,222-223,332 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |    45.8 |    61.53 |   44.44 |    45.8 | ...04,211,214-346 
  indexer.ts       |   83.87 |    45.45 |     100 |   83.87 | ...50,56-57,69-70 
  manager.ts       |   75.31 |    81.04 |    75.6 |   75.31 | ...1278,1291-1293 
  memoryAge.ts     |   90.47 |    77.77 |     100 |   90.47 | 50-51             
  paths.ts         |   55.47 |    89.47 |   85.71 |   55.47 | ...,89-90,106-114 
  prompt.ts        |   93.36 |    71.42 |     100 |   93.36 | ...58,161,228-229 
  recall.ts        |   77.54 |    69.38 |   88.88 |   77.54 | ...53-258,282-293 
  ...ceSelector.ts |   91.86 |    77.27 |     100 |   91.86 | ...15,117-118,126 
  scan.ts          |   87.91 |    68.42 |     100 |   87.91 | ...47-48,58,82-87 
  ...entPlanner.ts |    11.5 |      100 |       0 |    11.5 | ...57-192,210-298 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   94.44 |    83.33 |     100 |   94.44 | 56-57,92-93       
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   79.38 |    78.33 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.35 |    86.14 |    87.5 |   89.35 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.24 |    91.42 |     100 |   90.24 | 142,148,151-160   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.66 |    92.85 |     100 |   98.66 | 162,324,330       
  modelRegistry.ts |     100 |    98.59 |     100 |     100 | 222               
  modelsConfig.ts  |   84.57 |    82.14 |   81.57 |   84.57 | ...1223,1252-1253 
  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   |   74.36 |    88.55 |   57.55 |   74.36 |                   
  autoMode.ts      |   61.59 |    93.54 |   83.33 |   61.59 | ...00-238,340-356 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |   92.89 |     87.5 |     100 |   92.89 | 146-153,333-337   
  ...erousRules.ts |     100 |    83.87 |     100 |     100 | 101,113,137-143   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |    78.3 |    85.24 |   82.14 |    78.3 | ...-917,1023-1027 
  rule-parser.ts   |   96.06 |    93.22 |     100 |   96.06 | ...-875,1024-1026 
  ...-semantics.ts |   58.28 |    85.27 |    30.2 |   58.28 | ...1604-1614,1643 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   98.18 |       90 |     100 |   98.18 |                   
  system-prompt.ts |   98.18 |       90 |     100 |   98.18 | 150               
 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/qwen          |   83.87 |    77.46 |   95.83 |   83.87 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   80.85 |    70.74 |   90.32 |   80.85 | ...1169-1185,1215 
  ...kenManager.ts |   83.76 |    76.22 |     100 |   83.76 | ...62-767,788-793 
 src/services      |   85.32 |    83.28 |   91.28 |   85.32 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   98.44 |    91.83 |     100 |   98.44 | 268-269           
  ...ionService.ts |    95.6 |    96.36 |     100 |    95.6 | ...32,400,402-406 
  ...ingService.ts |   83.88 |    83.33 |   83.33 |   83.88 | ...1266,1283-1284 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |     100 |    96.77 |     100 |     100 | 133,182           
  cronScheduler.ts |   97.56 |    92.98 |     100 |   97.56 | 62-63,77,155      
  ...eryService.ts |   80.43 |    95.45 |      75 |   80.43 | ...19-134,140-141 
  ...oryService.ts |   86.18 |    76.76 |   91.17 |   86.18 | ...1150,1191-1194 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   91.27 |    82.69 |    90.9 |   91.27 | ...94,196,294-301 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  gitService.ts    |   68.75 |     92.3 |   55.55 |   68.75 | ...12-122,125-129 
  ...reeService.ts |   73.83 |    69.31 |    97.5 |   73.83 | ...1460,1488-1489 
  ...ionService.ts |   98.13 |     97.8 |   95.45 |   98.13 | ...32-333,380-381 
  ...orRegistry.ts |   96.54 |    91.73 |     100 |   96.54 | ...70-471,622-623 
  sessionRecap.ts  |   12.65 |      100 |       0 |   12.65 | 44-150            
  ...ionService.ts |   90.23 |     78.8 |   96.77 |   90.23 | ...1294,1298-1299 
  sessionTitle.ts  |   93.87 |    71.15 |     100 |   93.87 | ...33-236,267-268 
  ...ionService.ts |   81.07 |    77.92 |   89.28 |   81.07 | ...1923,1929-1934 
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...reeCleanup.ts |   14.56 |      100 |   33.33 |   14.56 | 58-185            
  ...ionService.ts |   84.21 |    79.41 |     100 |   84.21 | ...22-223,239-240 
 ...icrocompaction |   98.05 |     91.8 |     100 |   98.05 |                   
  microcompact.ts  |   98.05 |     91.8 |     100 |   98.05 | ...19,289,293,391 
 src/skills        |    87.5 |    83.86 |   94.23 |    87.5 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |   92.94 |    81.63 |     100 |   92.94 | ...06,226,238-240 
  skill-manager.ts |   83.31 |    79.66 |   90.32 |   83.31 | ...1120,1127-1131 
  skill-paths.ts   |   86.74 |    77.77 |     100 |   86.74 | ...00-101,106-107 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/subagents     |   82.61 |    78.89 |   95.23 |   82.61 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   77.15 |    71.36 |    93.1 |   77.15 | ...1178,1200-1201 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 51-56,69-74,78-83 
 src/telemetry     |   74.72 |    87.26 |   78.85 |   74.72 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |   98.13 |       88 |     100 |   98.13 | 185-187           
  ...-exporters.ts |   46.37 |      100 |   44.44 |   46.37 | ...85,88-89,92-93 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   93.93 |    90.21 |   94.11 |   93.93 | ...75-280,299-300 
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |    51.9 |       64 |   57.77 |    51.9 | ...1214,1231-1251 
  metrics.ts       |    74.9 |    82.95 |   74.54 |    74.9 | ...58-978,981-992 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   90.45 |    83.56 |   76.92 |   90.45 | ...17-318,338-342 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   92.24 |    88.77 |     100 |   92.24 | ...21-424,522-525 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.61 |    89.36 |     100 |   98.61 | 53,108            
  types.ts         |   79.17 |    94.49 |   83.33 |   79.17 | ...1149,1152-1181 
  uiTelemetry.ts   |   92.97 |    96.96 |   81.25 |   92.97 | ...93-194,200-207 
 ...ry/qwen-logger |   68.24 |    79.56 |   64.91 |   68.24 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.24 |    79.34 |   64.28 |   68.24 | ...1055,1093-1094 
 src/test-utils    |   93.16 |    95.91 |   76.47 |   93.16 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   91.19 |    97.14 |   72.41 |   91.19 | ...38,202-203,216 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   78.74 |     81.4 |   85.71 |   78.74 |                   
  ...erQuestion.ts |   88.93 |    76.74 |    90.9 |   88.93 | ...39-340,347-348 
  cron-create.ts   |   88.11 |    88.88 |    62.5 |   88.11 | ...,43-44,165-172 
  cron-delete.ts   |   96.82 |      100 |   83.33 |   96.82 | 26-27             
  cron-list.ts     |   96.66 |      100 |   83.33 |   96.66 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   81.02 |    84.07 |      75 |   81.02 | ...15-716,826-876 
  ...r-worktree.ts |   82.95 |    67.56 |    87.5 |   82.95 | ...82-185,276-277 
  exit-worktree.ts |   84.23 |    85.96 |   91.66 |   84.23 | ...92-293,298-312 
  exitPlanMode.ts  |   85.09 |    85.71 |     100 |   85.09 | ...60-163,177-189 
  glob.ts          |   90.63 |    88.33 |   84.61 |   90.63 | ...28,171,302,305 
  grep.ts          |   79.19 |    85.71 |   78.94 |   79.19 | ...20,560,569-576 
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.77 |    60.09 |   90.32 |   72.77 | ...1211,1213-1214 
  ...nt-manager.ts |   84.36 |    82.74 |   84.21 |   84.36 | ...2099-2103,2142 
  mcp-client.ts    |   33.18 |    77.65 |   66.66 |   33.18 | ...1490,1494-1497 
  mcp-tool.ts      |   90.98 |    88.88 |   96.42 |   90.98 | ...95-596,646-647 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-47              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   91.36 |    83.94 |   88.46 |   91.36 | ...61,574,770-775 
  notebook-edit.ts |   81.72 |       75 |   81.25 |   81.72 | ...54-870,916-917 
  ...nforcement.ts |   82.57 |       90 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |    95.4 |    90.32 |      90 |    95.4 | ...99,298-301,304 
  ripGrep.ts       |   94.59 |    85.71 |   93.33 |   94.59 | ...60,463,541-542 
  ...-transport.ts |    6.34 |      100 |       0 |    6.34 | 47-145            
  send-message.ts  |   84.68 |    91.66 |    62.5 |   84.68 | ...,82-90,167-170 
  shell.ts         |   73.05 |    79.66 |   91.42 |   73.05 | ...4216,4265-4271 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   88.35 |    91.42 |   86.66 |   88.35 | ...12,416,439-461 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  todoWrite.ts     |   89.17 |    82.05 |   92.85 |   89.17 | ...41-546,568-569 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   74.85 |    76.85 |   80.95 |   74.85 | ...30-831,839-840 
  tool-search.ts   |   95.19 |    86.48 |    92.3 |   95.19 | ...47-153,208-213 
  tools.ts         |   90.49 |    90.19 |   84.21 |   90.49 | ...78-479,495-501 
  web-fetch.ts     |   88.84 |       80 |   92.85 |   88.84 | ...12-313,315-316 
  write-file.ts    |   82.65 |    80.45 |   84.61 |   82.65 | ...65-668,696-731 
 src/tools/agent   |   74.64 |    81.34 |   73.61 |   74.64 |                   
  agent.ts         |    74.9 |     81.6 |   74.24 |    74.9 | ...2390,2399-2402 
  fork-subagent.ts |   69.62 |    71.42 |   66.66 |   69.62 | ...04-105,140-151 
 src/utils         |   89.09 |    87.76 |   93.65 |   89.09 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   77.96 |    80.48 |     100 |   77.96 | ...35,156,173-176 
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |    7.69 |      100 |       0 |    7.69 | 17-56             
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   89.11 |     87.5 |     100 |   89.11 | ...28-129,132-133 
  cronDisplay.ts   |   42.85 |    23.07 |     100 |   42.85 | 26-31,33-45,47-54 
  cronParser.ts    |   89.74 |    85.71 |     100 |   89.74 | ...,63-64,183-186 
  debugLogger.ts   |    95.9 |    93.84 |   94.73 |    95.9 | 106-107,214-218   
  editHelper.ts    |   93.63 |    83.52 |     100 |   93.63 | ...28-429,463-464 
  editor.ts        |   97.61 |    95.71 |     100 |   97.61 | ...70-271,273-274 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |     100 |    95.45 |     100 |     100 | 83                
  errorParsing.ts  |    97.7 |    97.05 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.92 |       80 |   53.33 |   70.92 | ...03-219,223-229 
  fetch.ts         |   70.18 |    71.42 |   71.42 |   70.18 | ...42,148,161,186 
  fileUtils.ts     |    91.5 |    86.25 |   95.23 |    91.5 | ...1191,1195-1201 
  forkedAgent.ts   |   80.68 |    78.12 |   83.33 |   80.68 | ...39-545,550-556 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  gitDiff.ts       |   92.36 |    79.53 |     100 |   92.36 | ...55-856,928-929 
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   56.66 |    85.71 |      75 |   56.66 | ...2,72-73,97-148 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 26                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |    74.1 |    90.76 |   58.33 |    74.1 | ...23-326,336-342 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |   96.87 |    91.83 |     100 |   96.87 | 214-219,272       
  ...yDiscovery.ts |    83.9 |    79.36 |     100 |    83.9 | ...16,319,411-414 
  ...tProcessor.ts |   93.63 |       90 |     100 |   93.63 | ...96-302,384-385 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  modelId.ts       |   98.95 |    98.18 |     100 |   98.95 | 148               
  ...kerChecker.ts |   88.75 |    85.71 |     100 |   88.75 | 69-70,87-93       
  notebook.ts      |   94.48 |    88.59 |   95.83 |   94.48 | ...16,328,380-382 
  openaiLogger.ts  |   90.85 |    87.87 |     100 |   90.85 | ...97-199,222-227 
  partUtils.ts     |     100 |    98.61 |     100 |     100 | 206               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.21 |    91.86 |     100 |   93.21 | ...89-390,392-394 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  ...ectSummary.ts |   89.39 |    72.41 |     100 |   89.39 | ...37-142,193-196 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   92.55 |    85.92 |     100 |   92.55 | ...70-272,309-310 
  readManyFiles.ts |   87.59 |       84 |     100 |   87.59 | ...09-211,227-238 
  retry.ts         |   89.81 |    88.05 |     100 |   89.81 | ...29,350,357-358 
  ripgrepUtils.ts  |   46.79 |    84.37 |   66.66 |   46.79 | ...45-246,258-335 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...tchOptions.ts |   81.72 |    85.04 |   95.23 |   81.72 | ...11,536,565-574 
  runtimeStatus.ts |    97.5 |    88.57 |     100 |    97.5 | 167-168           
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    88.23 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   94.57 |    80.26 |     100 |   94.57 | ...04,213-216,270 
  ...r-launcher.ts |   76.92 |     91.3 |   66.66 |   76.92 | ...34,136,157-195 
  ...orageUtils.ts |   96.89 |    85.84 |     100 |   96.89 | ...51,367,447,466 
  shell-utils.ts   |   82.93 |    89.89 |     100 |   82.93 | ...1522,1529-1533 
  ...lAstParser.ts |   95.58 |    85.79 |     100 |   95.58 | ...1059-1061,1071 
  ...nlyChecker.ts |   95.75 |    92.39 |     100 |   95.75 | ...00-301,313-314 
  sideQuery.ts     |   98.71 |    97.14 |     100 |   98.71 | 110               
  ...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          
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  truncation.ts    |     100 |       92 |     100 |     100 | 52,71             
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   93.71 |    89.28 |   93.33 |   93.71 | ...24-225,249-251 
  xml.ts           |     100 |      100 |     100 |     100 |                   
  yaml-parser.ts   |      92 |    84.61 |     100 |      92 | 49-53,65-69       
 ...ils/filesearch |   86.21 |    81.61 |   96.42 |   86.21 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.84 |    77.49 |   94.82 |   82.84 | ...1451,1485-1486 
  fileSearch.ts    |   93.58 |    87.32 |     100 |   93.58 | ...46-247,249-250 
  ignore.ts        |     100 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |     92.3 |     100 |     100 | 46                
 ...uest-tokenizer |   56.63 |    74.52 |   74.19 |   56.63 |                   
  ...eTokenizer.ts |   41.86 |    76.47 |   69.23 |   41.86 | ...70-443,453-507 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |      76 |      100 |   33.33 |      76 | 45-48,55-56       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

wenshao
wenshao previously requested changes May 9, 2026
Comment thread packages/core/src/utils/notebook.ts
Comment thread packages/core/src/tools/notebook-edit.ts Outdated
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/tools/notebook-edit.ts
…-2816

# Conflicts:
#	packages/core/src/services/fileReadCache.ts
#	packages/core/src/tools/read-file.ts
#	packages/core/src/tools/tool-names.ts
@zhangxy-zju

Copy link
Copy Markdown
Collaborator Author

Addressed the review feedback in c8b9a9a32:

  • Avoided cell-N id collisions by generating inserted nbformat 4.5+ cell ids as qwen-cell-N and checking against all rendered display ids.
  • Changed cell lookup to use the exact ids rendered by read_file; ambiguous rendered ids are now rejected instead of guessed.
  • Fixed follow-up edit safety by invalidating the file read cache after structural edits when rendered fallback ids can shift; stable-id notebooks can keep the fresh structured write state.
  • Implemented ModifiableDeclarativeTool for NotebookEdit so IDE/inline modified full-notebook proposals are applied.
  • Added CommitAttributionService.recordEdit for successful AI-originated NotebookEdit writes.
  • Updated bare-mode config tests to include notebook_edit in the expected default toolset.

Local validation:

npx eslint packages/core/src/config/config.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts
npx vitest run packages/core/src/utils/notebook.test.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/services/fileReadCache.test.ts packages/core/src/tools/read-file.test.ts packages/core/src/core/coreToolScheduler.test.ts
npx vitest run packages/core/src/config/config.test.ts
npm run typecheck --workspace=packages/core
npm run build
npm run bundle
QWEN_SANDBOX=false npx vitest run --root ./integration-tests cli/notebook-edit.test.ts --poolOptions.threads.minThreads 1 --poolOptions.threads.maxThreads 1
git diff --check

I also reran the two unrelated full-core timeout cases individually and both passed.

@zhangxy-zju zhangxy-zju requested a review from wenshao May 11, 2026 14:22
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/tools/read-file.ts
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/tools/notebook-edit.ts Outdated
Comment thread packages/core/src/utils/notebook.ts
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/utils/notebook.ts

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

Suggestion (cross-cutting): priorReadEnforcement.ts:243 still returns EDIT_REQUIRES_PRIOR_READ for FIFO/socket/device files, while this PR correctly introduces TARGET_NOT_REGULAR_FILE in notebook-edit.ts:364. The shared checkPriorRead path used by EditTool/WriteFileTool would benefit from using the new error type as well, to avoid the read/edit retry loop that the new type was designed to prevent.

— DeepSeek/deepseek-v4-pro via Qwen Code /review

Comment thread packages/core/src/utils/notebook.ts
…-2816

# Conflicts:
#	packages/core/src/services/fileReadCache.ts
@zhangxy-zju

zhangxy-zju commented May 19, 2026

Copy link
Copy Markdown
Collaborator Author

自测:1. 修改cell 内容: image
2. 删除cell:
image

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

Cross-file impact (not in PR files):

  • packages/core/src/utils/readManyFiles.ts:204 — This PR makes processSingleFileContent return isTruncated: true for large notebooks without setting linesShown or originalLineCount. readManyFiles.ts destructures fileReadResult.linesShown! → TypeError. The guard at read-file.ts:278-282 was not applied in readManyFiles.ts. Scenario: @src/notebooks/ with a large-output notebook crashes the batch read.
  • packages/core/src/tools/priorReadEnforcement.ts:~253 — The "non-text payload" error message directs the model to "use shell tool with a binary-aware writer" for .ipynb files, instead of pointing to the new notebook_edit tool. Shell-based notebook editing bypasses all cell-level safety.

— qwen-latest-series-invite-beta-v28 via Qwen Code /review

Comment thread packages/core/src/tools/notebook-edit.ts Outdated
Comment thread packages/core/src/utils/notebook.ts
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/tools/notebook-edit.ts
Comment thread packages/core/src/tools/notebook-edit.ts Outdated
@zhangxy-zju

Copy link
Copy Markdown
Collaborator Author

Addressed the latest review feedback in d3de6e005:

  • Fixed readManyFiles handling for truncated notebook reads that do not expose text linesShown / originalLineCount; batch reads now keep the notebook structured content instead of treating it like text line truncation.
  • Updated Edit / WriteFile prior-read guidance for non-text notebook payloads to direct agents to notebook_edit for .ipynb cell-level edits, instead of suggesting shell-based mutation.
  • Fixed the inline modified_notebook_content path so invalid original notebook JSON is converted to NOTEBOOK_INVALID_JSON rather than falling through as a generic notebook edit failure.

Validation:

npm test --workspace=packages/core -- --run src/tools/notebook-edit.test.ts src/utils/readManyFiles.test.ts src/tools/edit.test.ts src/tools/write-file.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts
npm run build --workspace=packages/core

The inline suggestion thread was replied to and resolved.

@zhangxy-zju

Copy link
Copy Markdown
Collaborator Author

Pushed d0e8e9adc to address the remaining notebook review threads.

Summary:

  • Preserved compact notebook JSON formatting by making inferred indentation optional.
  • Rejected malformed notebook cells early in parseNotebook().
  • Removed internal modify fields from the public NotebookEdit params and added additionalProperties: false; user-modified notebook content now travels through internal metadata that survives the scheduler clone path.
  • Added best-effort trackEdit() before the final freshness check and notebook write.
  • Added a distinct truncated-read rejection so large rendered notebooks no longer ask the model to re-read without offset/limit.

Validation passed locally:

npm test --workspace=packages/core -- --run src/utils/notebook.test.ts src/tools/notebook-edit.test.ts src/utils/readManyFiles.test.ts src/tools/edit.test.ts src/tools/write-file.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.ts packages/core/src/tools/notebook-edit.test.ts packages/core/src/utils/notebook.ts packages/core/src/utils/notebook.test.ts packages/core/src/utils/readManyFiles.ts packages/core/src/utils/readManyFiles.test.ts packages/core/src/tools/priorReadEnforcement.ts packages/core/src/tools/edit.test.ts packages/core/src/tools/write-file.test.ts
git diff --check
npm run build --workspace=packages/core

I also replied to and resolved each currently unresolved inline review thread.

@zhangxy-zju

Copy link
Copy Markdown
Collaborator Author

Pushed 8b1d7ebdd with usage documentation for NotebookEdit.

Docs updated:

  • Added notebook_edit usage, parameters, behavior, and examples to the file-system tools docs.
  • Documented .ipynb read_file behavior and the fresh full-read requirement before notebook edits.
  • Clarified that generic edit / write_file should not be used for raw notebook JSON cell edits.
  • Updated permissions/settings docs so NotebookEdit aliases and the Edit meta-category include notebook_edit.
  • Updated approval-mode and SDK permission-mode docs so auto-edit explicitly includes notebook_edit.

Validation passed:

./node_modules/.bin/prettier --check docs/developers/tools/file-system.md docs/users/configuration/settings.md docs/users/features/approval-mode.md docs/developers/sdk-typescript.md packages/sdk-typescript/README.md docs/developers/sdk-java.md packages/sdk-java/qwencode/README.md packages/sdk-java/qwencode/QWEN.md
git diff --check

@zhangxy-zju

Copy link
Copy Markdown
Collaborator Author

Pushed af0303a28 to address the two latest follow-up findings.

Summary:

  • read_file now treats an empty pages argument as unset and rejects non-empty pages for .ipynb files. That prevents PDF-only pagination arguments from making a full notebook render look like a partial/truncated read in the cache.
  • parseNotebook() now strips a leading UTF-8 BOM before JSON.parse, so BOM-prefixed notebooks can be read successfully and used as the prior-read basis for notebook_edit.

Validation passed locally:

npm test --workspace=packages/core -- --run src/tools/read-file.test.ts src/utils/notebook.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts
git diff --check
npm run build --workspace=packages/core

I also checked the GitHub review threads after the push; there are currently no unresolved inline threads to reply to or resolve individually.

@zhangxy-zju

Copy link
Copy Markdown
Collaborator Author

Pushed 1eaf0112a with the requested NotebookEdit unit coverage.

The new test creates a UTF-8 BOM-prefixed .ipynb, seeds the prior-read cache, runs a real notebook_edit replace invocation, and asserts both the updated cell content and the preserved BOM bytes on disk.

Validation passed locally:

npm test --workspace=packages/core -- --run src/tools/notebook-edit.test.ts
npm test --workspace=packages/core -- --run src/tools/notebook-edit.test.ts src/tools/read-file.test.ts src/utils/notebook.test.ts
npm run typecheck --workspace=packages/core
./node_modules/.bin/eslint packages/core/src/tools/notebook-edit.test.ts packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts --max-warnings 0
./node_modules/.bin/prettier --check packages/core/src/tools/notebook-edit.test.ts packages/core/src/tools/read-file.ts packages/core/src/utils/notebook.ts packages/core/src/tools/read-file.test.ts packages/core/src/utils/notebook.test.ts
git diff --check
npm run build --workspace=packages/core

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the updates. I rechecked the latest revision, and all CI checks are green now.

The two issues I raised earlier have also been addressed: read_file now rejects unsupported pages for .ipynb files, and UTF-8 BOM notebooks are parsed and written back correctly with BOM preservation.

Given the local recheck and the passing CI, this looks good to merge from my side. LGTM.


export function inferNotebookJsonFormat(content: string): NotebookJsonFormat {
const lineMatch = content.match(/\n( +)"/);
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.

[Critical] inferNotebookJsonFormat regex /\n( +)"/ only detects space-based indentation. Tab-indented notebooks (valid JSON, produced by some editors including VS Code with tab settings) yield indent: undefined, causing serializeNotebook to call JSON.stringify(notebook, null, undefined) — producing minified single-line JSON. A single cell edit would destroy formatting across the entire file.

Suggested change
return {
export function inferNotebookJsonFormat(content: string): NotebookJsonFormat {
const trailingNewline = content.endsWith('\n');
const match = content.match(/\n([ \t]+)"/);
const indent = match?.[1] !== undefined
? (match[1].includes('\t') ? match[1] : match[1].length)
: undefined;
return { indent, trailingNewline };
}

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

}
}

override async execute(signal: AbortSignal): Promise<ToolResult> {

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 debug logging on the successful write path. debugLogger is only invoked for prior-read rejections (line 110) and post-write cache failures (line 635). A successful notebook edit — including which cell was targeted, mode used, requiresReadAfterWrite decision, and whether content was user-modified — produces zero debug output. At 3 AM debugging a "model deleted the wrong cell" report, there's no trace to reconstruct what happened.

Suggested change
override async execute(signal: AbortSignal): Promise<ToolResult> {
// After successful write, before return:
debugLogger.debug('execute-success', {
path: this.params.notebook_path,
mode: this.params.edit_mode,
cellId: this.params.cell_id,
requiresReadAfterWrite: result.requiresReadAfterWrite,
modifiedByUser: this.modifyMetadata !== undefined,
});

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

if (prepared.requiresReadAfterWrite) {
cache.invalidate(postWriteStats);
} else {
cache.recordWrite(this.params.notebook_path, postWriteStats, {

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 { cacheable: false } flag here is the sole guard preventing the regular Edit/WriteFile tools from corrupting .ipynb files. checkPriorRead in priorReadEnforcement.ts rejects files where lastReadCacheable === false. But this contract is entirely implicit — no type-level enforcement, no named constant, no runtime assertion. A future tool that writes a notebook without this flag would silently make the notebook text-editable, leading to JSON corruption through text-level edits.

Consider extracting this into a named helper (e.g., recordNotebookWrite(path, stats)) that wraps recordWrite and documents the invariant, or adding a runtime assertion in recordWrite that cross-references .ipynb extension against cacheable.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

// never terminate; the rejection points the model at
// shell instead.
// re-reading can change: non-text payloads (binary / image /
// audio / video / PDF / notebook). read_file returns these as

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 comment for EDIT_REQUIRES_PRIOR_READ describes case 3 as "non-text payloads (binary / image / audio / video / PDF / notebook)" but omits FIFO/socket/device files. However, priorReadEnforcement.ts:244 still returns EDIT_REQUIRES_PRIOR_READ for !stats.isFile() (FIFO/socket/device). The comment inaccurately describes this usage, and the new TARGET_NOT_REGULAR_FILE code (line 88) is only used by notebook-edit.ts, making the inconsistency between the two tools more confusing.

Suggested fix: either add FIFO/socket/device to the case 3 description, or update priorReadEnforcement.ts to use TARGET_NOT_REGULAR_FILE for consistency.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

NotebookEditToolParams,
NotebookEditModifyMetadata
>();
private readonly modifyMetadataByKey = new Map<

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] modifyMetadataByKey is a regular Map<string, NotebookEditModifyMetadata[]> with no cleanup mechanism. If a user-modify operation is cancelled before consumeModifyMetadata runs, the entry persists forever. Each entry can hold large aiProposedContent and modifiedNotebookContent strings (full serialized notebook JSON). Over a long session with many cancelled modify attempts, this Map grows without bound.

The companion modifyMetadataByParams (WeakMap) is GC-safe, but the string-keyed Map is not. Consider adding TTL-based eviction, a size cap, or restructuring to encode metadata on the params object directly (similar to how EditTool handles it).

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

);
}

protected override validateToolParamValues(

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] validateToolParamValues has 6 validation branches (empty path, non-absolute path, wrong extension, invalid mode, invalid cell_type, missing source) but no direct unit tests covering the specific error messages. JSON Schema catches some cases, but the custom validation's user-friendly error messages are never asserted in tests.

Add expect(...).toThrow(...) tests for each branch to catch regressions in validation logic or error message changes.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

fileDiff,
originalContent: prepared.originalContent,
newContent: prepared.updatedContent,
onConfirm: async (outcome: ToolConfirmationOutcome) => {

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 onConfirm(ProceedAlways) callback calls this.config.setApprovalMode(ApprovalMode.AUTO_EDIT), but this behavior is never tested. If the callback is accidentally removed or the parameter changes, no test would detect it.

Suggested change
onConfirm: async (outcome: ToolConfirmationOutcome) => {
// In the confirmation test:
const editDetails = details as Extract<typeof details, { type: 'edit' }>;
await editDetails.onConfirm(ToolConfirmationOutcome.ProceedAlways);
expect(config.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.AUTO_EDIT);

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

let llmContent: PartUnion;
if (result.isTruncated) {
if (
result.isTruncated &&

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 guard if (result.isTruncated && result.linesShown && result.originalLineCount !== undefined) silently assumes that any isTruncated result WITHOUT linesShown already has truncation info baked into the content string. This is true for notebooks today (they embed "... [N remaining cells truncated...]"), but the assumption is undocumented.

If a future non-text file type sets isTruncated: true without linesShown and without embedding its own truncation message, the LLM will never learn the content was truncated. Add a comment explaining the assumption, or a defensive else if (result.isTruncated) branch with a generic truncation notice.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

getCurrentContent: async (
params: NotebookEditToolParams,
): Promise<string> => readCurrentContentSnapshot(params),
getProposedContent: async (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] getProposedContent calls applyNotebookEdit directly, which can throw NotebookEditError (with .type field). The framework in coreToolScheduler checks .errorType (from StructuredToolError) for error classification. Since NotebookEditError.type.errorType, errors from this path would be classified as UNHANDLED_EXCEPTION instead of the proper type (e.g., NOTEBOOK_CELL_NOT_FOUND).

Wrap with the same conversion used in prepareEdit:

Suggested change
getProposedContent: async (
getProposedContent: async (params) => {
const content = await readCurrentContentSnapshot(params);
try {
return applyNotebookEdit(content, params).updatedContent;
} catch (error) {
if (error instanceof NotebookEditError) {
throw new StructuredToolError(error.message, error.type);
}
throw error;
}
},

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

}

function prepareModifiedNotebookContent(
originalContent: string,

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] prepareModifiedNotebookContent uses a more conservative requiresReadAfterWrite formula (!hasStableCellIds(original) || !hasStableCellIds(notebook)) compared to applyNotebookEdit (structuralEdit && !(originalHasStable && updatedHasStable)). The difference is intentional (user-modified content may have arbitrary structural changes) but undocumented. A future maintainer reading one formula might "harmonize" the other to match, breaking one of the two paths.

Add a comment explaining why the user-modify path is more conservative.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review


export function inferNotebookJsonFormat(content: string): NotebookJsonFormat {
const lineMatch = content.match(/\n( +)"/);
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.

[Critical] inferNotebookJsonFormat regex /\\n( +)"/ only detects space-based indentation. Tab-indented notebooks (valid JSON, produced by some editors including VS Code with tab settings) yield indent: undefined, causing serializeNotebook to call JSON.stringify(notebook, null, undefined) — producing minified single-line JSON. A single cell edit would destroy formatting across the entire file.

Suggested change
return {
export function inferNotebookJsonFormat(content: string): NotebookJsonFormat {
const trailingNewline = content.endsWith('\n');
const match = content.match(/\n([ \t]+)"/);
const indent = match?.[1] !== undefined
? (match[1].includes('\t') ? match[1] : match[1].length)
: undefined;
return { indent, trailingNewline };
}

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

}
}

override async execute(signal: AbortSignal): Promise<ToolResult> {

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 debug logging on the successful write path. debugLogger is only invoked for prior-read rejections (line 110) and post-write cache failures (line 635). A successful notebook edit — including which cell was targeted, mode used, requiresReadAfterWrite decision, and whether content was user-modified — produces zero debug output. At 3 AM debugging a "model deleted the wrong cell" report, there's no trace to reconstruct what happened.

Add debugLogger.debug('execute-success', { path, mode, cellId, requiresReadAfterWrite, modifiedByUser }) after the write succeeds.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

if (prepared.requiresReadAfterWrite) {
cache.invalidate(postWriteStats);
} else {
cache.recordWrite(this.params.notebook_path, postWriteStats, {

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 { cacheable: false } flag here is the sole guard preventing the regular Edit/WriteFile tools from corrupting .ipynb files. checkPriorRead in priorReadEnforcement.ts rejects files where lastReadCacheable === false. But this contract is entirely implicit — no type-level enforcement, no named constant, no runtime assertion. A future tool that writes a notebook without this flag would silently make the notebook text-editable, leading to JSON corruption through text-level edits.

Consider extracting into a named helper (e.g., recordNotebookWrite(path, stats)) that documents the invariant.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

// never terminate; the rejection points the model at
// shell instead.
// re-reading can change: non-text payloads (binary / image /
// audio / video / PDF / notebook). read_file returns these as

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 comment for EDIT_REQUIRES_PRIOR_READ describes case 3 as "non-text payloads (binary / image / audio / video / PDF / notebook)" but omits FIFO/socket/device files. However, priorReadEnforcement.ts:244 still returns EDIT_REQUIRES_PRIOR_READ for !stats.isFile() (FIFO/socket/device). The comment inaccurately describes this usage, and the new TARGET_NOT_REGULAR_FILE code is only used by notebook-edit.ts, making the inconsistency confusing.

Fix: add FIFO/socket/device to the case 3 description, or update priorReadEnforcement.ts to use TARGET_NOT_REGULAR_FILE for consistency.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

NotebookEditToolParams,
NotebookEditModifyMetadata
>();
private readonly modifyMetadataByKey = new Map<

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] modifyMetadataByKey is a regular Map<string, NotebookEditModifyMetadata[]> with no cleanup mechanism. If a user-modify operation is cancelled before consumeModifyMetadata runs, the entry persists forever holding multi-KB notebook content strings. Over a long session with many cancelled modify attempts, this Map grows without bound.

Consider adding TTL-based eviction, a size cap, or restructuring to encode metadata on the params object directly (similar to how EditTool handles it).

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

return cell ? getCellDisplayId(cell, index) : `cell-${index}`;
}

function resolveTargetIndex(

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] resolveTargetIndex calls isAmbiguousCellId() and findCellIndex() sequentially, each internally calling findCellIndexesByDisplayId() which iterates every cell via forEach. The cell array is scanned twice for the same cellId.

Call findCellIndexesByDisplayId once, check length for ambiguity (>1), zero (not found), and return the index — eliminating the redundant scan.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

);
}

protected override validateToolParamValues(

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] validateToolParamValues has 6 validation branches (empty path, non-absolute path, wrong extension, invalid mode, invalid cell_type, missing source) but no direct unit tests covering the specific error messages. JSON Schema catches some cases, but the custom validation's user-friendly error messages are never asserted.

Add expect(...).toThrow(...) tests for each branch to catch regressions.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

fileDiff,
originalContent: prepared.originalContent,
newContent: prepared.updatedContent,
onConfirm: async (outcome: ToolConfirmationOutcome) => {

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 onConfirm(ProceedAlways) callback calls setApprovalMode(AUTO_EDIT), but this behavior is never tested. If the callback is removed or the parameter changes, no test would detect it.

Add to the confirmation test: await editDetails.onConfirm(ToolConfirmationOutcome.ProceedAlways); expect(config.setApprovalMode).toHaveBeenCalledWith(ApprovalMode.AUTO_EDIT);

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

let llmContent: PartUnion;
if (result.isTruncated) {
if (
result.isTruncated &&

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 guard if (result.isTruncated && result.linesShown && result.originalLineCount !== undefined) silently assumes any isTruncated result WITHOUT linesShown already has truncation info in the content. True for notebooks today, but undocumented. A future non-text file type that sets isTruncated: true without linesShown and without embedding its own truncation message would silently lose the truncation signal.

Add a comment explaining the assumption, or a defensive else if (result.isTruncated) branch.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

getCurrentContent: async (
params: NotebookEditToolParams,
): Promise<string> => readCurrentContentSnapshot(params),
getProposedContent: async (

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] getProposedContent calls applyNotebookEdit directly, which can throw NotebookEditError (with .type field). The framework checks .errorType (from StructuredToolError). Since NotebookEditError.type.errorType, errors would be classified as UNHANDLED_EXCEPTION instead of the proper type.

Wrap with: try { return applyNotebookEdit(content, params).updatedContent; } catch (e) { if (e instanceof NotebookEditError) throw new StructuredToolError(e.message, e.type); throw e; }

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

}

function prepareModifiedNotebookContent(
originalContent: string,

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] prepareModifiedNotebookContent uses a more conservative requiresReadAfterWrite formula (!hasStableCellIds(original) || !hasStableCellIds(notebook)) compared to applyNotebookEdit (structuralEdit && !(originalHasStable && updatedHasStable)). The difference is intentional (user-modified content may have arbitrary structural changes) but undocumented. A future maintainer might "harmonize" them, breaking one path.

Add a comment explaining why the user-modify path is more conservative.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

if (index === -1) {
throw new NotebookEditError(
`Cell with ID "${cellId}" not found in notebook.`,
ToolErrorType.NOTEBOOK_CELL_NOT_FOUND,

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] resolveTargetIndex returns NOTEBOOK_CELL_NOT_FOUND for all modes including insert, but the insert-mode-with-nonexistent-cell_id scenario is not covered by tests. Only insert-without-cell_id (insert at beginning) and insert-with-existing-cell_id are tested.

Suggested change
ToolErrorType.NOTEBOOK_CELL_NOT_FOUND,
// Add test: insert mode with cell_id="nonexistent" → expect NOTEBOOK_CELL_NOT_FOUND

— DeepSeek/deepseek-v4-pro via Qwen Code /review

const code = (error as NodeJS.ErrnoException | undefined)?.code;
if (code === 'ENOENT') {
if (options.expectExisting) {
return rejectNotebookPriorRead(notebookPath, 'missing-after-read', {

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 TOCTOU path where expectExisting=true and the file disappears between checks (ENOENT → FILE_CHANGED_SINCE_READ) lacks test coverage. This is a key safety path: the model reads a notebook, but before the edit executes, the file is deleted externally.

Suggested change
return rejectNotebookPriorRead(notebookPath, 'missing-after-read', {
// Add test: seed a read, delete the file before execute(), verify FILE_CHANGED_SINCE_READ

— DeepSeek/deepseek-v4-pro via Qwen Code /review

return `Notebook path must be absolute: ${params.notebook_path}`;
}

if (path.extname(params.notebook_path).toLowerCase() !== '.ipynb') {

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 non-.ipynb extension rejection in validateToolParamValues is not tested. All existing tests use .ipynb paths.

Suggested change
if (path.extname(params.notebook_path).toLowerCase() !== '.ipynb') {
// Add test: notebook_path="/tmp/not-a-notebook.txt" → expect rejection with "must be a Jupyter notebook (.ipynb)"

— DeepSeek/deepseek-v4-pro via Qwen Code /review

let llmContent: PartUnion;
if (result.isTruncated) {
if (
result.isTruncated &&

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 isTruncated && linesShown && originalLineCount !== undefined guard at this line correctly prevents notebook truncation headers from being added, but the notebook cacheable: false path (which flows through this guard's else branch and records lastReadCacheable: false) is not tested for the file_unchanged fast-path behavior. The existing notebook test only does a single read_file call.

Suggested change
result.isTruncated &&
// Add test: read_file on .ipynb twice → both returns should be full notebook content, not file_unchanged placeholder

— DeepSeek/deepseek-v4-pro via Qwen Code /review

const lineMatch = content.match(/\n( +)"/);
return {
indent: lineMatch?.[1]?.length,
trailingNewline: content.endsWith('\n'),

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] inferNotebookJsonFormat's trailingNewline: true branch (when the raw notebook JSON ends with \n) is not directly tested. Existing tests only cover trailingNewline: false (compact JSON).

Suggested change
trailingNewline: content.endsWith('\n'),
// Add test: notebook JSON ending with \n → inferNotebookJsonFormat returns trailingNewline: true, serializeNotebook preserves it

— DeepSeek/deepseek-v4-pro via Qwen Code /review

});
}

if (stats.isDirectory()) {

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] checkPriorNotebookReadstats.isDirectory() 分支(第 356-361 行)——当 notebook_path 解析为目录时,返回 TARGET_IS_DIRECTORY ——没有专门的测试覆盖。

如果用户以某种方式绕过 .ipynb 扩展名检查(例如,目录命名为 foo.ipynb),此路径依赖于未测试的代码来提供结构化的 TARGET_IS_DIRECTORY 错误。

Suggested change
if (stats.isDirectory()) {
// 在 notebook-edit.test.ts 中添加:
// 在 tempDir 中创建一个名为 dir.ipynb 的目录,seedNotebookRead 它,
// 然后断言 buildInvocation(...).execute() 返回 ToolErrorType.TARGET_IS_DIRECTORY

— DeepSeek/deepseek-v4-pro via Qwen Code /review

} catch (error) {
const code = (error as NodeJS.ErrnoException | undefined)?.code;
if (code === 'ENOENT') {
if (options.expectExisting) {

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] checkPriorNotebookReadENOENT + expectExisting: true 分支(第 337-343 行)——当文件在两次 stat 检查之间消失时,返回 FILE_CHANGED_SINCE_READ ——缺乏测试。

这是 prepareEdit 中的双重检查模式。现有的 "tracks file history before the final freshness check" 测试覆盖了外部修改路径,而非完全消失。如果文件消失,应返回正确的错误类型以区分"文件已更改"与"文件不再存在"。

Suggested change
if (options.expectExisting) {
// 在 notebook-edit.test.ts 中添加:
// seed 一个 notebook 读取,然后在 buildInvocation 之后但在 execute 之前删除文件路径。
// 验证错误类型为 ToolErrorType.FILE_CHANGED_SINCE_READ,消息包含 "disappeared"

— DeepSeek/deepseek-v4-pro via Qwen Code /review

return { ok: true };
}

return rejectNotebookPriorRead(notebookPath, 'stat-failed', {

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] checkPriorNotebookRead 中非 ENOENT 的 stat 失败分支(第 348-353 行)——当 fs.promises.stat 抛出错误且错误码既不是 ENOENT 也不是 undefined 时,返回 PRIOR_READ_VERIFICATION_FAILED ——缺乏测试。

文件系统问题如 EACCESEBUSY 或 NFS 故障需要正确的错误类型才能被调用者和指标理解。

Suggested change
return rejectNotebookPriorRead(notebookPath, 'stat-failed', {
// 在 notebook-edit.test.ts 中添加:
// 模拟 fs.promises.stat,抛出带有 EACCES 代码的 ErrnoException,
// seed 一个读取以确保文件存在,然后断言执行返回 ToolErrorType.PRIOR_READ_VERIFICATION_FAILED

— DeepSeek/deepseek-v4-pro via Qwen Code /review


async function checkPriorNotebookRead(
config: Config,
notebookPath: string,

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] checkPriorNotebookReadconfig.getFileReadCacheDisabled()true 时直接返回 { ok: true },完全跳过所有文件系统检查——包括 stat、isDirectory、isFile 以及 expectExisting 检查。

在缓存禁用模式下,notebook_edit 可以对已删除的文件静默创建新文件,或对目录/特殊文件进行操作。expectExisting: true 场景(文件在读后消失)在缓存禁用时毫无防护。

Suggested change
notebookPath: string,
// 即使缓存禁用,也应保留基本的文件系统检查:
try {
const stats = await fs.promises.stat(notebookPath);
if (stats.isDirectory()) return rejectNotebookPriorRead(...);
if (!stats.isFile()) return rejectNotebookPriorRead(...);
} catch (error) {
const code = (error as NodeJS.ErrnoException)?.code;
if (code === 'ENOENT' && options.expectExisting) return rejectNotebookPriorRead(...);
if (code === 'ENOENT') return { ok: true };
return rejectNotebookPriorRead(...);
}
if (config.getFileReadCacheDisabled()) return { ok: true };
// ... rest of cache checks

— DeepSeek/deepseek-v4-pro via Qwen Code /review

message,
type: ToolErrorType.FILE_WRITE_FAILURE,
},
};

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] execute() 在写入阶段捕获错误并将其包装为 Error writing notebook: ${message},但丢弃了 notebook_pathcell_id 上下文。

如果多个 notebook 编辑同时进行且其中一个失败,运维人员只有错误消息字符串可供关联——没有路径、cell ID 或编辑模式。

Suggested change
};
llmContent: `Error writing notebook ${this.params.notebook_path} (${prepared.mode} cell ${prepared.editedCellId}): ${message}`,

— DeepSeek/deepseek-v4-pro via Qwen Code /review


function rejectNotebookPriorRead(
notebookPath: string,
reason: string,

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] NotebookPriorReadDecision 类型与 priorReadEnforcement.ts 中的 PriorReadDecision 结构重复。两者都定义了 { ok: true } | { ok: false; type: ToolErrorType; rawMessage: string; displayMessage: string }

未来如果有人向 PriorReadDecision 添加新字段(例如 retry-after 提示),NotebookPriorReadDecision 将会静默发散。

Suggested change
reason: string,
// 选项 1: 直接复用 PriorReadDecision
import type { PriorReadDecision } from '../priorReadEnforcement.js';
// 选项 2: 提取共享接口
export interface RejectionDetail {
type: ToolErrorType;
rawMessage: string;
displayMessage: string;
}

— DeepSeek/deepseek-v4-pro via Qwen Code /review


override async execute(signal: AbortSignal): Promise<ToolResult> {
let prepared: PreparedNotebookEdit;
try {

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] prepareEditgetConfirmationDetails()execute() 各调用一次,每次都会重新读取整个 notebook 文件并重新计算编辑结果。

确认时展示的 diff 基于第一次读取(T1),但实际写入使用第二次读取(T2)的内容。如果文件在 T1 和 T2 之间被外部修改,用户批准的 diff 与实际写入内容不匹配。execute() 中的 checkPriorNotebookRead 互锁会捕获 mtime/size 漂移并拒绝,但错误消息说 "modified since you last read it"——在用户刚批准确认后就收到过期读取错误,看起来很困惑。

Suggested change
try {
// 将 prepareEdit 结果缓存在 invocation 实例上:
private preparedEditCache: PreparedNotebookEdit | undefined;
private async prepareEdit(abortSignal: AbortSignal): Promise<PreparedNotebookEdit> {
if (this.preparedEditCache) return this.preparedEditCache;
// ... 现有逻辑
this.preparedEditCache = result;
return result;
}

— DeepSeek/deepseek-v4-pro via Qwen Code /review

@pomelo-nwu

Copy link
Copy Markdown
Collaborator

Thanks @wenshao and @yiliang114 for the detailed review. I re-checked every [Critical] against the current head (1eaf0112). Net: the functional criticals are all resolved; one 3-line edge case is worth fixing before merge, and the rest are test-coverage / defensive hardening that I'd suggest tracking as follow-ups rather than blocking.

Resolved functional criticals (verified in current code)

  • Internal-param prompt injectionNotebookEditToolParams now exposes only the 5 public params, schema sets additionalProperties: false, and modify metadata is carried off the LLM-facing path (notebook-edit.ts:66, :755).
  • parseNotebook crash on null / non-object cells — validated per cell (notebook.ts:110).
  • Large-notebook truncation retry loop — dedicated truncated-cache-entry rejection with a "too large / split the notebook" message (notebook-edit.ts:386).
  • readManyFiles linesShown! TypeError — guarded with linesShown && (readManyFiles.ts:204).
  • Structural-edit cache invalidation, IDE-modify discard, commit attribution, and trackEdit all landed in earlier commits.

One issue worth fixing before merge

inferNotebookJsonFormat's regex /\n( +)"/ matches space indentation only. A tab-indented .ipynb gives indent: undefined, so serializeNotebook minifies the whole file to one line. This does not corrupt data (the JSON stays valid / openable) — it's diff-noise on a rare input — but it's an easy fix:

const match = content.match(/\n([ \t]+)"/);
const indent = match?.[1] ? (match[1].includes('\t') ? match[1] : match[1].length) : undefined;

Suggest as follow-ups (non-blocking)

  • The three newest [Critical]s (dir / ENOENT / non-ENOENT stat branches) are test-coverage asks — the logic already exists (notebook-edit.ts:357, :338, :348); only unit tests are missing.
  • Remaining [Suggestion]s: success-path debug log, modifyMetadataByKey eviction, documenting the cacheable:false invariant, PriorReadDecision de-dup, prepareEdit double-call micro-opt, richer write-error context, and assorted comments.

CI is green and there's one approval. Proposal: land the tab-indent fix, merge, and open a follow-up for the test-coverage + hardening items. Happy to push the tab-indent fix.

中文

感谢 @wenshao@yiliang114 的细致 review。我对照当前 head(1eaf0112)逐条核对了所有 [Critical]。结论:功能性 critical 已全部修复;有一个 3 行的边缘情况建议合并前修掉,其余都是测试覆盖 / 防御性增强,建议作为 follow-up 跟进,不必阻塞合并。

已修复的功能性 critical(已在当前代码核实)

  • 内部参数 prompt injectionNotebookEditToolParams 现在只暴露 5 个公开参数,schema 设了 additionalProperties: false,modify 元数据不再走 LLM 参数路径(notebook-edit.ts:66:755)。
  • parseNotebook 遇 null / 非对象 cell 崩溃:已逐项校验(notebook.ts:110)。
  • 大 notebook 截断导致重读死循环:新增 truncated-cache-entry 拒绝路径,提示"过大 / 拆分 notebook"(notebook-edit.ts:386)。
  • readManyFileslinesShown! TypeError:已用 linesShown && 守卫(readManyFiles.ts:204)。
  • 结构性编辑后的缓存失效、IDE 修改丢弃、commit 归属、trackEdit 均在更早的 commit 中落地。

一个建议合并前修掉的问题

inferNotebookJsonFormat 的正则 /\n( +)"/ 只匹配空格缩进。tab 缩进的 .ipynb 会得到 indent: undefined,导致 serializeNotebook 把整个文件压成单行。这不会损坏数据(JSON 仍合法、可正常打开),只是罕见输入下的 diff 噪声——修复很简单(见上方代码)。

建议转为 follow-up(不阻塞)

  • 最新的三个 [Critical](目录 / ENOENT / 非 ENOENT stat 分支)实为补测试——逻辑已存在(notebook-edit.ts:357:338:348),缺的只是单元测试。
  • 其余 [Suggestion]:成功路径 debug 日志、modifyMetadataByKey 清理、把 cacheable:false 不变量文档化、PriorReadDecision 类型去重、prepareEdit 重复调用的微优化、写入错误补充上下文,以及若干注释。

CI 全绿,且已有一个 approval。建议:合入 tab 缩进修复后即可 merge,测试覆盖与防御性项另开 follow-up。我可以来提交 tab 缩进的修复。

@zhangxy-zju zhangxy-zju dismissed stale reviews from wenshao, wenshao, wenshao, and wenshao May 20, 2026 16:05

Dismissing to merge the complete NotebookEdit feature now. The remaining review items are accepted as follow-up work: one tab-indentation formatting fix and a few low-risk unit-test additions will be handled in a subsequent PR; other hardening suggestions are non-blocking follow-ups.

@zhangxy-zju zhangxy-zju merged commit ed14a33 into main May 20, 2026
58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Jupyter Notebook Read/Edit Support

4 participants