Skip to content

fix(core): limit skill watcher depth to prevent FD exhaustion#3320

Merged
tanzhenxin merged 2 commits into
mainfrom
fix/3289-skill-watcher-fd-exhaustion
Apr 17, 2026
Merged

fix(core): limit skill watcher depth to prevent FD exhaustion#3320
tanzhenxin merged 2 commits into
mainfrom
fix/3289-skill-watcher-fd-exhaustion

Conversation

@tanzhenxin

@tanzhenxin tanzhenxin commented Apr 16, 2026

Copy link
Copy Markdown
Collaborator

TLDR

The skill file watcher had no depth limit, causing it to recursively watch entire subtrees (including node_modules) inside skill directories. This exhausted file descriptors, which broke shell command execution — node-pty could spawn processes but its I/O callbacks silently stopped firing, making every shell command return exit code 1 with no output.

The fix limits watcher depth to 2 levels (matching the <skill-name>/SKILL.md layout) and filters out .git directories and special file types (sockets, FIFOs, devices).

Screenshots / Video Demo

N/A — no user-facing change beyond restoring correct shell command behavior.

Dive Deeper

The root cause chain:

  1. SkillManager.updateWatchersFromCache() calls chokidar watch() with no depth or ignored options
  2. If a skill directory contains node_modules (e.g., a skill that depends on electron), chokidar opens a file handle for every file recursively
  3. This exhausts the OS file descriptor limit (typically 4096 on macOS/Linux)
  4. Once FDs are exhausted, node-pty.spawn() succeeds but onData/onExit callbacks never fire
  5. Shell commands time out and return exit code 1 with empty output

The depth limit of 2 is sufficient because skills follow a flat <skill-name>/SKILL.md convention — there's no reason to watch deeper. The ignored function additionally filters out special file types that cause EOPNOTSUPP errors on lstat.

Reviewer Test Plan

  1. Install a skill that has a node_modules directory with many files (or create a dummy one with 500+ files)
  2. Start qwen-code and run !pwd or !ls — should return output normally
  3. Check lsof -p <pid> | wc -l — FD count should stay reasonable (not climb into thousands)
  4. Verify skill hot-reload still works: edit a SKILL.md file and confirm the change is picked up

Testing Matrix

🍏 🪟 🐧
npm run
npx
Docker
Podman - -
Seatbelt - -

Linked issues / bugs

@github-actions

Copy link
Copy Markdown
Contributor

📋 Review Summary

This PR fixes a critical file descriptor exhaustion issue in the skill file watcher by limiting chokidar's watch depth and filtering special file types. The fix is well-targeted, minimal, and includes comprehensive tests. The implementation correctly addresses issue #3289.

🔍 General Feedback

  • Clean, minimal fix: The changes are surgical and focused on the root cause (unbounded recursive watching)
  • Good test coverage: Three new test cases cover the watcher options, .git filtering, and special file type handling
  • Well-documented: Code comments clearly explain the rationale (skill directory layout, FD exhaustion, EOPNOTSUPP errors)
  • Proper exports: WATCHER_MAX_DEPTH and watcherIgnored are exported for testing, which is a good pattern
  • Follows conventions: Uses vi.hoisted() correctly for mocks consumed by vi.mock()

🎯 Specific Feedback

🟢 Medium

  • File: skill-manager.test.ts:24-37 - The chokidar mock setup is duplicated in the test file. Consider extracting this into a shared test utility if similar mocking is needed elsewhere, or adding a comment explaining why this mock is local to this file.

  • File: skill-manager.test.ts:947 - The test watcherIgnored should reject special file types creates mock Stats objects inline. Consider extracting a helper function like makeMockStats() for reusability and clarity:

    const makeMockStats = (options: { isFile: boolean; isDirectory: boolean }) => ({
      isFile: () => options.isFile,
      isDirectory: () => options.isDirectory,
    } as fsSync.Stats);

🔵 Low

  • File: skill-manager.ts:44 - The comment mentions the fixed layout <skill-name>/SKILL.md, but consider adding a reference to the issue number for traceability:

    // that would otherwise exhaust file descriptors (see #3289).
  • File: skill-manager.ts:48-54 - The watcherIgnored function could benefit from a JSDoc comment explaining its purpose and parameters, consistent with other exported functions in the codebase.

  • File: skill-manager.test.ts:959 - Consider adding a test case for .git at the end of a path (e.g., /skills/my-skill/.git) to ensure the includes('.git') check works correctly for nested .git directories.

✅ Highlights

  • Excellent bug fix: Addresses a real production issue (FD exhaustion causing silent shell command failures)
  • Smart depth limit: depth: 2 is well-reasoned given the fixed skill directory layout
  • Defensive filtering: The ignored function prevents EOPNOTSUPP errors from special files (sockets, FIFOs, devices)
  • Comprehensive tests: All three test cases are meaningful and cover the key scenarios
  • E2E verification: The PR description mentions E2E testing with 800+ files in node_modules - excellent validation

@github-actions

github-actions Bot commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 54.85% 54.85% 68.32% 79.53%
Core 75.14% 75.14% 78.36% 81.45%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   54.85 |    79.53 |   68.32 |   54.85 |                   
 src               |   68.25 |    66.28 |   72.22 |   68.25 |                   
  gemini.tsx       |   60.85 |    62.06 |      75 |   60.85 | ...35,543-546,554 
  ...ractiveCli.ts |   61.61 |     61.4 |      40 |   61.61 | ...79,386,390-519 
  ...liCommands.ts |   83.84 |    69.76 |     100 |   83.84 | ...14,249,251,379 
  ...ActiveAuth.ts |     100 |    88.23 |     100 |     100 | 66,80             
 ...cp-integration |   14.12 |       80 |      40 |   14.12 |                   
  acpAgent.ts      |   12.65 |    83.33 |      60 |   12.65 | ...64-169,172-712 
  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 |   64.06 |    65.67 |   73.07 |   64.06 |                   
  ...ryReplayer.ts |      76 |    79.41 |      90 |      76 | ...19-220,228-229 
  Session.ts       |   56.89 |    59.42 |      60 |   56.89 | ...1887,1893-1896 
  ...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 |   91.53 |    89.47 |   88.46 |   91.53 |                   
  BaseEmitter.ts   |   76.92 |    66.66 |      80 |   76.92 | 23-24,39-40,55-56 
  ...ageEmitter.ts |   82.22 |    83.33 |   83.33 |   82.22 | 29-44             
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   97.96 |     91.8 |     100 |   97.96 | 230-231,320,328   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |   88.03 |    85.13 |   94.11 |   88.03 |                   
  LlmRewriter.ts   |   80.53 |    79.31 |     100 |   80.53 | ...17-119,170-174 
  ...Middleware.ts |   91.39 |    83.33 |     100 |   91.39 | ...23-125,141-144 
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/commands      |   66.22 |      100 |    12.5 |   66.22 |                   
  auth.ts          |   46.55 |      100 |       0 |   46.55 | ...58,67-72,75-76 
  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                
 src/commands/auth |   42.15 |    95.83 |      60 |   42.15 |                   
  handler.ts       |   27.29 |    94.44 |   14.28 |   27.29 | 55-406            
  ...veSelector.ts |     100 |    96.66 |     100 |     100 | 58                
 ...mmands/channel |   26.76 |    93.75 |   26.47 |   26.76 |                   
  ...l-registry.ts |    8.57 |      100 |       0 |    8.57 | 6-21,24-42        
  config-utils.ts  |   91.89 |      100 |   66.66 |   91.89 | 20-25             
  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         |     5.2 |      100 |       0 |     5.2 | ...61-464,466-474 
  status.ts        |   17.54 |      100 |       0 |   17.54 | 15-26,32-77       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   84.53 |    88.95 |   81.81 |   84.53 |                   
  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  |   91.28 |    82.97 |   88.88 |   91.28 |                   
  add.ts           |     100 |    96.66 |     100 |     100 | 213               
  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             
 src/config        |   91.41 |    81.42 |    85.5 |   91.41 |                   
  auth.ts          |   87.87 |    81.35 |     100 |   87.87 | ...20-221,237-238 
  config.ts        |   87.25 |    81.85 |   72.22 |   87.25 | ...1156,1178-1179 
  keyBindings.ts   |   95.95 |       50 |     100 |   95.95 | 160-163           
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  sandboxConfig.ts |    58.9 |    61.53 |   66.66 |    58.9 | ...54-68,73,77-89 
  settings.ts      |   83.13 |    82.55 |   85.71 |   83.13 | ...35-936,941-944 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.29 |       94 |     100 |   96.29 | ...88-190,205-206 
  webSearch.ts     |   41.37 |       25 |     100 |   41.37 | ...4,88-95,98-114 
 ...nfig/migration |   94.56 |    78.94 |   83.33 |   94.56 |                   
  index.ts         |   93.93 |    88.88 |     100 |   93.93 | 85-86             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   93.63 |     94.5 |     100 |   93.63 |                   
  ...-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 |                   
 src/constants     |   93.66 |    94.11 |   66.66 |   93.66 |                   
  ...dardApiKey.ts |     100 |      100 |     100 |     100 |                   
  codingPlan.ts    |   93.43 |    94.11 |   66.66 |   93.43 | ...26-327,335-347 
 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/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   45.08 |    76.19 |   38.88 |   45.08 |                   
  index.ts         |   26.11 |    76.92 |   26.66 |   26.11 | ...35-236,246-257 
  languages.ts     |   98.43 |       75 |     100 |   98.43 | 95                
 src/i18n/locales  |       0 |        0 |       0 |       0 |                   
  de.js            |       0 |        0 |       0 |       0 | 1-2018            
  en.js            |       0 |        0 |       0 |       0 | 1-2057            
  fr.js            |       0 |        0 |       0 |       0 | 1-2095            
  ja.js            |       0 |        0 |       0 |       0 | 1-1508            
  pt.js            |       0 |        0 |       0 |       0 | 1-2008            
  ru.js            |       0 |        0 |       0 |       0 | 1-2015            
  zh.js            |       0 |        0 |       0 |       0 | 1-1862            
 ...nonInteractive |   68.34 |    71.68 |   68.88 |   68.34 |                   
  session.ts       |    73.1 |    69.52 |   81.81 |    73.1 | ...03-604,612-622 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...80-581,584-585 
 ...active/control |   77.55 |    88.23 |      80 |   77.55 |                   
  ...rolContext.ts |    7.69 |        0 |       0 |    7.69 | 47-79             
  ...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.07 |       80 |   13.33 |    7.07 |                   
  ...Controller.ts |   19.32 |      100 |      60 |   19.32 | 81-118,127-210    
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    3.96 |      100 |   11.11 |    3.96 | ...61-379,389-494 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |    5.27 |      100 |       0 |    5.27 | ...21-433,442-467 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   97.57 |    92.91 |   96.15 |   97.57 |                   
  ...putAdapter.ts |    97.3 |    91.75 |     100 |    97.3 | ...1272,1297-1298 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.23 |      100 |   89.47 |   98.23 | 70-71,111-112     
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/services      |   88.74 |    86.69 |   96.29 |   88.74 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 79                
  ...killLoader.ts |     100 |    95.65 |     100 |     100 | 39                
  ...andService.ts |     100 |      100 |     100 |     100 |                   
  ...mandLoader.ts |   86.38 |    81.48 |     100 |   86.38 | ...25-330,335-340 
  ...omptLoader.ts |    75.1 |    80.64 |   83.33 |    75.1 | ...03-204,270-271 
  ...nd-factory.ts |    91.2 |    93.33 |     100 |    91.2 | 119-126           
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...and-parser.ts |   89.74 |    85.71 |     100 |   89.74 | 59-62             
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   85.95 |    86.42 |   90.47 |   85.95 |                   
  DataProcessor.ts |   85.68 |    86.46 |   92.85 |   85.68 | ...1110,1114-1121 
  ...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 |   92.38 |    84.12 |     100 |   92.38 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |    78.3 |    71.42 |     100 |    78.3 | ...33-148,151,160 
  tipRegistry.ts   |     100 |    95.23 |     100 |     100 | 33                
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/test-utils    |   93.63 |    83.33 |      80 |   93.63 |                   
  ...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            |   62.53 |    66.34 |   51.35 |   62.53 |                   
  App.tsx          |     100 |      100 |     100 |     100 |                   
  AppContainer.tsx |   65.62 |    58.75 |   71.42 |   65.62 | ...1573,1589-1722 
  ...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        |   52.72 |      100 |   23.52 |   52.72 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   91.83 |    88.46 |     100 |   91.83 | 25-26,54-55       
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   29.61 |       50 |   26.08 |   29.61 |                   
  AuthDialog.tsx   |   51.82 |    51.16 |   28.57 |   51.82 | ...73,692,694,696 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  useAuth.ts       |    2.47 |      100 |       0 |    2.47 | 48-612            
 src/ui/commands   |   57.97 |    79.07 |   50.54 |   57.97 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |    64.7 |      100 |       0 |    64.7 | ...30,35-36,39-41 
  ...odeCommand.ts |     100 |      100 |     100 |     100 |                   
  arenaCommand.ts  |   32.65 |    67.64 |    37.5 |   32.65 | ...52-557,636-641 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |     100 |    91.66 |     100 |     100 | 26,239,253        
  bugCommand.ts    |   76.47 |    66.66 |      50 |   76.47 | 21-22,58-67       
  clearCommand.ts  |   89.65 |    55.55 |      50 |   89.65 | 23-24,49-50,68-69 
  ...essCommand.ts |   63.15 |       50 |      50 |   63.15 | ...47-148,162-165 
  ...extCommand.ts |    6.82 |      100 |       0 |    6.82 | ...59-360,364-365 
  copyCommand.ts   |   96.22 |      100 |      50 |   96.22 | 15-16             
  ...ryCommand.tsx |   59.19 |    73.07 |    37.5 |   59.19 | ...15-216,224-232 
  docsCommand.ts   |   95.23 |       80 |      50 |   95.23 | 20-21             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   55.97 |    91.66 |   33.33 |   55.97 | ...48-349,356-357 
  ...onsCommand.ts |   44.09 |    85.71 |   27.27 |   44.09 | ...35-236,244-245 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   17.93 |    33.33 |      20 |   17.93 | ...85-186,202-203 
  ideCommand.ts    |   56.79 |    57.69 |   35.29 |   56.79 | ...00-301,304-318 
  initCommand.ts   |    81.7 |       70 |      50 |    81.7 | ...67,81-86,88-93 
  ...ghtCommand.ts |   69.23 |       40 |   66.66 |   69.23 | ...97-111,116-129 
  ...ageCommand.ts |   89.24 |    82.35 |   76.92 |   89.24 | ...20-323,345-346 
  mcpCommand.ts    |   85.71 |      100 |      50 |   85.71 | 14-15             
  memoryCommand.ts |   71.11 |    84.61 |    37.5 |   71.11 | ...89,296-297,315 
  modelCommand.ts  |   56.47 |    81.81 |   66.66 |   56.47 | 25-36,54-80       
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   76.19 |       75 |      50 |   76.19 | ...34,50-55,67-72 
  quitCommand.ts   |   93.75 |      100 |      50 |   93.75 | 15-16             
  ...oreCommand.ts |   92.24 |     87.5 |     100 |   92.24 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   80.12 |    63.63 |      60 |   80.12 | ...69-172,175-178 
  skillsCommand.ts |    12.5 |      100 |       0 |    12.5 | ...89-105,108-135 
  statsCommand.ts  |   76.92 |       75 |      50 |   76.92 | ...36,50-51,65-66 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    4.61 |      100 |       0 |    4.61 | 21-24,27-322      
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |   95.12 |      100 |      50 |   95.12 | 18-19             
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  vimCommand.ts    |   42.85 |      100 |       0 |   42.85 | 14-15,18-28       
 src/ui/components |   62.81 |    74.34 |   63.49 |   62.81 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |     100 |      100 |     100 |     100 |                   
  ApiKeyInput.tsx  |   18.91 |      100 |       0 |   18.91 | 30-95             
  AppHeader.tsx    |   87.03 |    42.85 |     100 |   87.03 | 33-39,41          
  ...odeDialog.tsx |     9.7 |      100 |       0 |     9.7 | 35-47,50-182      
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   14.63 |      100 |       0 |   14.63 | 18-56             
  ...TextInput.tsx |   63.92 |    73.17 |      50 |   63.92 | ...12,226-228,246 
  Composer.tsx     |   89.69 |    58.33 |      50 |   89.69 | ...-55,73,110,123 
  ...itDisplay.tsx |   55.81 |      100 |      50 |   55.81 | 22-38,42-43       
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   90.47 |       75 |     100 |   90.47 | 20-21             
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   12.53 |      100 |       0 |   12.53 | 54-383            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   74.03 |    38.46 |     100 |   74.03 | ...,83-87,116-120 
  ...ngSpinner.tsx |   54.28 |       50 |      50 |   54.28 | 31-48,61          
  Header.tsx       |   94.28 |    76.92 |     100 |   94.28 | 96,98,103-106     
  Help.tsx         |   98.74 |    68.75 |     100 |   98.74 | 74,129            
  ...emDisplay.tsx |   62.05 |    39.02 |     100 |   62.05 | ...55-257,260-269 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   84.49 |     79.1 |     100 |   84.49 | ...1165,1230,1279 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   15.23 |      100 |       0 |   15.23 | 28-133            
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   76.77 |    54.54 |     100 |   76.77 | ...58-474,531-535 
  ...tsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.18 |      100 |       0 |    2.18 | 62-133,148-986    
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   88.14 |    83.87 |     100 |   88.14 | ...01-105,133-138 
  PrepareLabel.tsx |   91.66 |    76.19 |     100 |   91.66 | 73-75,77-79,110   
  ...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           
  ...ionPicker.tsx |   94.18 |    92.85 |     100 |   94.18 | 79,194-202        
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...ngsDialog.tsx |   66.88 |    73.37 |     100 |   66.88 | ...11-819,825-826 
  ...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 |    8.04 |      100 |       0 |    8.04 | 21-129            
  StatsDisplay.tsx |   98.66 |    93.33 |     100 |   98.66 | 199-201           
  ...nsDisplay.tsx |   84.09 |    57.14 |     100 |   84.09 | ...16-118,125-127 
  ThemeDialog.tsx  |   90.95 |    44.44 |      75 |   90.95 | ...16-117,159-161 
  Tips.tsx         |   21.87 |      100 |       0 |   21.87 | 22-40,43-53       
  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            
 ...nts/agent-view |   25.14 |    89.36 |    12.5 |   25.14 |                   
  ...tChatView.tsx |    8.42 |      100 |       0 |    8.42 | 53-272            
  ...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  |    8.25 |      100 |       0 |    8.25 | 35-55,60-167      
  ...oryAdapter.ts |     100 |     91.3 |     100 |     100 | 102,108-109,137   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    5.92 |      100 |       0 |    5.92 |                   
  ArenaCards.tsx   |       4 |      100 |       0 |       4 | 24-129,134-290    
  ...ectDialog.tsx |    5.28 |      100 |       0 |    5.28 | 32-260            
  ...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            
 ...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.77 |    94.23 |   66.66 |   54.77 |                   
  ...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.35 |    94.73 |      80 |   88.35 | 51-52,58-71,105   
  ...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 |   72.24 |    70.52 |      80 |   72.24 |                   
  ...etailStep.tsx |   96.52 |       75 |     100 |   96.52 | 33,37,50,59       
  ...etailStep.tsx |   93.27 |    73.68 |     100 |   93.27 | 41-42,99-104,110  
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   36.09 |    47.05 |      50 |   36.09 | ...49,453-466,470 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   18.82 |    84.37 |   77.77 |   18.82 |                   
  ...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         |   96.42 |    87.09 |     100 |   96.42 | 21,96-97          
 ...ents/mcp/steps |    7.31 |      100 |       0 |    7.31 |                   
  ...icateStep.tsx |    7.58 |      100 |       0 |    7.58 | 27-197            
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.26 |      100 |       0 |    5.26 | 31-247            
  ...rListStep.tsx |    5.88 |      100 |       0 |    5.88 | 20-176            
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |    7.14 |      100 |       0 |    7.14 | 16-146            
 ...nents/messages |   73.24 |    73.26 |   60.37 |   73.24 |                   
  ...ionDialog.tsx |   64.44 |    69.69 |   42.85 |   64.44 | ...20,538,556-558 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   10.97 |      100 |       0 |   10.97 | 22-47,52-114      
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   77.35 |      100 |      70 |   77.35 | ...31-244,248-260 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...sMessages.tsx |   63.85 |       40 |   33.33 |   63.85 | ...06-116,120-125 
  ...ryMessage.tsx |   12.82 |      100 |       0 |   12.82 | 22-59             
  ...onMessage.tsx |   73.55 |    55.81 |   33.33 |   73.55 | ...41-443,450-452 
  ...upMessage.tsx |   86.66 |    65.21 |     100 |   86.66 | ...21,132,188-189 
  ToolMessage.tsx  |   82.37 |     72.6 |   88.88 |   82.37 | ...20-425,452-454 
 ...ponents/shared |   80.96 |    76.14 |   92.42 |   80.96 |                   
  ...ctionList.tsx |   99.03 |    95.65 |     100 |   99.03 | 85                
  ...tonSelect.tsx |   97.14 |    66.66 |     100 |   97.14 | 72                
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   81.13 |    81.96 |   88.88 |   81.13 | ...12-513,618-619 
  MultiSelect.tsx  |    5.59 |      100 |       0 |    5.59 | 34-41,44-193      
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  TextInput.tsx    |   67.92 |    48.14 |      75 |   67.92 | ...90-194,206-212 
  ...Indicator.tsx |     100 |     87.5 |     100 |     100 | 30                
  text-buffer.ts   |   82.82 |    75.96 |   97.56 |   82.82 | ...2282,2309,2377 
  ...er-actions.ts |   86.71 |    67.79 |     100 |   86.71 | ...07-608,809-811 
 ...ents/subagents |    32.1 |      100 |       0 |    32.1 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  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 |    8.39 |      100 |       0 |    8.39 |                   
  ...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 |    2.29 |      100 |       0 |    2.29 | 28-449            
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...agents/runtime |    7.59 |      100 |       0 |    7.59 |                   
  ...onDisplay.tsx |    7.59 |      100 |       0 |    7.59 | ...92-522,531-569 
 ...mponents/views |   48.59 |    69.23 |      30 |   48.59 |                   
  ContextUsage.tsx |    5.07 |      100 |       0 |    5.07 | ...30-145,148-424 
  ...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   |   76.14 |    79.77 |   88.63 |   76.14 |                   
  ...ewContext.tsx |   65.77 |      100 |      75 |   65.77 | ...22-225,231-241 
  AppContext.tsx   |      40 |      100 |       0 |      40 | 17-22             
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   82.93 |    82.67 |     100 |   82.93 | ...1123,1129-1131 
  ...owContext.tsx |   89.28 |       80 |   66.66 |   89.28 | 34,47-48,60-62    
  ...onContext.tsx |   47.02 |     62.5 |   71.42 |   47.02 | ...36-239,243-246 
  ...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             
  ...nsContext.tsx |   89.47 |       50 |     100 |   89.47 | 114-115           
  ...teContext.tsx |   85.71 |       50 |     100 |   85.71 | 157-158           
  ...deContext.tsx |   76.08 |    72.72 |     100 |   76.08 | 47-48,52-59,77-78 
 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      |   80.84 |    81.02 |   83.75 |   80.84 |                   
  ...dProcessor.ts |   83.02 |     81.9 |     100 |   83.02 | ...86-387,406-433 
  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 |   76.08 |    58.71 |   66.66 |   76.08 | ...88,712,731-735 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-158            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...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 |   88.05 |    94.73 |     100 |   88.05 | 84-93             
  ...tIndicator.ts |     100 |    93.75 |     100 |     100 | 63                
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...lanUpdates.ts |     100 |       92 |     100 |     100 | 59,158            
  ...ompletion.tsx |   94.84 |    80.55 |     100 |   94.84 | ...01-202,204-205 
  ...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 
  ...extualTips.ts |   76.92 |       50 |     100 |   76.92 | 55,68,71-75,88-96 
  ...ialogClose.ts |   22.22 |      100 |     100 |   22.22 | 67-109            
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...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 |   50.37 |    77.77 |   33.33 |   50.37 | ...58-174,195-196 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   89.15 |     64.7 |     100 |   89.15 | ...22-124,149-150 
  ...miniStream.ts |   76.35 |    74.58 |   83.33 |   76.35 | ...1830,1839-1841 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   98.41 |    93.33 |     100 |   98.41 | 43                
  ...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 |    8.97 |      100 |       0 |    8.97 | 20-67,74-125      
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |   92.42 |      100 |     100 |   92.42 | 79-83             
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...raseCycler.ts |   84.48 |    76.47 |     100 |   84.48 | ...47,50-51,67-69 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   85.06 |    94.73 |     100 |   85.06 | ...05-208,295-305 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   94.54 |    68.75 |     100 |   94.54 | 60-61,79          
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   96.59 |    94.62 |     100 |   96.59 | ...82-183,237-240 
  ...sionPicker.ts |   91.66 |    72.34 |     100 |   91.66 | ...45-246,250-251 
  ...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 |   78.99 |    81.48 |   94.11 |   78.99 | ...77-579,587-624 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   90.84 |    84.28 |     100 |   90.84 | ...33-335,378-380 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...rminalSize.ts |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   66.66 |    31.25 |     100 |   66.66 | ...09-110,114-115 
  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 |                   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  vim.ts           |   83.77 |    80.31 |     100 |   83.77 | ...55,759-767,776 
 src/ui/layouts    |   73.83 |    38.46 |     100 |   73.83 |                   
  ...AppLayout.tsx |   76.47 |       40 |     100 |   76.47 | 38-40,46-53,73-78 
  ...AppLayout.tsx |   69.23 |    33.33 |     100 |   69.23 | 30-35,39-44       
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |    7.69 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    7.69 |     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     |      99 |    58.38 |     100 |      99 |                   
  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 |                   
  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.08 |    79.36 |     100 |   87.08 | ...03-312,317-318 
  theme.ts         |     100 |    28.98 |     100 |     100 | 272-461           
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   73.12 |    84.18 |      81 |   73.12 |                   
  ...Colorizer.tsx |   82.78 |    88.23 |     100 |   82.78 | ...10-111,197-223 
  ...nRenderer.tsx |   52.41 |    36.36 |      50 |   52.41 | ...49-151,171-180 
  ...wnDisplay.tsx |   86.79 |    88.88 |     100 |   86.79 | ...06-315,348-373 
  ...eRenderer.tsx |   94.45 |    81.25 |   94.11 |   94.45 | ...65,477,480-483 
  ...boardUtils.ts |   59.61 |    58.82 |     100 |   59.61 | ...,86-88,107-149 
  commandUtils.ts  |   93.54 |    88.63 |     100 |   93.54 | ...43,147,149-150 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  displayUtils.ts  |   60.46 |      100 |      50 |   60.46 | 19-35             
  formatters.ts    |    94.8 |    98.07 |     100 |    94.8 | 101-104           
  highlight.ts     |   98.63 |       95 |     100 |   98.63 | 93                
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |     7.4 |      100 |       0 |     7.4 | ...20-121,124-125 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |   98.05 |    95.12 |     100 |   98.05 | 44-45             
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   59.68 |    67.69 |      90 |   59.68 | ...40,388,393-415 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   96.36 |    93.84 |   88.88 |   96.36 | ...49-150,285-286 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |    2.36 |        0 |       0 |    2.36 |                   
  collect.ts       |    0.87 |      100 |       0 |    0.87 | 40-394,401-697    
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |     1.2 |      100 |       0 |     1.2 | 17-346            
  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         |   69.34 |    89.76 |   93.91 |   69.34 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  ...tification.ts |   92.59 |    71.42 |     100 |   92.59 | 36-37             
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   65.38 |      100 |   66.66 |   65.38 | 28-37             
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   85.29 |    89.47 |     100 |   85.29 | 48-57             
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  ...arResolver.ts |   94.28 |    88.46 |     100 |   94.28 | 28-29,125-126     
  errors.ts        |   98.27 |       95 |     100 |   98.27 | 44-45             
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |    51.2 |       90 |      50 |    51.2 | 87-152            
  ...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              
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.84 |    93.28 |     100 |   96.84 | ...87-488,586,599 
  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-984             
  settingsUtils.ts |   86.32 |    90.59 |   94.44 |   86.32 | ...38,569,632-644 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |     100 |       96 |     100 |     100 | 110               
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |      99 |     90.9 |     100 |      99 | 172               
  ...InfoFields.ts |   86.91 |    65.78 |     100 |   86.91 | ...16-117,138-139 
  ...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 |    62.1 |    77.77 |     100 |    62.1 | 93,107,118-157    
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   75.14 |    81.45 |   78.36 |   75.14 |                   
 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        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |   64.56 |    66.66 |   68.49 |   64.56 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |    61.9 |    63.09 |   67.27 |    61.9 | ...1611,1620-1630 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   76.12 |    85.79 |   72.22 |   76.12 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    91.6 |    89.09 |   81.81 |    91.6 | ...15-235,294,379 
  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 |   76.77 |    74.48 |   70.78 |   76.77 |                   
  agent-core.ts    |   70.81 |    67.16 |   56.52 |   70.81 | ...1038,1065-1111 
  agent-events.ts  |   86.48 |      100 |      75 |   86.48 | 218-222           
  ...t-headless.ts |      80 |    69.56 |      55 |      80 | ...67-368,371-372 
  ...nteractive.ts |   83.53 |    78.12 |   77.77 |   83.53 | ...01,503,505,508 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  forkSubagent.ts  |       0 |      100 |     100 |       0 | 3-116             
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   74.37 |    72.42 |   64.14 |   74.37 |                   
  config.ts        |   71.44 |    68.24 |   58.02 |   71.44 | ...2349,2353-2356 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   95.72 |    92.85 |   91.66 |   95.72 | ...06-207,241-242 
 ...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          |   80.73 |    80.28 |   90.25 |   80.73 |                   
  baseLlmClient.ts |     100 |    96.42 |     100 |     100 | 115               
  client.ts        |   72.65 |       75 |   81.81 |   72.65 | ...6,965,991-1007 
  ...tGenerator.ts |    72.1 |    61.11 |     100 |    72.1 | ...42,344,351-354 
  ...lScheduler.ts |      73 |    76.51 |    90.9 |      73 | ...1767,1824-1828 
  geminiChat.ts    |    84.2 |    83.83 |   90.32 |    84.2 | ...86-887,922-925 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  logger.ts        |   82.25 |    81.81 |     100 |   82.25 | ...57-361,407-421 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   75.51 |    53.84 |     100 |   75.51 | ...81-182,196-205 
  prompts.ts       |   88.84 |    88.05 |      75 |   88.84 | ...-899,1102-1103 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 50-51             
  ...okTriggers.ts |   99.31 |     90.9 |     100 |   99.31 | 124,135           
  turn.ts          |   96.27 |    88.46 |     100 |   96.27 | ...76,389-390,438 
 ...ntentGenerator |   93.72 |    73.43 |    90.9 |   93.72 |                   
  ...tGenerator.ts |   95.99 |    72.17 |   86.66 |   95.99 | ...03-304,438,494 
  converter.ts     |   93.47 |       75 |     100 |   93.47 | ...87-488,498,558 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
 ...ntentGenerator |   91.53 |    71.21 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.49 |   92.85 |      90 | ...77-283,301-302 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   90.76 |    76.63 |      85 |   90.76 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   90.72 |    76.63 |      85 |   90.72 | ...06,516-517,545 
 ...ntentGenerator |   75.81 |    84.46 |   91.42 |   75.81 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   70.98 |    78.77 |   88.88 |   70.98 | ...1321,1342-1351 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-94              
  ...tGenerator.ts |   48.78 |    91.66 |   77.77 |   48.78 | ...10-163,166-167 
  pipeline.ts      |    94.8 |    89.88 |     100 |    94.8 | ...68,288-289,455 
  ...CallParser.ts |   90.66 |    88.57 |     100 |   90.66 | ...15-319,349-350 
 ...rator/provider |   95.91 |    85.71 |   93.75 |   95.91 |                   
  dashscope.ts     |   97.22 |    87.69 |   93.33 |   97.22 | ...10-211,287-288 
  deepseek.ts      |   90.76 |       75 |     100 |   90.76 | 40-41,45-46,59-60 
  default.ts       |   94.44 |    84.21 |   85.71 |   94.44 | 85-86,150-152     
  index.ts         |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/extension     |   59.98 |    79.65 |   78.22 |   59.98 |                   
  ...-converter.ts |   62.35 |    47.82 |      90 |   62.35 | ...90-791,800-832 
  ...ionManager.ts |   44.67 |    83.59 |   65.11 |   44.67 | ...1335,1356-1375 
  ...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       |   94.73 |       90 |     100 |   94.73 | 41-42             
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   52.58 |    89.38 |   76.31 |   52.58 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  forkedQuery.ts   |   96.72 |    77.77 |     100 |   96.72 | 143,213-214,263   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   95.06 |       84 |     100 |   95.06 | 78,108,122,133    
  speculation.ts   |    13.4 |      100 |   16.66 |    13.4 | 88-458,518-563    
  ...onToolGate.ts |     100 |    96.29 |     100 |     100 | 93                
  ...nGenerator.ts |   37.25 |    95.12 |   33.33 |   37.25 | ...20-322,357-387 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/hooks         |   80.57 |    84.34 |   84.16 |   80.57 |                   
  ...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.37 |    90.54 |     100 |   96.37 | ...89,291-292,365 
  ...entHandler.ts |   95.58 |    84.37 |   92.59 |   95.58 | ...29,682-683,693 
  hookPlanner.ts   |   84.13 |    76.59 |      90 |   84.13 | ...38,144,162-173 
  hookRegistry.ts  |   88.83 |    86.36 |     100 |   88.83 | ...21,326,330,334 
  hookRunner.ts    |   53.63 |    72.22 |   61.11 |   53.63 | ...23-724,733-734 
  hookSystem.ts    |   75.47 |      100 |   56.41 |   75.47 | ...75-576,582-583 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |    96.5 |     91.8 |     100 |    96.5 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  trustedHooks.ts  |       0 |        0 |       0 |       0 | 1-124             
  types.ts         |   90.15 |    91.02 |   85.18 |   90.15 | ...91-392,452-456 
  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           |   33.39 |    43.56 |   44.91 |   33.39 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |    4.29 |        0 |       0 |    4.29 | ...20-371,377-394 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   10.47 |       75 |      25 |   10.47 | ...56-675,681-711 
  ...eLspClient.ts |   17.89 |      100 |       0 |   17.89 | ...37-244,254-258 
  ...LspService.ts |   45.87 |    62.13 |   66.66 |   45.87 | ...1282,1299-1309 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   78.69 |    75.68 |   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.77 |    54.45 |     100 |   73.77 | ...80-887,894-896 
  ...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.48 |    86.66 |   86.36 |   79.48 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   82.75 |    82.35 |   92.85 |   82.75 | ...62-172,180-181 
  ...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/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   88.03 |    83.91 |   86.95 |   88.03 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   88.67 |     90.9 |     100 |   88.67 | 112,118,121-130   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |    97.5 |    86.44 |     100 |    97.5 | ...95,301,316-317 
  modelRegistry.ts |     100 |    98.21 |     100 |     100 | 182               
  modelsConfig.ts  |      83 |    81.37 |   81.57 |      83 | ...1168,1197-1198 
  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   |   70.58 |       88 |    48.2 |   70.58 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   80.82 |    81.72 |   79.16 |   80.82 | ...56-757,764-773 
  rule-parser.ts   |   95.81 |    94.08 |     100 |   95.81 | ...36-837,981-983 
  ...-semantics.ts |   58.28 |    85.27 |    30.2 |   58.28 | ...1604-1614,1643 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/qwen          |    85.9 |    79.74 |   97.18 |    85.9 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   84.73 |    75.37 |   93.33 |   84.73 | ...8,977-993,1023 
  ...kenManager.ts |   83.79 |    76.22 |     100 |   83.79 | ...63-768,789-794 
 src/services      |   82.81 |    80.96 |   87.16 |   82.81 |                   
  ...ionService.ts |   97.95 |    94.04 |     100 |   97.95 | 255,257-261       
  ...ingService.ts |   68.39 |    48.38 |   85.71 |   68.39 | ...25-437,453-454 
  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 
  ...temService.ts |   89.76 |     85.1 |   88.88 |   89.76 | ...89,191,266-273 
  gitService.ts    |   68.08 |     92.3 |   55.55 |   68.08 | ...10-120,123-127 
  ...reeService.ts |   68.75 |    67.04 |   86.95 |   68.75 | ...88-789,805,821 
  ...ionService.ts |   98.98 |     98.3 |     100 |   98.98 | 260-261           
  ...ionService.ts |   83.84 |    73.33 |   94.44 |   83.84 | ...53-674,706-707 
  ...ionService.ts |   83.46 |    78.53 |   83.33 |   83.46 | ...1017,1023-1028 
 ...icrocompaction |   98.63 |    86.44 |     100 |   98.63 |                   
  microcompact.ts  |   98.63 |    86.44 |     100 |   98.63 | 139,143           
 src/skills        |   83.87 |    79.89 |   90.32 |   83.87 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  skill-load.ts    |    90.9 |    77.77 |     100 |    90.9 | ...32,152,164-166 
  skill-manager.ts |   81.33 |    78.83 |   88.46 |   81.33 | ...52-860,867-871 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/subagents     |   82.46 |     80.6 |    90.9 |   82.46 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   75.85 |    72.02 |   86.66 |   75.85 | ...1082,1107-1108 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.43 |    95.18 |     100 |   92.43 | 51-56,69-74,78-83 
 src/telemetry     |   68.01 |    84.36 |    72.3 |   68.01 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...-exporters.ts |   36.76 |      100 |   22.22 |   36.76 | ...84,87-88,91-92 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   53.23 |    62.68 |   54.76 |   53.23 | ...1130,1133-1157 
  metrics.ts       |   78.17 |    82.95 |   78.84 |   78.17 | ...09-846,849-878 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   85.13 |    56.25 |     100 |   85.13 | ...78,184-185,191 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |   77.31 |    94.17 |   81.81 |   77.31 | ...1108,1111-1140 
  uiTelemetry.ts   |   91.87 |    96.15 |   78.57 |   91.87 | ...67-168,174-181 
 ...ry/qwen-logger |   68.18 |    80.21 |   64.91 |   68.18 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.18 |       80 |   64.28 |   68.18 | ...1040,1078-1079 
 src/test-utils    |   93.07 |    95.65 |   73.52 |   93.07 |                   
  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.02 |    96.87 |   68.96 |   91.02 | ...32,196-197,210 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   74.12 |    79.44 |    80.1 |   74.12 |                   
  agent.ts         |   79.22 |    84.29 |   90.47 |   79.22 | ...11-915,921-925 
  ...erQuestion.ts |   87.89 |     73.8 |    90.9 |   87.89 | ...44-345,349-350 
  cron-create.ts   |   97.61 |    88.88 |   83.33 |   97.61 | 30-31             
  cron-delete.ts   |   96.55 |      100 |   83.33 |   96.55 | 26-27             
  cron-list.ts     |   96.22 |      100 |   83.33 |   96.22 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   81.37 |    85.05 |   73.33 |   81.37 | ...03-504,587-637 
  exitPlanMode.ts  |   84.61 |    85.71 |     100 |   84.61 | ...60-163,177-189 
  glob.ts          |   91.57 |    88.33 |   84.61 |   91.57 | ...20,163,293,296 
  grep.ts          |   71.64 |    87.34 |   72.22 |   71.64 | ...84,524,532-539 
  ls.ts            |   96.72 |    90.14 |     100 |   96.72 | 169-174,205,209   
  lsp.ts           |   72.58 |    60.29 |   90.32 |   72.58 | ...1202,1204-1205 
  ...nt-manager.ts |   47.47 |       60 |   44.44 |   47.47 | ...73-491,494-531 
  mcp-client.ts    |   29.52 |    71.05 |   46.87 |   29.52 | ...1427,1431-1434 
  mcp-tool.ts      |   90.92 |    88.88 |   96.42 |   90.92 | ...89-590,640-641 
  memoryTool.ts    |   74.48 |    83.05 |   90.47 |   74.48 | ...48-356,458-542 
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  read-file.ts     |   96.47 |     87.8 |   88.88 |   96.47 | 68,70,72-73,79-80 
  ripGrep.ts       |   96.46 |     91.3 |     100 |   96.46 | ...93,296,374-375 
  ...-transport.ts |    6.34 |        0 |       0 |    6.34 | 47-145            
  shell.ts         |   86.14 |    78.12 |    92.3 |   86.14 | ...59-463,657-658 
  skill.ts         |   84.68 |       85 |   84.61 |   84.68 | ...59,263,286-308 
  todoWrite.ts     |   85.42 |    84.09 |   84.61 |   85.42 | ...05-410,432-433 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   62.79 |    65.38 |   59.37 |   62.79 | ...34-543,550-566 
  tools.ts         |   84.18 |    89.58 |   82.35 |   84.18 | ...25-426,442-448 
  web-fetch.ts     |   86.09 |    60.86 |   91.66 |   86.09 | ...53-254,256-257 
  write-file.ts    |    81.6 |    78.18 |      75 |    81.6 | ...05-408,420-455 
 ...ols/web-search |   72.42 |    76.59 |   76.47 |   72.42 |                   
  base-provider.ts |    40.9 |    33.33 |     100 |    40.9 | 40-43,48-56       
  index.ts         |   76.85 |    84.61 |   84.61 |   76.85 | ...62-166,272-282 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      60 |       50 |      50 |      60 | 35-42             
 ...arch/providers |   46.73 |    61.11 |   72.72 |   46.73 |                   
  ...e-provider.ts |       8 |        0 |       0 |       8 | 68-83,89-199      
  ...e-provider.ts |      82 |    55.55 |     100 |      82 | 57-58,61-62,72-76 
  ...y-provider.ts |   89.79 |       75 |     100 |   89.79 | 62-66             
 src/utils         |   86.65 |    87.24 |    90.4 |   86.65 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   76.08 |    44.44 |     100 |   76.08 | 61-70,72          
  browser.ts       |    7.69 |      100 |       0 |    7.69 | 17-56             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  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   |   96.12 |    93.75 |   93.75 |   96.12 | 164-168           
  editHelper.ts    |   92.67 |    82.14 |     100 |   92.67 | ...52-454,463-464 
  editor.ts        |   96.98 |    93.87 |     100 |   96.98 | ...93-194,196-197 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |     100 |       95 |     100 |     100 | 83                
  errorParsing.ts  |   97.05 |       95 |     100 |   97.05 | 39-40             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.92 |    80.39 |   53.33 |   70.92 | ...03-219,223-229 
  fetch.ts         |   71.97 |    71.42 |   71.42 |   71.97 | ...38,144,157,182 
  fileUtils.ts     |   91.68 |    83.85 |   94.73 |   91.68 | ...28-734,748-754 
  formatters.ts    |   54.54 |       50 |     100 |   54.54 | 12-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             
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   36.66 |    76.92 |      50 |   36.66 | ...4,88-89,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   |    8.87 |      100 |       0 |    8.87 | ...51-184,190-196 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...yDiscovery.ts |   82.97 |    76.59 |     100 |   82.97 | ...75,292-293,296 
  ...tProcessor.ts |   93.63 |       90 |     100 |   93.63 | ...96-302,384-385 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  ...kerChecker.ts |   84.04 |    78.94 |     100 |   84.04 | 68-69,79-84,92-98 
  openaiLogger.ts  |   86.27 |    82.14 |     100 |   86.27 | ...05-107,130-135 
  partUtils.ts     |     100 |      100 |     100 |     100 |                   
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   95.67 |    94.52 |     100 |   95.67 | ...,70-71,103-104 
  ...ectSummary.ts |   91.66 |       70 |     100 |   91.66 | ...37,139,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     |   91.48 |    94.11 |     100 |   91.48 | 80,93-95          
  readManyFiles.ts |   85.95 |    85.71 |     100 |   85.95 | ...80-182,198-209 
  retry.ts         |   70.14 |    76.92 |     100 |   70.14 | ...89,207,214-215 
  ripgrepUtils.ts  |   46.53 |    83.33 |   66.66 |   46.53 | ...32-233,245-322 
  ...tchOptions.ts |   55.88 |       50 |      75 |   55.88 | ...29-130,151-152 
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    87.87 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   93.43 |    76.66 |     100 |   93.43 | ...46,155-158,212 
  ...r-launcher.ts |   76.52 |     87.5 |   66.66 |   76.52 | ...33,135,153-191 
  shell-utils.ts   |    83.6 |    90.63 |     100 |    83.6 | ...1040,1047-1051 
  ...lAstParser.ts |   95.58 |    85.71 |     100 |   95.58 | ...1059-1061,1071 
  ...nlyChecker.ts |   95.75 |    92.47 |     100 |   95.75 | ...00-301,313-314 
  ...tGenerator.ts |     100 |     90.9 |     100 |     100 | 129               
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  ...Serializer.ts |   99.07 |    91.22 |     100 |   99.07 | 90,156-158        
  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             
  ...aceContext.ts |   96.22 |       92 |   93.33 |   96.22 | ...15-116,133,160 
  yaml-parser.ts   |      92 |    83.67 |     100 |      92 | 49-53,65-69       
 ...ils/filesearch |   96.34 |    91.66 |     100 |   96.34 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   96.87 |    94.44 |     100 |   96.87 | 83-84             
  fileSearch.ts    |   93.29 |    86.76 |     100 |   93.29 | ...40-241,243-244 
  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.

@tanzhenxin

tanzhenxin commented Apr 16, 2026

Copy link
Copy Markdown
Collaborator Author

E2E Verification Report

Setup

Test project with a skill containing 5,000 packages (10,000 files, 5,001 directories) under node_modules — comparable to the electron-scale tree in the issue:

.qwen/skills/heavy-skill/
├── SKILL.md
└── node_modules/
    ├── pkg_1/   (package.json + index.js)
    ├── pkg_2/
    └── ... (5,000 directories, 10,000 files)

Both runs used interactive mode via tmux (--approval-mode yolo), waited for the TUI prompt, then sent !pwd as described in the issue's repro steps.

Results

Machine: macOS Sequoia (Darwin 25.3.0), kern.maxfilesperproc = 138,240

Before fix (global qwen v0.14.4, hard RLIMIT_NOFILE=4096)

Metric Value
!pwd output posix_openpt failed: Too many open files / (Command produced no output)
Total open FDs 4,099 (at hard cap of 4,096)
FDs in node_modules 4,077

After fix (local build from fix/3289-skill-watcher-fd-exhaustion)

Metric Value
!pwd output /private/tmp/qwen-3289-fdtest-after (success)
Total open FDs 25
FDs in node_modules 0 (from skill watching)
kqueue entries 4

Linux (inotify watch count only)

Metric Before (global qwen 0.14.5) After (local build with fix)
Inotify watches 15,022 22
!pwd result ✓ (Linux doesn't exhaust FDs)

99.85% reduction in filesystem watches (15,022 → 22).

Reproduction notes

Node.js raises its soft FD limit to kern.maxfilesperproc at startup, ignoring ulimit -n. On modern macOS (Ventura+), kern.maxfilesperproc is ~138K, so ulimit -n 4096 alone cannot constrain the process. To reproduce the symptom, a Python setrlimit wrapper was used to enforce a hard RLIMIT_NOFILE=4096 before exec'ing Node:

import resource, os, sys
limit = int(sys.argv[1])
resource.setrlimit(resource.RLIMIT_NOFILE, (limit, limit))
os.execvp(sys.argv[2], sys.argv[2:])

The original reporter likely ran an older macOS (Catalina ~10K, Big Sur/Monterey ~24K kern.maxfilesperproc), where 5,000 packages generating ~10K FDs would exceed the limit without any wrapper.

Failure mechanism

When FDs are exhausted, node-pty.spawn() fails at posix_openpt() with EMFILE — the PTY cannot be allocated. No onData/onExit callbacks ever fire, and the shell command returns exit code 1 with no output.

The fix (depth: 2 + ignored filter) keeps chokidar within the skill layout boundary (<skill-name>/SKILL.md), never entering node_modules or any other deep subtree.

The chokidar file watcher in SkillManager.updateWatchersFromCache() had
no depth limit or ignored paths. When skill directories contained heavy
subtrees like node_modules, chokidar recursively watched every file,
exhausting file descriptors and breaking child-process I/O (node-pty
onData/onExit callbacks silently stop firing).

Fix: set depth to 2 (skills use a fixed <skill-name>/SKILL.md layout)
and add an ignored function that filters out special file types (sockets,
FIFOs, devices) and .git directories.

Made-with: Cursor
The watcherIgnored test used hardcoded forward-slash paths which don't
split correctly on Windows where path.sep is backslash.

Made-with: Cursor

@LaZzyMan LaZzyMan left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM!

@tanzhenxin tanzhenxin merged commit 0f8e8db into main Apr 17, 2026
14 checks passed
mabry1985 added a commit to protoLabsAI/protoCLI that referenced this pull request Apr 26, 2026
…wenLM#3320) (#109)

Cherry-picked from QwenLM/qwen-code:

- QwenLM#3499 fix(core): use empty string instead of null for reasoning-only
  assistant content. Some OpenAI-compatible providers (e.g. Ollama
  qwen3.5:9b) reject content: null with HTTP 400 when reasoning_content is
  also present. Tool-call-only messages keep null per OpenAI spec.

- QwenLM#3630 fix(telemetry): switch FileExporter.serialize from JSON.stringify
  to safeJsonStringify. OTel ReadableSpans hold a BatchSpanProcessor
  back-reference that forms a cycle and crashed --telemetry-outfile users.

- QwenLM#3320 fix(core): cap chokidar depth at 2 in SkillManager and skip
  .git / special file types. Prevents FD exhaustion when a skill dir
  contains node_modules etc., which silently broke node-pty I/O.

Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mabry1985 added a commit to protoLabsAI/protoCLI that referenced this pull request Apr 26, 2026
* fix: backport upstream trivial bug fixes (QwenLM#3499, QwenLM#3630, QwenLM#3320)

Cherry-picked from QwenLM/qwen-code:

- QwenLM#3499 fix(core): use empty string instead of null for reasoning-only
  assistant content. Some OpenAI-compatible providers (e.g. Ollama
  qwen3.5:9b) reject content: null with HTTP 400 when reasoning_content is
  also present. Tool-call-only messages keep null per OpenAI spec.

- QwenLM#3630 fix(telemetry): switch FileExporter.serialize from JSON.stringify
  to safeJsonStringify. OTel ReadableSpans hold a BatchSpanProcessor
  back-reference that forms a cycle and crashed --telemetry-outfile users.

- QwenLM#3320 fix(core): cap chokidar depth at 2 in SkillManager and skip
  .git / special file types. Prevents FD exhaustion when a skill dir
  contains node_modules etc., which silently broke node-pty I/O.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): scope StreamingToolCallParser per-stream (QwenLM#3525)

Backports upstream PR QwenLM#3525 + extends the per-stream context to also
cover our fork's <think>-tag parser state.

Bug: every caller of Config.getContentGenerator() — foreground turns,
fork subagents, run_in_background subagents, ACP concurrent Agent calls
(after QwenLM#3463) — shared a single OpenAIContentConverter, which held the
StreamingToolCallParser as an instance field. Concurrent streams
corrupted each other's tool-call buffers, surfacing as NO_RESPONSE_TEXT.

Fix:
- New ConverterStreamContext interface holds toolCallParser, thinkBuffer,
  inThinkTag — one per stream.
- createStreamContext() factory replaces resetStreamingToolCalls().
- convertOpenAIChunkToGemini(chunk, ctx) and processThinkChunk(chunk, ctx)
  thread the context through every parser/think-buffer access.
- ContentGenerationPipeline.processStreamWithLogging creates one context
  at stream entry. The error path no longer manually resets — the
  context is GC'd when the generator unwinds.

Our protoInternal recovery-note logic is preserved on the new shape.

Note: upstream's follow-up QwenLM#3550 (full stateless converter refactor) is
deferred — it's hygiene without a functional bug; QwenLM#3525 alone fixes
the concurrency race.

Tests:
- New createStreamContext describe replaces resetStreamingToolCalls suite
- Streaming <think> tests use a per-test context
- pipeline.test.ts mock updated to match the new API
- pipeline.concurrent.test.ts (from upstream commit 38edd9d)
  drives two real concurrent streams and asserts neither corrupts the
  other's tool-call output (positive control: pre-fix, this test fails
  with exactly the user-reported bug shape).

Refs upstream QwenLM#3516, QwenLM#3525.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mabry1985 added a commit to protoLabsAI/protoCLI that referenced this pull request Apr 26, 2026
…enLM#3590, QwenLM#3505, QwenLM#3467) (#113)

* fix: backport upstream trivial bug fixes (QwenLM#3499, QwenLM#3630, QwenLM#3320)

Cherry-picked from QwenLM/qwen-code:

- QwenLM#3499 fix(core): use empty string instead of null for reasoning-only
  assistant content. Some OpenAI-compatible providers (e.g. Ollama
  qwen3.5:9b) reject content: null with HTTP 400 when reasoning_content is
  also present. Tool-call-only messages keep null per OpenAI spec.

- QwenLM#3630 fix(telemetry): switch FileExporter.serialize from JSON.stringify
  to safeJsonStringify. OTel ReadableSpans hold a BatchSpanProcessor
  back-reference that forms a cycle and crashed --telemetry-outfile users.

- QwenLM#3320 fix(core): cap chokidar depth at 2 in SkillManager and skip
  .git / special file types. Prevents FD exhaustion when a skill dir
  contains node_modules etc., which silently broke node-pty I/O.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): scope StreamingToolCallParser per-stream (QwenLM#3525)

Backports upstream PR QwenLM#3525 + extends the per-stream context to also
cover our fork's <think>-tag parser state.

Bug: every caller of Config.getContentGenerator() — foreground turns,
fork subagents, run_in_background subagents, ACP concurrent Agent calls
(after QwenLM#3463) — shared a single OpenAIContentConverter, which held the
StreamingToolCallParser as an instance field. Concurrent streams
corrupted each other's tool-call buffers, surfacing as NO_RESPONSE_TEXT.

Fix:
- New ConverterStreamContext interface holds toolCallParser, thinkBuffer,
  inThinkTag — one per stream.
- createStreamContext() factory replaces resetStreamingToolCalls().
- convertOpenAIChunkToGemini(chunk, ctx) and processThinkChunk(chunk, ctx)
  thread the context through every parser/think-buffer access.
- ContentGenerationPipeline.processStreamWithLogging creates one context
  at stream entry. The error path no longer manually resets — the
  context is GC'd when the generator unwinds.

Our protoInternal recovery-note logic is preserved on the new shape.

Note: upstream's follow-up QwenLM#3550 (full stateless converter refactor) is
deferred — it's hygiene without a functional bug; QwenLM#3525 alone fixes
the concurrency race.

Tests:
- New createStreamContext describe replaces resetStreamingToolCalls suite
- Streaming <think> tests use a per-test context
- pipeline.test.ts mock updated to match the new API
- pipeline.concurrent.test.ts (from upstream commit 38edd9d)
  drives two real concurrent streams and asserts neither corrupts the
  other's tool-call output (positive control: pre-fix, this test fails
  with exactly the user-reported bug shape).

Refs upstream QwenLM#3516, QwenLM#3525.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): strip thinking blocks from history on model switch (QwenLM#3304)

When switching models mid-session, reasoning_content fields from
thinking-capable models leaked into API requests sent to the new
provider, causing 422 errors on strict OpenAI-compatible endpoints.

Call stripThoughtsFromHistory() in handleModelChange() so thought parts
are removed before the next request is built for the new model.

* fix(core): reject truncated subagent write_file calls (QwenLM#3505)

Backport of upstream QwenLM#3505. Propagates MAX_TOKENS truncation from
subagent responses into tool requests and rejects truncated edit calls
before schema validation can surface misleading missing-parameter errors.

Adapted to our fork's coreToolScheduler.ts which already had the
truncation rejection block — kept both, dropped the unused
clearRetryCountsForTool() call (we don't have that retry-counter
machinery yet).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): prevent malformed permission rules from becoming tool-wide catch-alls (QwenLM#3467)

Backport of upstream QwenLM#3467. A permission rule with unbalanced parens
was silently parsed with specifier: undefined, causing matchesRule to
treat it as a catch-all. For deny rules this blocked all commands; for
allow rules a typo could silently auto-approve everything.

- Adds an invalid flag to PermissionRule
- parseRule marks unbalanced-paren rules as invalid
- matchesRule short-circuits invalid rules to never match
- parseRules / addSession*Rule / addPersistentRule warn on malformed input
- listRules filters invalid rules from /permissions UI

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): preserve reasoning_content during session resume and active sessions (GH#3579)

* test(config): drop fork-incompatible QwenLM#3304 strip-thoughts test

The test from upstream QwenLM#3304 backport assumed an in-place qwen-oauth
model switch path that our fork doesn't have; the source-side fix in
config.ts (stripThoughtsFromHistory call in handleModelChange) is
preserved. Coverage will be re-added when the fork's switch flow
stabilizes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: tanzhenxin <tanzhenxing1987@gmail.com>
Co-authored-by: Yuchen Fu <fuyuchen0904@163.com>
mabry1985 added a commit to protoLabsAI/protoCLI that referenced this pull request Apr 26, 2026
…wenLM#3574) (#115)

* fix: backport upstream trivial bug fixes (QwenLM#3499, QwenLM#3630, QwenLM#3320)

Cherry-picked from QwenLM/qwen-code:

- QwenLM#3499 fix(core): use empty string instead of null for reasoning-only
  assistant content. Some OpenAI-compatible providers (e.g. Ollama
  qwen3.5:9b) reject content: null with HTTP 400 when reasoning_content is
  also present. Tool-call-only messages keep null per OpenAI spec.

- QwenLM#3630 fix(telemetry): switch FileExporter.serialize from JSON.stringify
  to safeJsonStringify. OTel ReadableSpans hold a BatchSpanProcessor
  back-reference that forms a cycle and crashed --telemetry-outfile users.

- QwenLM#3320 fix(core): cap chokidar depth at 2 in SkillManager and skip
  .git / special file types. Prevents FD exhaustion when a skill dir
  contains node_modules etc., which silently broke node-pty I/O.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): scope StreamingToolCallParser per-stream (QwenLM#3525)

Backports upstream PR QwenLM#3525 + extends the per-stream context to also
cover our fork's <think>-tag parser state.

Bug: every caller of Config.getContentGenerator() — foreground turns,
fork subagents, run_in_background subagents, ACP concurrent Agent calls
(after QwenLM#3463) — shared a single OpenAIContentConverter, which held the
StreamingToolCallParser as an instance field. Concurrent streams
corrupted each other's tool-call buffers, surfacing as NO_RESPONSE_TEXT.

Fix:
- New ConverterStreamContext interface holds toolCallParser, thinkBuffer,
  inThinkTag — one per stream.
- createStreamContext() factory replaces resetStreamingToolCalls().
- convertOpenAIChunkToGemini(chunk, ctx) and processThinkChunk(chunk, ctx)
  thread the context through every parser/think-buffer access.
- ContentGenerationPipeline.processStreamWithLogging creates one context
  at stream entry. The error path no longer manually resets — the
  context is GC'd when the generator unwinds.

Our protoInternal recovery-note logic is preserved on the new shape.

Note: upstream's follow-up QwenLM#3550 (full stateless converter refactor) is
deferred — it's hygiene without a functional bug; QwenLM#3525 alone fixes
the concurrency race.

Tests:
- New createStreamContext describe replaces resetStreamingToolCalls suite
- Streaming <think> tests use a per-test context
- pipeline.test.ts mock updated to match the new API
- pipeline.concurrent.test.ts (from upstream commit 38edd9d)
  drives two real concurrent streams and asserts neither corrupts the
  other's tool-call output (positive control: pre-fix, this test fails
  with exactly the user-reported bug shape).

Refs upstream QwenLM#3516, QwenLM#3525.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): strip thinking blocks from history on model switch (QwenLM#3304)

When switching models mid-session, reasoning_content fields from
thinking-capable models leaked into API requests sent to the new
provider, causing 422 errors on strict OpenAI-compatible endpoints.

Call stripThoughtsFromHistory() in handleModelChange() so thought parts
are removed before the next request is built for the new model.

* fix(core): reject truncated subagent write_file calls (QwenLM#3505)

Backport of upstream QwenLM#3505. Propagates MAX_TOKENS truncation from
subagent responses into tool requests and rejects truncated edit calls
before schema validation can surface misleading missing-parameter errors.

Adapted to our fork's coreToolScheduler.ts which already had the
truncation rejection block — kept both, dropped the unused
clearRetryCountsForTool() call (we don't have that retry-counter
machinery yet).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): prevent malformed permission rules from becoming tool-wide catch-alls (QwenLM#3467)

Backport of upstream QwenLM#3467. A permission rule with unbalanced parens
was silently parsed with specifier: undefined, causing matchesRule to
treat it as a catch-all. For deny rules this blocked all commands; for
allow rules a typo could silently auto-approve everything.

- Adds an invalid flag to PermissionRule
- parseRule marks unbalanced-paren rules as invalid
- matchesRule short-circuits invalid rules to never match
- parseRules / addSession*Rule / addPersistentRule warn on malformed input
- listRules filters invalid rules from /permissions UI

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): preserve reasoning_content during session resume and active sessions (GH#3579)

* test(config): drop fork-incompatible QwenLM#3304 strip-thoughts test

The test from upstream QwenLM#3304 backport assumed an in-place qwen-oauth
model switch path that our fork doesn't have; the source-side fix in
config.ts (stripThoughtsFromHistory call in handleModelChange) is
preserved. Coverage will be re-added when the fork's switch flow
stabilizes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(acp): run Agent tool calls concurrently + graceful degrade (QwenLM#3463)

Backport of upstream QwenLM#3463. When the model returns multiple Agent tool
calls in a single turn, ACP Session was executing them sequentially in
a for-loop, multiplying latency by sub-agent count.

- Add private runToolCalls() helper that mirrors coreToolScheduler's
  partition logic: consecutive Agent calls form a parallel batch (safe
  because sub-agents have no shared mutable state); other tools form
  sequential batches.
- Replace 2 for-loops in Session.ts with runToolCalls() calls.
- Switch the AgentTool eventEmitter guard from key-presence check to
  truthy check (commit 651979c) — the key-presence check passed for
  { eventEmitter: undefined } and crashed inside SubAgentTracker.setup.

Note: upstream replaced 3 for-loops; our fork only had 2 in those code
paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(acp): support SSE and HTTP MCP servers in ACP mode

In ACP mode, the Mcp server list sent by the IDE client can include
SSE (type: "sse") and HTTP (type: "http") transports, but the previous
implementation only handled stdio servers via toStdioServer(). Non-stdio
servers were silently skipped (continue), so any SSE/HTTP-configured
MCP server would never be registered.

Changes:
- Add toSseServer() helper: detects type=="sse" servers and maps them
  to MCPServerConfig(url=..., headers=...)
- Add toHttpServer() helper: detects type=="http" servers and maps them
  to MCPServerConfig(httpUrl=..., headers=...)
- Refactor newSessionConfig() loop to handle all three transport types
- Declare mcpCapabilities: { sse: true, http: true } in agentCapabilities
  so IDE clients know this agent supports these transports without needing
  a transparent proxy
- Export the three helper functions for unit testing

Tests:
- Unit tests for toStdioServer / toSseServer / toHttpServer helpers
  (type discrimination, mutual exclusion)
- Integration-style tests for QwenAgent.initialize() mcpCapabilities
- Integration-style tests for newSession() with SSE/HTTP MCP servers,
  verifying MCPServerConfig is constructed with the correct arguments
  (url vs httpUrl, headers passthrough, empty-headers → undefined)

Fixes QwenLM#3472

---------

Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: tanzhenxin <tanzhenxing1987@gmail.com>
Co-authored-by: Yuchen Fu <fuyuchen0904@163.com>
Co-authored-by: LaZzyMan <zeusdream7@gmail.com>
mabry1985 added a commit to protoLabsAI/protoCLI that referenced this pull request Apr 26, 2026
* fix: backport upstream trivial bug fixes (QwenLM#3499, QwenLM#3630, QwenLM#3320)

Cherry-picked from QwenLM/qwen-code:

- QwenLM#3499 fix(core): use empty string instead of null for reasoning-only
  assistant content. Some OpenAI-compatible providers (e.g. Ollama
  qwen3.5:9b) reject content: null with HTTP 400 when reasoning_content is
  also present. Tool-call-only messages keep null per OpenAI spec.

- QwenLM#3630 fix(telemetry): switch FileExporter.serialize from JSON.stringify
  to safeJsonStringify. OTel ReadableSpans hold a BatchSpanProcessor
  back-reference that forms a cycle and crashed --telemetry-outfile users.

- QwenLM#3320 fix(core): cap chokidar depth at 2 in SkillManager and skip
  .git / special file types. Prevents FD exhaustion when a skill dir
  contains node_modules etc., which silently broke node-pty I/O.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): scope StreamingToolCallParser per-stream (QwenLM#3525)

Backports upstream PR QwenLM#3525 + extends the per-stream context to also
cover our fork's <think>-tag parser state.

Bug: every caller of Config.getContentGenerator() — foreground turns,
fork subagents, run_in_background subagents, ACP concurrent Agent calls
(after QwenLM#3463) — shared a single OpenAIContentConverter, which held the
StreamingToolCallParser as an instance field. Concurrent streams
corrupted each other's tool-call buffers, surfacing as NO_RESPONSE_TEXT.

Fix:
- New ConverterStreamContext interface holds toolCallParser, thinkBuffer,
  inThinkTag — one per stream.
- createStreamContext() factory replaces resetStreamingToolCalls().
- convertOpenAIChunkToGemini(chunk, ctx) and processThinkChunk(chunk, ctx)
  thread the context through every parser/think-buffer access.
- ContentGenerationPipeline.processStreamWithLogging creates one context
  at stream entry. The error path no longer manually resets — the
  context is GC'd when the generator unwinds.

Our protoInternal recovery-note logic is preserved on the new shape.

Note: upstream's follow-up QwenLM#3550 (full stateless converter refactor) is
deferred — it's hygiene without a functional bug; QwenLM#3525 alone fixes
the concurrency race.

Tests:
- New createStreamContext describe replaces resetStreamingToolCalls suite
- Streaming <think> tests use a per-test context
- pipeline.test.ts mock updated to match the new API
- pipeline.concurrent.test.ts (from upstream commit 38edd9d)
  drives two real concurrent streams and asserts neither corrupts the
  other's tool-call output (positive control: pre-fix, this test fails
  with exactly the user-reported bug shape).

Refs upstream QwenLM#3516, QwenLM#3525.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): strip thinking blocks from history on model switch (QwenLM#3304)

When switching models mid-session, reasoning_content fields from
thinking-capable models leaked into API requests sent to the new
provider, causing 422 errors on strict OpenAI-compatible endpoints.

Call stripThoughtsFromHistory() in handleModelChange() so thought parts
are removed before the next request is built for the new model.

* fix(core): reject truncated subagent write_file calls (QwenLM#3505)

Backport of upstream QwenLM#3505. Propagates MAX_TOKENS truncation from
subagent responses into tool requests and rejects truncated edit calls
before schema validation can surface misleading missing-parameter errors.

Adapted to our fork's coreToolScheduler.ts which already had the
truncation rejection block — kept both, dropped the unused
clearRetryCountsForTool() call (we don't have that retry-counter
machinery yet).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): prevent malformed permission rules from becoming tool-wide catch-alls (QwenLM#3467)

Backport of upstream QwenLM#3467. A permission rule with unbalanced parens
was silently parsed with specifier: undefined, causing matchesRule to
treat it as a catch-all. For deny rules this blocked all commands; for
allow rules a typo could silently auto-approve everything.

- Adds an invalid flag to PermissionRule
- parseRule marks unbalanced-paren rules as invalid
- matchesRule short-circuits invalid rules to never match
- parseRules / addSession*Rule / addPersistentRule warn on malformed input
- listRules filters invalid rules from /permissions UI

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(core): preserve reasoning_content during session resume and active sessions (GH#3579)

* test(config): drop fork-incompatible QwenLM#3304 strip-thoughts test

The test from upstream QwenLM#3304 backport assumed an in-place qwen-oauth
model switch path that our fork doesn't have; the source-side fix in
config.ts (stripThoughtsFromHistory call in handleModelChange) is
preserved. Coverage will be re-added when the fork's switch flow
stabilizes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(acp): run Agent tool calls concurrently + graceful degrade (QwenLM#3463)

Backport of upstream QwenLM#3463. When the model returns multiple Agent tool
calls in a single turn, ACP Session was executing them sequentially in
a for-loop, multiplying latency by sub-agent count.

- Add private runToolCalls() helper that mirrors coreToolScheduler's
  partition logic: consecutive Agent calls form a parallel batch (safe
  because sub-agents have no shared mutable state); other tools form
  sequential batches.
- Replace 2 for-loops in Session.ts with runToolCalls() calls.
- Switch the AgentTool eventEmitter guard from key-presence check to
  truthy check (commit 651979c) — the key-presence check passed for
  { eventEmitter: undefined } and crashed inside SubAgentTracker.setup.

Note: upstream replaced 3 for-loops; our fork only had 2 in those code
paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(acp): support SSE and HTTP MCP servers in ACP mode

In ACP mode, the Mcp server list sent by the IDE client can include
SSE (type: "sse") and HTTP (type: "http") transports, but the previous
implementation only handled stdio servers via toStdioServer(). Non-stdio
servers were silently skipped (continue), so any SSE/HTTP-configured
MCP server would never be registered.

Changes:
- Add toSseServer() helper: detects type=="sse" servers and maps them
  to MCPServerConfig(url=..., headers=...)
- Add toHttpServer() helper: detects type=="http" servers and maps them
  to MCPServerConfig(httpUrl=..., headers=...)
- Refactor newSessionConfig() loop to handle all three transport types
- Declare mcpCapabilities: { sse: true, http: true } in agentCapabilities
  so IDE clients know this agent supports these transports without needing
  a transparent proxy
- Export the three helper functions for unit testing

Tests:
- Unit tests for toStdioServer / toSseServer / toHttpServer helpers
  (type discrimination, mutual exclusion)
- Integration-style tests for QwenAgent.initialize() mcpCapabilities
- Integration-style tests for newSession() with SSE/HTTP MCP servers,
  verifying MCPServerConfig is constructed with the correct arguments
  (url vs httpUrl, headers passthrough, empty-headers → undefined)

Fixes QwenLM#3472

* fix(openai): when samplingParams is set, pass it through verbatim

Previously pipeline.ts always hardcoded max_tokens as the output-token parameter name on the OpenAI-compatible path, falling back from samplingParams.max_tokens to request.config.maxOutputTokens to provider defaults. This broke GPT-5 / o-series on OpenAI and Azure OpenAI, which require max_completion_tokens and reject max_tokens with a 400 error.

Fix: when the user provides samplingParams explicitly, treat it as the complete source of truth for the wire shape and pass its keys through verbatim. No client-injected defaults, no request fallbacks, no hardcoded parameter names. The user describes what the provider wants; the client trusts them.

When samplingParams is absent, the historical default behavior (request fallback through temperature/top_p/.../max_tokens plus provider defaults) is preserved unchanged — existing users see no difference.

Concretely, users can now set any of:

  samplingParams: { max_tokens: 4096 }                # GPT-4 / Qwen / DeepSeek

  samplingParams: { max_completion_tokens: 4096 }    # GPT-5 / o-series

  samplingParams: { reasoning_effort: 'medium' }     # future knobs

without waiting for a qwen-code release that adds model-specific branches.

Signed-off-by: Gordon Lam (SH) <yeelam@microsoft.com>

---------

Signed-off-by: Gordon Lam (SH) <yeelam@microsoft.com>
Co-authored-by: Automaker <automaker@localhost>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: tanzhenxin <tanzhenxing1987@gmail.com>
Co-authored-by: Yuchen Fu <fuyuchen0904@163.com>
Co-authored-by: LaZzyMan <zeusdream7@gmail.com>
Co-authored-by: Gordon Lam (SH) <yeelam@microsoft.com>
@tanzhenxin tanzhenxin linked an issue Apr 30, 2026 that may be closed by this pull request
xaelistic pushed a commit to xaelistic/qwen-code that referenced this pull request Jun 7, 2026
…#3320)

* fix(core): limit skill watcher depth to prevent FD exhaustion (QwenLM#3289)

The chokidar file watcher in SkillManager.updateWatchersFromCache() had
no depth limit or ignored paths. When skill directories contained heavy
subtrees like node_modules, chokidar recursively watched every file,
exhausting file descriptors and breaking child-process I/O (node-pty
onData/onExit callbacks silently stop firing).

Fix: set depth to 2 (skills use a fixed <skill-name>/SKILL.md layout)
and add an ignored function that filters out special file types (sockets,
FIFOs, devices) and .git directories.

Made-with: Cursor

* fix(core): use path.join in watcher test for Windows compat

The watcherIgnored test used hardcoded forward-slash paths which don't
split correctly on Windows where path.sep is backslash.

Made-with: Cursor
@tanzhenxin tanzhenxin deleted the fix/3289-skill-watcher-fd-exhaustion branch June 13, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/bug Something isn't working as expected

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Shell commands silently fail (exit code 1, no output) when skills contain node_modules mac os 无法执行shell命令

2 participants