Skip to content

chore: sync upstream QwenLM/qwen-code (19 commits)#49

Merged
TaimoorSiddiquiOfficial merged 24 commits into
mainfrom
merge/upstream-qwen-sync
Jun 2, 2026
Merged

chore: sync upstream QwenLM/qwen-code (19 commits)#49
TaimoorSiddiquiOfficial merged 24 commits into
mainfrom
merge/upstream-qwen-sync

Conversation

@TaimoorSiddiquiOfficial

@TaimoorSiddiquiOfficial TaimoorSiddiquiOfficial commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Merges 19 upstream commits from QwenLM/qwen-code into HopCode's main branch, adapting all changes to HopCode branding and package names.

Upstream Changes Adopted

  • Virtual viewport: VirtualizedList/ScrollableList for large conversation histories
  • Hooks UI overhaul: Matcher-aware routing in HookDetailStep
  • New hook events: PostCompact, StopFailure; hookEventSupportsMatcher API
  • Shell context env vars: getShellContextEnvVars() injected into hook subprocess environment
  • Memory diagnostics improvements
  • AUTO mode improvements
  • Cleanup housekeeping: general.cleanupPeriodDays setting for ~/.hopcode/file-history/ retention
  • Status line: respectUserColors and hideContextIndicator options
  • /simplify bundled skill added
  • Qualitative.tsx: conditional hasFeatureSuggestions/hasUsagePatterns guards
  • NavToc: configurable sections via props

Branding Preserved

  • Package: @hoptrendy/hopcode-core
  • Env vars: HOPCODE_PROJECT_DIR, HOPCODE_EMIT_TOOL_USE_SUMMARIES
  • Paths: ~/.hopcode/, .hopcode/
  • Skill exclusion: .hopcode dirs excluded from bundled skill scanning

How to Verify

  1. Run npm run build and npm run typecheck
  2. Verify hooks UI shows matcher-based routing for hook events that support matchers
  3. Confirm /simplify skill appears in slash command list
  4. Verify general.cleanupPeriodDays appears in settings documentation

Summary by CodeRabbit

  • New Features

    • Added /simplify command for safe review/cleanup.
    • Virtual scrollable viewport mode for conversation history (optional).
    • Matcher-grouped view in hooks management for clearer event/matcher organization.
  • Enhancements

    • Keyboard shortcuts and mouse-wheel scrolling for history (including page/home/end).
    • Status line gains respectUserColors and hideContextIndicator options.
    • Added cleanupPeriodDays setting and background housekeeping to auto-prune session backups.
  • Documentation

    • Added detailed design, capture, and reproduce alignment guides.

LaZzyMan and others added 20 commits June 1, 2026 11:29
)

The Auto-memory / Auto-dream / Auto-skill rows initialized their state
from Config getters, which are frozen at startup and never reflect a
setValue() write. Each /memory reopen re-mounts the dialog and re-reads
that stale snapshot, so a just-flipped toggle appeared to revert. Read the
initial state from the live merged settings instead, matching the existing
write path (bareMode semantics preserved).

Also switch the test's `act` import to `react` — the previously used
@testing-library/react is declared in package.json but not installed, so
the suite could not run — and add a mount/unmount/remount regression test.
…rite files (QwenLM#4431)

* fix(core): preserve uid/gid in atomicWriteFile to avoid breaking shared-write files

atomicWriteFile uses write-to-tmp + rename for crash atomicity. POSIX
rename creates a new inode owned by the calling process's euid/egid, so
the rename silently strips the original uid/gid. On shared-write setups
(e.g. a group-writable file owned by another user in a shared workspace
where the current user has group-write access), every Write/Edit/
NotebookEdit through qwen-code would reset ownership to the running
user and effectively revoke write access for the original collaborators.

The fix:

1. If the target exists and is owned by a different uid/gid than the
   process's effective uid/gid (and we are not root), fall back to
   in-place writeFile. This truncates the existing inode in place,
   preserving uid/gid. The trade-off is loss of crash atomicity for
   this specific case — an acceptable trade for not silently breaking
   shared-write file ownership.

2. If running as root, atomic rename is still used, and ownership is
   restored via chown(uid, gid) after the rename. Root can chown back;
   non-root cannot, hence the in-place fallback for non-root.

3. Windows is unaffected (no POSIX ownership semantics).

Tests:

- New: in-place fallback on uid mismatch — verify content updates, mode
  preserved, and inode unchanged (the inode is the signal that the
  fallback path ran rather than rename).
- New: same scenario triggered via gid mismatch.
- New: positive case — ownership matches → atomic rename → inode changes.

Regression: a v0.16.0 user reported "every write turns a world-writable
file into one other users can no longer write." Bisected to QwenLM#4096 which
introduced atomicWriteFile + write-to-tmp + rename.

* fix(core): route root through in-place fallback + doc/test follow-ups

Review follow-ups on the atomic-write ownership fix:

1. Remove the root-special-case (rename + post-rename chown). chown
   silently fails inside user-namespaced or CAP_CHOWN-stripped Docker
   containers, which re-triggers the original bug for root-in-Docker
   users — exactly the scenario this fix was reported against. Routing
   root through the same in-place fallback as non-root eliminates this
   failure mode and drops an untestable branch (chown-back can't be
   exercised under non-root CI).

2. Document the three properties traded away by the in-place fallback:
   crash atomicity, concurrent-reader isolation, inotify watcher
   semantics (MODIFY vs MOVED_TO).

3. Document that the in-place fallback surfaces EACCES when the file's
   mode forbids the current user from writing — this is correct
   behavior (atomic rename used to silently replace files the user had
   no permission on, which was arguably a privilege issue).

4. Replace the brittle "see step 6 in the function doc" comment with a
   step-number-independent reference.

5. New test covering the EACCES path: chmod 0o444 + mocked geteuid
   triggers the fallback, fallback hits the read-only file, EACCES
   propagates cleanly, original content is preserved.

* fix(core): harden in-place fallback against symlink/unlink/inode races + doc/test follow-ups

Review follow-ups on QwenLM#4431 ownership-preservation fix:

CRITICAL — in-place fallback security hardening (wenshao review):

The path-based `fs.writeFile(targetPath, ...)` fallback introduced
three races that the prior `rename(tmp, target)` form did not have:

1. Non-regular files (FIFO/socket/device): fs.writeFile calls
   open(O_WRONLY|O_CREAT|O_TRUNC). On a FIFO this blocks forever
   waiting for a reader. On a character/block device it writes to
   the actual device. The rename path replaced these with a
   regular file.

2. Symlink-swap TOCTOU: an attacker with parent-dir write can swap
   targetPath for a symlink between our stat and our writeFile.
   fs.writeFile follows symlinks at the destination; POSIX rename
   does not. In the very "shared-write workspace / Docker bind-mount"
   scenarios this PR targets, this lets a directory-writable
   attacker redirect agent writes elsewhere (e.g. /etc/passwd if
   the agent runs as root).

3. Unlink race: if targetPath is unlinked between stat and write,
   O_CREAT silently recreates it owned by the calling user — the
   exact ownership change the fallback was designed to prevent.
   Silent regression to the pre-fix bug under this race.

Fix: extract the fallback into writeInPlaceWithFdGuards():

  - open(target, O_WRONLY | O_TRUNC | O_NOFOLLOW) — no O_CREAT, so
    unlink-race surfaces ENOENT instead of silently recreating; and
    O_NOFOLLOW rejects symlink-swaps with ELOOP.
  - fstat(fd) verifies the bound inode's uid/gid still match
    existingStat — refuses the write if an inode-swap happened
    between stat and open.
  - Write through the fd (locked to the verified inode), chmod
    through the fd, close.

Caller now gates the fallback on existingStat.isFile() — non-regular
targets fall through to the atomic path which has well-defined
"replace special-file with regular-file" semantics.

DOC / TEST follow-ups:

- Add hardlink-propagation as a 4th trade-off in the in-place
  fallback JSDoc (review comment #4): rename creates a new inode so
  sibling hardlinks keep old content; in-place truncate+write keeps
  the inode so all hardlinks see new content.

- Update atomicWriteJSON JSDoc to note the write is now
  *conditionally* atomic (review comment #5): atomic when uid/gid
  matches the process, in-place when ownership differs. Previously
  the JSDoc still claimed unconditional atomicity.

- Update caller comments at runtimeStatus.ts and
  worktreeSessionService.ts that advertised crash-atomic writes via
  tmp+rename — those guarantees are now conditional (review
  comment #6).

- Add mode + tmp-leftover assertions to the gid-mismatch test to
  match the uid-mismatch test (review comment #2 — test
  consistency). Without these, a gid-fallback regression that
  silently dropped permissions or left a tmp file would not be
  caught.

- New test: FIFO + ownership mismatch must take the atomic path,
  not in-place (verifies the existingStat.isFile() guard works;
  hang on in-place would trip vitest timeout).

- New test: writing through a symlink with ownership mismatch
  exercises the resolve-then-stat-then-open flow and verifies the
  symlink itself is preserved.

Tests: 192/192 pass (atomicFileWrite + write-file + edit +
fileSystemService).

* fix(core): defer O_TRUNC and verify dev+ino in writeInPlaceWithFdGuards

PR QwenLM#4431 review follow-up (wenshao critical):

The previous form opened with `O_WRONLY | O_TRUNC | O_NOFOLLOW`, which
truncated the bound file *before* the fd-bound fstat verification ran.
If an attacker swapped the path between the caller's stat and our
open, we would truncate the attacker's substituted inode (destroying
unrelated content) before detecting the swap.

Two fixes:

1. Open without O_TRUNC. Verify dev+ino+uid+gid+isFile match
   expectedStat through fh.stat(). Only then call fh.truncate(0)
   through the validated fd.

2. Expand the verification beyond uid+gid to include dev+ino+isFile.
   uid+gid alone misses a same-owner inode swap (attacker replaces
   the path with a different inode they own). dev+ino is the strong
   identity check; isFile catches a swap to FIFO/socket/device after
   the caller's existingStat.isFile() gate.

JSDoc updated to enumerate the four guards (NOFOLLOW, no CREAT, no
TRUNC at open, dev+ino+uid+gid+isFile via fstat) and explain why
truncation must wait until after verification.

192/192 tests pass.

* fix(core): close FIFO swap race with O_NONBLOCK + cover EOWNERSHIP_CHANGED path

PR QwenLM#4431 review follow-up (deepseek-v4-pro via /review):

CRITICAL — FIFO swap TOCTOU:

The caller's `existingStat.isFile()` gate uses stat data captured
earlier. An attacker with parent-dir write can swap the regular file
for a FIFO between the caller's stat and our open inside
`writeInPlaceWithFdGuards`. The previous `O_WRONLY | O_NOFOLLOW` open
would then block indefinitely waiting for a FIFO reader; O_NOFOLLOW
only catches symlinks.

Fix: add O_NONBLOCK to the open flags. Defense in depth:

- On a reader-less FIFO, `open(O_WRONLY | O_NONBLOCK)` returns ENXIO
  immediately — no hang.
- If the FIFO has a reader (open succeeds), the subsequent fstat
  isFile() check still refuses the write via EOWNERSHIP_CHANGED.
- For regular files, O_NONBLOCK is a no-op.

CRITICAL test gap — EOWNERSHIP_CHANGED branch untested:

The primary TOCTOU defense (fdStat dev/ino/uid/gid/isFile vs
expectedStat) had no coverage. Exported `writeInPlaceWithFdGuards` so
it can be unit-tested directly:

- New test: simulate post-stat inode swap (unlink + recreate at same
  path), call helper with stale stat, assert EOWNERSHIP_CHANGED and
  that the attacker's content survives.
- New test: simulate post-stat regular→FIFO swap, assert open fails
  fast (ENXIO) or fstat catches it — either way no hang, no write.

DOC fix:

JSDoc said "we open read-write without truncating" but the code uses
O_WRONLY. Wording corrected to "write-only".

194/194 tests pass.

* fix(core): fix flaky inode-swap test + apply review follow-ups

PR QwenLM#4431 review follow-up (glm-5.1 via /review) — 7 suggestions adopted,
1 partially adopted, 0 rejected:

CI FIX (Ubuntu test failure on tmpfs inode reuse):

The EOWNERSHIP_CHANGED inode-swap test used unlink+create to simulate
a post-stat swap. On Linux tmpfs the freshly-freed inode number is
often reused by the immediately-following create, so dev+ino remained
identical and the guard didn't trip (intermittent on Ubuntu CI; macOS
APFS happened to allocate different inodes). Switched to rename(decoy,
target) which moves an existing distinct inode into place, guaranteed
to differ from the original.

CODE:

- Wrap fh.writeFile failure after fh.truncate(0) with
  EINPLACE_WRITE_FAILED + cause, so callers see explicitly that the
  file was truncated and the write didn't complete (otherwise they
  see raw ENOSPC/EIO and may wrongly assume the original is intact
  given this lives in atomicFileWrite.ts).
- Skip fh.chmod when euid is neither root nor expectedStat.uid —
  chmod is guaranteed to fail with EPERM in that case (POSIX requires
  owner or root). Avoids a guaranteed-failing syscall on every call.
- Caller catches ENOENT from writeInPlaceWithFdGuards and falls
  through to atomic rename path. If the file was deleted between
  caller's stat and our open there is no ownership to preserve; the
  rename path correctly creates a new file at targetPath.

DOC:

- Replaced "defends against four races" with "hardened against
  post-stat races" (the bullet list has 5 items, the count was wrong).
- Reworded "non-regular targets must not reach this function" to
  describe defense-in-depth — O_NONBLOCK + !fdStat.isFile() reject
  post-stat regular→FIFO/socket/device swaps. The old wording made
  it look like O_NONBLOCK was redundant.
- Documented the dual chmod behavior (root vs non-root with foreign
  uid) inline.

TESTS:

- Added happy-path test for writeInPlaceWithFdGuards (write succeeds,
  inode preserved, mode preserved).
- Added ENOENT regression test (verifies the missing-O_CREAT
  property — if file unlinked between stat and open, no silent
  recreate with caller's uid).
- Renamed the misleading "O_NOFOLLOW guard" test (it actually tests
  resolve-through-symlink, not O_NOFOLLOW) to reflect what it does,
  and added a direct ELOOP test that drives writeInPlaceWithFdGuards
  with a path whose final component is a symlink — that's the real
  O_NOFOLLOW exercise.
- Fixed the FIFO test to pass a stat captured from the FIFO itself
  (not a stale regular-file stat) so only the FIFO-specific defense
  fires, not the inode/dev mismatch from a different file.

NOT ADOPTED:

- Skip-when-non-root chmod optimization adopted (small, useful), but
  the larger "structured chmod error model" deferred — best-effort
  matches the existing tryChmod pattern at file scope.

197/197 tests pass.

* fix(core): wrap truncate err + post-write nlink check + guard close + chmod sync

PR QwenLM#4431 review follow-up (qwen-latest-series-invite-beta-v34 via /review)
— 7 of 10 suggestions adopted, 3 deferred:

CODE:

- **EINPLACE_TRUNCATE_FAILED wrap** (review #3291863048): symmetric to
  the existing EINPLACE_WRITE_FAILED — distinguishes "truncate failed,
  original intact" from "write failed post-truncate, original lost".

- **Post-write nlink === 0 check** (review #3291863059):
  EINODE_UNLINKED_DURING_WRITE detects the fstat-to-close window where
  a concurrent rename-over drops our bound inode's link count to zero
  and our write goes to an anonymous inode close will free. Silent
  data loss path now surfaces.

- **fh.close() guarded in finally** (review #3291863044): close failure
  on NFS/FUSE was masking the original try-body exception (including
  the meaningful EOWNERSHIP_CHANGED, EINPLACE_*, EINODE_*). flush:true
  already fsync'd, so close-after-flush is best-effort.

- **fdStat.uid in canChmod** (review #3291863055 part 1): use the
  fd-bound verified value instead of expectedStat.uid. Defense in depth
  — a future weakening of the fstat guard won't silently widen chmod
  privilege.

- **fh.sync() after chmod** (review #3291863053): chmod is metadata,
  not covered by writeFile({ flush: true }). A crash before lazy
  metadata flush would lose the mode restoration (matters for
  setuid/setgid). One extra syscall, best-effort.

- **@remarks freshness contract** (review #3291863051 partial): JSDoc
  now spells out that expectedStat MUST be a fresh stat captured
  immediately before the call. Stale stats nullify every guard.

- **Concurrent-writer limitation noted** (review #3291863061 partial):
  added a "Known limitation — no advisory locking" paragraph to JSDoc
  rather than adopting flock (Linux-specific, NFS issues, scope
  expansion). Callers needing multi-process coordination should layer
  their own lockfile.

- **@throws documentation** (review #3291863051 partial): four
  documented error codes (EOWNERSHIP_CHANGED, EINODE_UNLINKED_DURING_WRITE,
  EINPLACE_TRUNCATE_FAILED, EINPLACE_WRITE_FAILED).

TESTS:

- **EINPLACE_WRITE_FAILED via FileHandle.prototype.writeFile monkey-patch**
  (review #3291863040): triggers the data-loss path, asserts the wrapped
  code + message + cause, and verifies the file is empty (truncate ran).

- **canChmod=false actually skips chmod** (review #3291863055 part 2):
  prior uid-mismatch test had desiredMode === current mode, couldn't
  distinguish "skipped" from "no-op". New test uses desiredMode=0o755
  on a 0o644 file under canChmod=false → asserts mode stays 0o644.

NOT ADOPTED:

- ENOENT/ELOOP/ENXIO catch extension (review #3291863043): keeping the
  strict refusal for swap-to-special-file. Silent fallthrough-to-replace
  was pre-PR atomic-rename behavior, but in shared-write workspaces
  (this PR's target users) a special-file appearing at the target path
  is a signal worth surfacing, not papering over.

- Diagnostic logging (review #3291863049): the function has no logger
  dependency today; adding one is an architecture decision outside
  this PR's scope. The path taken is implied by the side effects
  (inode preserved vs new) but agreed: out-of-band telemetry would
  help ops. Defer to follow-up.

- flock advisory locking (review #3291863061 main): scope expansion;
  Linux-specific semantics, NFS edge cases. Documented as known
  limitation instead.

- Integration test for ENOENT fallthrough at atomicWriteFile level
  (review #3291863043 part 1): ESM module bindings prevent monkey-
  patching writeInPlaceWithFdGuards from outside. The unit test for
  the helper's ENOENT path covers the throwing behavior; the catch is
  3 lines and review-visible. Defer until a refactor opens an
  injection seam.

- Error code string constants export (review #3291863051 part 3): two
  codes don't merit a constant module. Magic strings are fine at this
  size.

199/199 tests pass.

* docs(core): sync writeRuntimeStatus JSDoc with conditional-atomic contract

PR QwenLM#4431 review follow-up: function-level JSDoc still claimed
unconditional "Atomically write" and "never sees a partially written
file", inconsistent with the module-level docblock updated in earlier
commits. Updated to describe the conditional-atomic behavior (atomic
when uid/gid matches, in-place fallback when ownership differs) and
explicitly note the concurrent-reader visibility trade-off in the
fallback path. Links to atomicWriteJSON for the full contract.

Doc-only change. 199/199 tests pass.

* fix(core): add explicit fh.sync() — FileHandle.writeFile ignores flush option

PR QwenLM#4431 review follow-up (qwen3.7-max via /review):

CRITICAL — FileHandle.writeFile silently ignores flush:

Node.js FileHandle.writeFile takes an early-return path that bypasses
the flush option entirely (the option is only honored on the
path-based fs.writeFile form). Our previous code passed
{ flush: true } to fh.writeFile and relied on the implicit fsync.
The only explicit fh.sync() was nested in the chmod block guarded by
canChmod — which is FALSE precisely when a non-root group member
writes to a group-writable file they don't own (the exact shared-write
scenario this PR targets). Net effect: in that branch, zero fsync.
Data sits in the kernel page cache; a crash before lazy flush leaves
the file empty (truncate succeeded) or partially written.

Fix:
- Drop flush from the fhWriteOptions object (silently ignored anyway).
- Add an explicit `fh.sync()` after writeFile succeeds, gated on
  options.flush. Runs BEFORE the chmod block so the canChmod=false
  branch also fsyncs.
- The chmod-block fh.sync() becomes metadata-only (covers the mode
  change), as the data is already on disk.

Updated comments to reflect the actual semantics rather than the
incorrect "writeFile({ flush: true }) fsyncs" assumption.

TESTS (partial adoption of review #3293252349):

- EINPLACE_TRUNCATE_FAILED: sibling test to EINPLACE_WRITE_FAILED.
  Monkey-patches FileHandle.prototype.truncate to throw EIO; asserts
  err.code + cause + "original content is intact" message, and
  verifies the file's original bytes are unchanged (truncate didn't
  run).
- Buffer in in-place fallback: locks in binary fidelity (byte-exact
  comparison) so a future encoding-passthrough regression for Buffer
  data would be caught.

NOT ADOPTED in this commit:

- EINODE_UNLINKED_DURING_WRITE test: requires post-write fh.stat()
  mocking with call-count discrimination (first call: real stat for
  verification; second call: nlink=0). The monkey-patch pattern works
  but is fragile; deferred to a follow-up that may also refactor the
  helper to accept an injectable stat fn for cleaner testability.

201/201 tests pass.

* fix: correct stale flush comment + add fh.sync() regression test

- Fix misleading close() comment that said "flush:true already
  fsync'd" — the explicit fh.sync() does the actual fsync, not the
  flush option (which is silently ignored on FileHandle.writeFile).
- Add regression test verifying fh.sync() is called when flush:true
  and skipped when flush is absent, preventing silent removal of the
  core durability fix.

Addresses wenshao review threads from 2026-05-23.

* test: add EINODE_UNLINKED_DURING_WRITE regression test

Monkey-patches FileHandle.stat to return nlink:0 on the post-write
check, verifying the nlink guard throws with the correct error code.
Addresses wenshao review from 2026-05-28.

* simplify: replace writeInPlaceWithFdGuards with plain fs.writeFile

Address yiliang114's review (CHANGES_REQUESTED):

1. [Critical] Remove ~120 lines of fd-level TOCTOU hardening
   (writeInPlaceWithFdGuards) — over-engineering for a local CLI.
   The in-place fallback now uses plain fs.writeFile + tryChmod,
   matching the EXDEV fallback pattern.

2. [Suggestion] Fix macOS GID false-positive: only compare uid in
   ownershipWouldChange(). macOS inherits parent dir GID for new
   files, so egid !== file.gid was a false positive that needlessly
   dropped crash atomicity.

3. [Suggestion] Trim 60+ lines of JSDoc to project style (AGENTS.md:
   "default to none, add only when WHY is non-obvious").

Net: -748 lines. 24 tests pass.

* fix: restore Stats type import (TS2304 build failure)

* docs: narrow scope from uid/gid to uid-only preservation

The gid check is intentionally skipped because macOS inherits the
parent directory's GID for new files, making egid !== file.gid a
false positive. Update comments and PR description to match the
actual implementation scope.

* test: add inode assertion to symlink ownership-mismatch test

Proves the in-place fallback actually ran instead of atomic rename.
* feat(cli): improve hooks matcher display

* test(cli): cover hooks navigation levels
Detach closeSession/killSession from the session entry's owning channel instead of the current attach target, so the correct channel is decremented and killed during channel overlap (old channel dying while a fresh channel is current). Extracts findChannelInfoForEntry/detachSessionIdFromEntryChannel helpers with unit + integration coverage. Fixes QwenLM#4325.
… variants to prevent OOM on resume (QwenLM#4644)

* fix(core,cli): replace full-history structuredClone with shallow/tail variants to prevent OOM on resume

Several UI and service call sites clone the entire chat history via
structuredClone(getHistory()) every turn. On a resumed session with
thousands of entries, each clone allocates 150-200 MB transiently.
When multiple async side-requests overlap (suggestion generation,
auto-title, checkpointing), multiple clones coexist on the heap,
pushing V8 past its limit within 10 turns (2 GB heap cap).

Changes:
- AppContainer.tsx: use getHistoryTail(40, true) instead of
  getHistory(true) + slice(-40)
- btwCommand.ts: same pattern, use getHistoryTail(40, true)
- sessionTitle.ts: use getHistoryShallow() (read-only filtering)
- sessionRecap.ts: use getHistoryShallow() (read-only filtering)
- useGeminiStream.ts: use getHistoryShallow() for checkpoint
  serialization (only needs to survive JSON.stringify)

Closes QwenLM#4624

* fix(test): update mocks for getHistoryShallow/getHistoryTail in sessionTitle and btwCommand tests

* fix(cli): migrate remaining getHistory() clone sites to shallow/tail variants

- AppContainer.tsx rewind path: getHistory() → getHistoryShallow()
  (only used read-only by computeApiTruncationIndex)
- Session.ts ACP rewind: getHistory() → getHistoryShallow()
  (only walks entries to compute truncation index)
- Session.ts stop-hook: getHistory() + filter(.model).pop() →
  getLastModelMessageText() (O(1) backward scan, no clone)

* fix(core): use client-level getHistoryShallow with fallback

sessionTitle.ts and sessionRecap.ts were calling
chat.getHistoryShallow() directly, bypassing the client-level
wrapper that provides a getHistory() fallback when the chat
implementation doesn't support shallow reads. Use
geminiClient.getHistoryShallow() instead.

Update test mocks to match the new call site.

* fix(test): add getHistoryShallow and getLastModelMessageText to Session test mocks

Session.ts now calls chat.getHistoryShallow() in rewindToTurn and
chat.getLastModelMessageText() in the Stop hook. Update all mockChat
instances in Session.test.ts to provide these methods.
… statusline (QwenLM#4670)

* feat(cli): add respectUserColors option to preserve ANSI colors in
     statusline command output

* test(cli): add respectUserColors tests for useStatusLine and Footer

* feat(cli): add hideContextIndicator option to hide built-in context usage in footer

* docs: update statusline configuration docs with respectUserColors and hideContextIndicator
…e handling (QwenLM#3557)

* Harden insight facet normalization and empty qualitative handling

* feat: enhance AtAGlance component to accept target sections for dynamic rendering
* feat(core): add simplify bundled skill

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

* test(cli): stabilize SettingsDialog restart prompt test

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

* fix(skills): use agent tool instead of task in simplify skill

The simplify skill referenced the 'task' tool for launching review passes,
but Qwen Code exposes 'agent' as the callable subagent tool ('task' is only
a legacy permission alias). Using 'task' would cause /simplify to stall when
trying to launch parallel review passes.

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

* docs: document simplify bundled skill

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

* Update packages/core/src/skills/skill-manager.test.ts

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* fix(core): repair simplify skill tests

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

* Update packages/core/src/skills/bundled/simplify/SKILL.md

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* fix(skills): address simplify review feedback (read-only passes, gitignore scope, safer dead-code removal)

- drop inert `argument-hint` frontmatter (argumentHint is never parsed or
  rendered anywhere; no other bundled skill uses it)
- mark Step 2 review passes read-only so edits stay isolated to Step 4
- narrow the no-diff fallback to `git ls-files --modified --others
  --exclude-standard` so ignored build output is excluded
- require a repo-wide caller check before removing code
- make the commands.md row state it edits code directly
- assert non-conflicting bundled skills survive cross-level dedup

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

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: wenshao <wenshao@U-K7F6PQY3-2157.local>
* chore(skills): add codex reproduce workflows

* feat(agent-reproduce): implement agent reproduction workflow and supporting scripts

* feat(skills): capture reference agent state diffs
)

* chore(deps): re-upgrade ink 6 → 7.0.3 (upstream Static remount fix landed)

PR QwenLM#3860 first upgraded ink 6 → 7.0.2. PR QwenLM#4083 reverted because of a
TUI regression: `<Static>` did not re-emit items when its `key` prop
was bumped, so `/clear` / Ctrl+O / refreshStatic left the history area
blank under ink 7.0.2.

ink 7.0.3 (released after QwenLM#4083) contains the exact fixes:

  - be9f44cda Fix: <Static> remount via key change drops new items (QwenLM#948)
  - 669c4386c Fix: Drop stale <Static> output from fullStaticOutput on identity change (QwenLM#950)
  - 7c2267c01 Fix `useBoxMetrics` not accepting ref objects with an initial null value (QwenLM#945)

Changes:
  - `ink` ^6.2.3 → ^7.0.3 (root hoist + cli direct)
  - `react` ^19.1.0 → ^19.2.4 (cli direct; ink 7.0.3 peerDeps requires >=19.2.0)
  - `react`/`react-dom` overrides ^19.2.4 added so the transitive graph
    stays deduped to a single instance (avoids `Invalid hook call` from
    multiple React copies, the classic ink-upgrade hazard)
  - `wrap-ansi` already on ^10.0.0 from QwenLM#4083's partial-revert (no change)

Verified:
  - `npm ls ink` → single `ink@7.0.3` across all peer deps
  - `npm ls react` → single `react@19.2.4`
  - `npm run typecheck --workspace=@qwen-code/qwen-code` clean
  - `npm run typecheck --workspace=@qwen-code/qwen-code-core` clean
  - Composer.test.tsx 20/20, MainContent.test.tsx 6/6, TableRenderer.test.tsx
    59/59 + 1 skipped — all key UI components green on the new ink

The Static-remount regression is upstream-fixed in 7.0.3, so the
runtime path is restored without needing QwenLM#3941's overflowY-self-managed
viewport. QwenLM#3941 (virtual viewport) remains an opt-in performance
feature on top.

* fix(deps,cli): add @types/react overrides + move refreshStatic out of setCurrentModel updater

Two follow-ups from the multi-round audit of the ink 7.0.3 re-upgrade:

1. @types/react / @types/react-dom now pinned to ^19.2.0 in root
   overrides. packages/web-templates still declares @types/react ^18.2.0
   in its devDeps. Today the CLI build is unaffected (web-templates's
   18.x types are nested in its own node_modules and the React-using
   src/insight and src/export-html files are excluded from its tsconfig
   build), but a future reincludes-or-hoist accident would land
   conflicting global JSX namespaces in the CLI compile graph. Match
   the dep dedup we already enforce for `react` and `react-dom` so the
   type graph stays as deduped as the runtime graph.

2. AppContainer's onModelChange handler was calling refreshStatic() as
   a side-effect inside the setCurrentModel updater. React.StrictMode
   double-invokes state updaters in dev, so model swaps fired two
   clearTerminal writes + two <Static> key bumps. The double work was
   masked under ink 6 (key changes were no-ops on <Static>), but ink
   7.0.3 honors key changes — the doubled work is now potentially
   visible as a faster flash-flash on every model switch.

   Refactor: setCurrentModel becomes a pure setter; refreshStatic
   moves into a useEffect keyed on currentModel with a ref-comparison
   guard so the first render doesn't fire. Single clearTerminal write
   per real model change, even under StrictMode.

Verified: npm ls ink → single 7.0.3, npm ls react → single 19.2.4,
npm ls @types/react → 19.2.10 hoisted (npm flags web-templates's 18.x
constraint as overridden, which is the intended behavior). Typecheck
clean across cli + core workspaces.

* docs(design): virtual viewport on ink 7 — analysis + PR sequence

Captures the architectural analysis of how to thoroughly close the
flicker / refresh-storm class of issues (QwenLM#2950, QwenLM#3118, QwenLM#3007, QwenLM#3838 UI
side, QwenLM#3899 follow-on) using a virtualized history viewport.

- Surveys claude-code (forked ink) and gemini-cli (@jrichman/ink +
  ScrollableList + VirtualizedList) reference implementations.
- Confirms ink 7 already exposes the primitives needed
  (`useBoxMetrics`, `measureElement`, `useWindowSize`,
  `useAnimation`) — no fork swap required.
- Picks porting gemini-cli's virtualized list components to ink 7 with
  `ResizeObserver` -> `useBoxMetrics` and a custom `StaticRender`.
- Splits the work into V.0..V.4 PRs with scope, dependencies, risk.
- Lists open questions + 11-item approval checklist that must clear
  before V.0 implementation begins.

This is a docs-only PR per the project's design-first workflow. No
runtime code changes.

Generated with AI

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

* feat(cli): virtual viewport for long conversations on ink 7

Port gemini-cli's VirtualizedList + ScrollableList to stock ink 7,
adapting for ink 7's available primitives:

- `overflowY="hidden"` + `marginTop={-scrollTop}` instead of ink-fork's
  `overflowY="scroll"` (ink 7 has proper clip/unclip in render-node-to-output)
- `useBoxMetrics` inside each VirtualizedListItem (Option A) instead of a
  single ResizeObserver WeakMap; reports height changes via onHeightChange
  callback so the parent can update its heights record
- Custom `StaticRender` as `React.memo` with a reference-equality comparator,
  keyed on `itemKey-static-{width}` to freeze completed conversation items
- Character scrollbar column (`│` track / `█` thumb) since ink 7 has no
  native scrollbar prop
- No ScrollProvider / mouse drag (deferred to a follow-up PR)

Wire into MainContent.tsx behind `ui.useTerminalBuffer` setting (Settings
dialog → UI → Virtualized History; default false — opt-in).

Key bindings: Shift+↑/↓ (line), PgUp/PgDn (page), Ctrl+Home/End (top/bottom).

Re-render optimisations:
- renderItem wrapped in useCallback so renderedItems useMemo only recomputes
  when actual deps change (not on every streaming tick)
- Completed history items passed by original object reference so
  VirtualHistoryItem = memo(HistoryItemDisplay) can bail out on stable props
- estimatedItemHeight / keyExtractor / isStaticItem defined as module-level
  constants with no closure deps

Generated with AI

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

* test(cli): add test coverage for virtual viewport scroll bindings and settings

- keyMatchers.test.ts: 6 new test cases for SCROLL_UP/DOWN, PAGE_UP/DOWN,
  SCROLL_HOME/END commands (41 tests total)
- settingsSchema.test.ts: assert ui.useTerminalBuffer is boolean, default false,
  showInDialog true, requiresRestart false

Generated with AI

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

* feat(cli): use ink 7 native overflow for VP pending items

In VP mode, pending items are rendered inside VirtualizedList's
overflowY="hidden" container, which uses ink 7's native clipping
as the viewport guard. Remove the availableTerminalHeight JS-
truncation bound from pending items in renderVirtualItem:

- JS truncation at terminal height would silently cut off content
  the user could scroll to read within the virtual viewport.
- ink 7 overflowY="hidden" on the VirtualizedList container is the
  correct clip guard — no JS line-counting workaround needed.
- Remove uiState.constrainHeight from renderVirtualItem deps (no
  longer referenced in the VP rendering path).

The legacy <Static> path is unchanged.

Generated with AI

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

* perf(cli): binary-search offsets in virtualized list hot path

Replace linear findLastIndex / findIndex scans on the offsets array with
upperBound. Offsets are monotonic by construction, so the lookups inside
the render body and getAnchorForScrollTop drop from O(n) to O(log n).
Material for thousand-turn sessions where the lookup runs on every frame.

* fix(cli): wire ShowMoreLines + skip clearTerminal in VP mode

Two audit-found bugs in the VP path:

1. `<ShowMoreLines>` was outside the `<OverflowProvider>` that wraps
   `<ScrollableList>` in VP mode. `useOverflowState()` returns
   `undefined` outside the provider, so the component returned `null`
   and the "press ctrl-s to show more lines" affordance silently
   disappeared. Move `<ShowMoreLines>` inside the provider so the hook
   sees the live overflow state, matching the legacy path.

2. `refreshStatic()` and `repaintStaticViewport()` wrote
   `clearTerminal` / `cursorTo+eraseDown` to the host terminal
   unconditionally. In VP mode the React tree owns the visible region
   via ink 7's native `overflowY="hidden"` clipping — the physical
   write is a wasted flash on Ctrl+O / Alt+M / model change / resize.
   Guard both writes on `useTerminalBuffer === false`. The
   `historyRemountKey` bump still fires so the legacy `<Static>`
   fallback would still remount if someone toggled the setting mid-
   session.

Extends the targeted-repaint pattern introduced in QwenLM#3967 to all
refreshStatic call sites, gated by the VP setting instead of by event
type.

* fix(cli): VP renderItem stability + source-copy offsets + heights GC

Three audit-found regressions tightened, in order of severity:

1. **Source-copy index offsets missing in VP** — legacy `<Static>` path
   threads per-item `sourceCopyIndexOffsets` so `/copy mermaid N` /
   `/copy latex N` hints stay stable across continuation messages. VP
   `renderVirtualItem` was not passing this prop, so the copy hints
   shown under each diagram drifted on every `gemini_content` chunk
   (the clipboard mechanism itself still worked from raw history; only
   the displayed number was wrong). Add two lookup tables —
   identity-keyed for static items, index-keyed for pending — without
   changing the VirtualizedList data signature, and thread offsets in
   both render branches.

2. **`renderVirtualItem` callback invalidated on every streaming tick**
   — its deps included `activePtyId` / `embeddedShellFocused` /
   `isEditorDialogOpen`, all of which flip mid-stream when a shell
   tool runs or a dialog opens. Each flip rebuilt the callback,
   invalidated `VirtualizedList.renderedItems`'s useMemo, and forced
   every static item to re-render through `<StaticRender>` — defeating
   the very memoization the design relies on. Move the three pending-
   only fields into a ref read inside the callback. Static-item closure
   now depends only on inputs that legitimately affect static output
   (terminalWidth, slashCommands, getCompactLabel, …). Pending items
   still re-render correctly because their item identity changes per
   tick, so the callback is called fresh each time and reads the
   latest ref.

3. **`pending` items now honour `constrainHeight`** in VP, matching the
   legacy path. Previously VP unconditionally passed `undefined` for
   `availableTerminalHeight` on pending, relying on the viewport
   `overflowY="hidden"` clip to limit visible size — but that hid the
   `<ShowMoreLines>` affordance from the user. Now that ShowMoreLines
   is correctly wired (previous commit), restore parity.

4. **Heights map memory leak** in `VirtualizedList` — `setHeights` only
   grew. Each `/clear` left orphan `h-N` keys; each pending → completed
   transition left orphan `p-N` keys. Add a `useLayoutEffect` that
   prunes entries whose keys are not in the current `data`. Runs in
   layout phase so the prune commits in the same paint as the data
   change — no stale-offsets frame.

* test+fix(cli): VP path coverage + stabilize absorbedCallIds empty Set

Completion-pass artifacts driven by the multi-agent audit:

- Settings description rewritten to enumerate the symptoms VP fixes so
  users with active flicker reports can find the toggle without reading
  the design doc.
- `absorbedCallIds` returns a module-level constant Set when compact mode
  is off, instead of a fresh `new Set()` per render. Fixes a hidden
  cascade: `activePtyId` flip mid-stream → useMemo runs → returns a new
  empty Set → `isSummaryAbsorbed` rebuilds → `renderVirtualItem`
  rebuilds → `VirtualizedList.renderedItems` recomputes → every static
  item re-renders. With the constant, the cascade dies at the source.
  Helps both VP and legacy paths.
- VP-path unit tests for MainContent (4 cases): ScrollableList mounts
  and Static does not when `useTerminalBuffer: true`; ShowMoreLines is
  reachable in VP mode (regression of the OverflowProvider mis-wrap);
  source-copy index offsets thread into renderItem for static items;
  renderItem callback identity is stable across `activePtyId` flips
  (proves the ref-based read keeps StaticRender memo effective).

* fix(cli): stabilize absorbedCallIds in compact mode + gate heights prune + tighten ShowMoreLines test

Round-2 audit follow-ups. Three real findings addressed; one flagged
false positive documented separately.

1. **absorbedCallIds Set identity now content-stable when compact mode is
   on.** The earlier EMPTY constant only short-circuited the compactMode=
   false path; when compact mode is enabled (some users default-on it),
   activePtyId / embeddedShellFocused flips during streaming still
   produced fresh Sets per render even when membership was unchanged,
   restarting the same cascade the pendingStateRef fix was meant to
   avoid. Compare-and-reuse via a ref: if the new Set has identical
   membership to the previous one, return the previous reference.

2. **`heights` map prune in `VirtualizedList` is gated.** Previously
   every streaming tick rebuilt an N-key Set and walked all heights,
   even on the steady-state path where nothing changes. Now only fires
   when the heights record has clearly outpaced live data
   (`size > max(8, 2 × data.length)`) — covers `/clear` and accumulated
   pending → completed transitions, skips the 30-Hz hot path entirely.

3. **VP ShowMoreLines test now actually verifies overflow connectivity.**
   Previous mock unconditionally rendered "SHOW_MORE", so the test only
   proved the JSX mounted — it would still pass if a future refactor
   moved `<OverflowProvider>` out of the VP tree again. The mock now
   reads `useOverflowState()` and emits "OVERFLOW_DISCONNECTED" when the
   context is missing. The VP test asserts both presence of "SHOW_MORE"
   and absence of the disconnected marker, so the regression is now
   caught.

Not addressed:
- Audit P0-1 claim that `renderMode` (Alt+M) / model-change updates
  don't reach VP static items: false positive. `renderMode` is a React
  Context (`RenderModeContext`), and Context propagation traverses the
  tree past `memo` boundaries — MarkdownDisplay's `useRenderMode()`
  consumer re-renders on context change regardless of whether
  `StaticRender` bails out. Verified by reading
  `packages/cli/src/ui/contexts/RenderModeContext.tsx` and
  `MarkdownDisplay.tsx:172`. No code change.
- Audit P1-2 pendingStateRef write-during-render race: speculative,
  relies on a multi-pass render path React 18+ does not currently use.
  Documented assumption in the existing inline comment.

* fix(cli): isolate renderItem errors + defensive height coerce + compact-mode mergedHistory stability

Round-3 audit follow-ups. Three real findings; the rest verified clean.

1. **`renderItem` errors no longer crash the CLI.** Previously a throw
   inside a per-item render propagated through `VirtualizedList`'s
   useMemo into React's commit phase, tearing down the whole Ink tree —
   one bad history record could nuke the session. Wrap each call in a
   try/catch and substitute a small red `[render error] …` text box on
   failure. The row stays in the viewport so the user can scroll past
   it.

2. **Defensive height coerce in offset accumulation.** A buggy
   `estimatedItemHeight` returning NaN / negative / Infinity would
   poison every downstream offset and break the `upperBound` /
   `findLastLE` binary search (which assumes monotonic offsets). Clamp
   to `Number.isFinite(raw) && raw > 0 ? raw : 0`. No-op for the
   in-tree estimators that return 3; insurance against future
   consumers.

3. **`mergedHistory` is content-stable when compact mode is on.** The
   Round-2 absorbedCallIds stability fix didn't reach this path:
   `mergeCompactToolGroups` always allocates a fresh array, and
   `mergedHistory`'s useMemo lists `activePtyId` / `embeddedShellFocused`
   as deps, so every streaming tick mid-shell-tool produced a new array
   even when items aligned. Cascade went `mergedHistory` → offsets map
   → `renderVirtualItem` → every static item re-rendered. Pair-wise
   compare new vs previous and return the previous reference when items
   align. Restores StaticRender memo effectiveness for compact-mode
   users.

Not addressed (audit findings deemed not worth fixing in this PR):
- `scrollToItem` silently no-ops when item is not in data — no current
  caller checks the return value, low impact.
- `allVirtualItems` array spread is O(n) per streaming tick — real but
  not a crash; revisit in a perf-focused follow-up.
- `itemRefs.current` is dead surface (never read) — cosmetic.
- StrictMode-only-in-DEBUG double-invoke paths verified safe.

* test+chore(cli): VP review round 4 — VirtualizedList/useBatchedScroll coverage + cleanups

Addresses wenshao's CHANGES_REQUESTED review on PR QwenLM#3941.

- Add focused unit tests for `VirtualizedList` (9 cases) covering empty
  data, `renderStatic` full-render, `initialScrollIndex` with
  `SCROLL_TO_ITEM_END`, `targetScrollIndex` anchoring, imperative
  `scrollToEnd` / `scrollToIndex`, per-item `renderItem` error isolation,
  NaN/negative estimator coercion, and out-of-range `initialScrollIndex`
  clamping.
- Add `useBatchedScroll` unit tests (4 cases) covering initial reads,
  pending-value reads in the same tick, post-commit pending reset, and
  callback identity stability across rerenders.
- Remove dead `itemRefs` / `onSetRef` plumbing (declared, written, never
  read; `useCallback` with empty deps was also a stale-closure trap).
- Remove unused `isStatic?: boolean` from `VirtualizedListProps`
  (only `isStaticItem` is actually consumed).
- Tighten the render-phase setState block: each setter is now guarded
  by an equality check so React bails out of redundant updates, and a
  comment documents that this is the React-endorsed "adjusting state
  while rendering" pattern (the synchronous update avoids a one-frame
  flash at the previous position when `targetScrollIndex` changes).

Generated with AI

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

* chore(cli): remove dead `dataRef` from VirtualizedList (round-4 followup)

Declared and written in a `useLayoutEffect` on every `data` change but
never read anywhere in the component. Flagged in wenshao's round-4 review
of PR QwenLM#3941.

Generated with AI

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

* fix(cli): collapse model-change effect back into one batched handler

wenshao's PR QwenLM#4119 review correctly flagged that splitting the
onModelChange flow into two effects (b25831b) reintroduced the
issue QwenLM#3899 freeze regression on every model switch:

  1. setCurrentModel(model) commits first, with the OLD
     historyRemountKey.
  2. <Static key={`${historyRemountKey}-${currentModel}`}> sees its
     key change (because currentModel did) and remounts immediately.
  3. MainContent's render-phase progressive-replay reset only fires
     when historyRemountKey changes, so replayCount is still the
     full mergedHistory.length from any prior catch-up.
  4. The remounted Static dumps the entire history in one synchronous
     layout pass — exactly the freeze progressive replay was added
     to avoid (QwenLM#3899). The second effect's refreshStatic() bump
     arrives a render too late.

Fix: do not split. Both side effects (refreshStatic, which writes
clearTerminal + bumps historyRemountKey, and setCurrentModel) live
in the event handler again, with a ref guard for same-model
notifications. The React.StrictMode concern that motivated b25831b
is addressed by keeping the side effect OUT of the setState updater
(it now runs once per event-handler invocation, not once per
double-invoked updater call). Both setState calls land in the same
React batch, so historyRemountKey and currentModel update together —
MainContent's render-phase reset sees the new key, replayCount drops
to the first chunk, and Static remounts with chunked replay intact.

Tests:
- AppContainer.test.tsx: 4 new tests covering the synchronous
  refreshStatic side-effect contract, same-model no-op, ref-guarded
  StrictMode double-invoke, and unsubscribe-on-unmount.
- MainContent.test.tsx: new regression guard — when currentModel
  changes but historyRemountKey is held constant, progressive replay
  must NOT reset (pins the MainContent invariant the two-effect
  refactor accidentally relied on).

Verified: vitest packages/cli AppContainer + MainContent green (82/82).
Typecheck clean.

Generated with AI

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

* fix+docs(cli): VP review round 5 — typecheck, doc drift, scroll keys

PR QwenLM#4146 review feedback (wenshao + Claude Opus 4.7 audit) addressed:

Code:
- MainContent.test: activePtyId typed as number (was 'pty-xyz' string,
  broke tsc with TS2322 — the test only relies on reference change so
  any number works).
- VirtualizedList: sanitize renderItem error path. Display becomes the
  generic `[render error]` marker; full err goes to debugLogger.debug
  so file paths / partial tool state don't leak to scrollback.
- MainContent: move pendingSourceCopyOffsetsByIndex into a ref so it
  no longer rebuilds renderVirtualItem identity every streaming tick.
  Without this, VirtualizedList.renderedItems useMemo invalidated
  per-tick → JSX rebuilt for every visible item → memo(HistoryItem
  Display) was still bailing but allocations were O(visible) per tick.
- AppContainer: drop the misleading "state-driven scroll reset" claim
  in the VP refreshStatic comment. VP is intentionally near-no-op:
  the React tree owns the visible region, mergedHistory mutation is
  what refreshes the screen, and the remount-key bump is preserved
  only to keep the legacy Static branch in sync if the user toggles
  the flag off mid-session.
- StaticRender: rewrite JSDoc to match reality. The custom React.memo
  is NOT output caching like @jrichman/ink's StaticRender export;
  the comparator rarely matches (parent allocates fresh JSX); the
  real skip happens at memo(HistoryItemDisplay) one level deeper.

Docs:
- docs/design/virtual-viewport: sync file map (drop non-existent
  ScrollProvider.tsx / useAnimatedScrollbar.ts), PR sequence (one PR
  QwenLM#4146, V.3-V.5 deferred), open-question + checklist resolution for
  QwenLM#3905 (superseded) and base branch rename.
- docs/users/reference/keyboard-shortcuts: document the 6 VP scroll
  keys (Shift+↑/↓, PgUp/PgDn, Ctrl+Home/End) under a "History
  scrollback (when ui.useTerminalBuffer is on)" section. Previously
  the only discovery path was the Settings dialog description.

Verified: tsc --noEmit -p packages/cli ✓, vitest 160/160 ✓ across
AppContainer / MainContent / VirtualizedList / useBatchedScroll /
keyMatchers / settingsSchema, eslint clean on touched files.

Generated with AI

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

* feat(cli): SGR mouse wheel scroll in VP mode

Recovers the most-felt UX regression vs legacy `<Static>` mode: when
`ui.useTerminalBuffer` is on, legacy users lose mouse wheel as a way
to scroll history (the host terminal stopped seeing the conversation
in its scrollback buffer). This PR enables button-event tracking
(`?1002h`) + SGR coordinates (`?1006h`) while the ScrollableList has
focus, parses wheel events off stdin, and routes them to scrollBy.

Scope kept tight on purpose:
- Wheel only. Hit-testing for scrollbar drag / click-to-position
  needs screen-absolute element coords; stock ink 7's useBoxMetrics
  returns yoga's parent-relative layout. Deferred to V.4 with two
  exit paths (upstream getBoundingBox to ink 7, or local yoga walker).
- Mouse mode is enabled only while ScrollableList is mounted; non-VP
  users never see their terminal flipped into button-event tracking.
- Side effect: native click-and-drag text selection is captured by
  the program. Docs + settings dialog description now spell out the
  Shift / Option (macOS) bypass.

Implementation:
- `ui/utils/mouse.ts` — SGR + X11 parser, ported and trimmed from
  gemini-cli (Google LLC, Apache-2.0). Single-consumer.
- `ui/hooks/useMouseEvents.ts` — enable/parse/disable lifecycle
  hook. Listens on stdin via `useStdin().stdin`, runs handler
  through a ref so callers don't have to memoize.
- `ui/components/shared/ScrollableList.tsx` — subscribe to mouse
  events, route wheel → `scrollBy(±3)`. Also drops a dead outer
  `<Box flexGrow={1}>` wrapper that held an unread containerRef
  and collapsed to zero height in ink-testing-library (the test
  renderer has no flex parent, so flexGrow=1 → 0 height → no items
  ever rendered, which is how this dead code was exposed).

Tests:
- `ui/utils/mouse.test.ts` — 14 cases: SGR parsing (wheel, presses,
  modifiers, move), X11 parsing, fallback chain, incomplete-sequence
  guard (including the >50-byte garbage cap).
- `ui/components/shared/ScrollableList.test.tsx` — 3 cases: wheel
  events shift the rendered window; hasFocus=false makes the mouse
  pipeline inactive (no throw); non-wheel events leave the window
  unchanged. Renders are wrapped in `<KeypressProvider>` (required
  by useKeypress in production but easy to forget in standalone
  tests).

Docs:
- `docs/users/reference/keyboard-shortcuts.md` — adds "Mouse wheel"
  row + the Shift/Option-to-select note.
- `packages/cli/src/config/settingsSchema.ts` — the in-app dialog
  description now mentions mouse wheel and the text-select bypass.
- `docs/design/virtual-viewport/README.md` — §1 status, §5 file map,
  §7 PR sequence all reflect mouse wheel landing in QwenLM#4146 and the
  V.4–V.7 follow-up split (scrollbar drag / in-app search / alt-
  buffer / host-scrollback dual-write research).

Verified: tsc --noEmit -p packages/cli ✓, vitest 182/182 ✓ across
AppContainer / MainContent / VirtualizedList / ScrollableList /
useBatchedScroll / mouse / keyMatchers / settingsSchema.

Generated with AI

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

* feat(cli): auto-hide animation for VP scrollbar thumb

Pairs with the SGR mouse-wheel work from the previous commit:
when the user actually scrolls, the thumb pops bright; after a
1.5s idle it fades into the dim track so the bar stops competing
with the conversation. The track column itself stays in layout
regardless, so the viewport never reflows mid-flash (which would
trigger per-item re-measure and a visible jitter).

Implementation kept minimal for stock ink 7:
- gemini-cli's `useAnimatedScrollbar` interpolates RGB colors via
  a theme + per-frame setInterval. The terminal can't render
  smooth fades anyway, so this hook collapses the state to a
  binary `isVisible` flag with a single setTimeout. ~75 LoC.
- `VirtualizedList` calls `flashScrollbar()` from a useLayoutEffect
  keyed on `clampedScrollTop`. The very first commit is skipped
  via a ref so initial mount doesn't paint a flash.
- The render switches the thumb glyph (`█` vs `│`) and `dimColor`
  based on `isVisible && inThumb`. Width stays 1 either way.

Tests (6 new):
- initial mount stays hidden (no spurious mount flash)
- flash → visible, hides after idle timeout, successive flashes
  reset the timer (no premature hide), idleHideMs<=0 disables
  auto-hide for tests that want to assert on the visible state,
  unmount cleans up the pending timer.

Doc updates:
- `docs/design/virtual-viewport/README.md` §1 status, §5 file map,
  §7 PR sequence — V.4 row now scopes only the drag/click-jump
  work (still coord-blocked); animated scrollbar moved out of
  deferred and into shipped.
- PR QwenLM#4146 body — architecture table mentions the auto-hide, new
  files list adds `useAnimatedScrollbar.ts`, test count refreshed
  to 188/188.

Verified: tsc --noEmit -p packages/cli ✓, vitest 188/188 ✓.

Generated with AI

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

* fix(cli): VP review round 6 — ESC bug, CI lint, scope-controlled cleanup

Triage of /review feedback from 2026-05-18 + 2026-05-19. Took the
ones that are real and small; declined the ones that are
false-positive / out-of-scope so this PR stops expanding.

Must-fix:
- CI Lint failure: vscode-ide-companion/schemas/settings.schema.json
  was stale after the keyboard-shortcuts description bump. Regenerated
  via `npm run generate:settings-schema`.
- useMouseEvents.ts had `const ESC = '';` (literal empty string after
  the raw 0x1B byte got stripped somewhere in the source pipeline).
  `buffer.indexOf('', 1) === 1` would have degraded garbage skipping
  to a one-byte scan, and the `else { buffer = ''; break }` branch
  could never run. Fixed by switching to the `'\x1b'` text escape and
  doing the same in `mouse.ts` (which had the raw byte, also fragile).
  Comment explains why.

Small wins (one-liners taken from the review batch):
- ScrollableList: rest-spread separates `hasFocus` from the props
  forwarded to VirtualizedList. Latent collision risk; no behaviour
  change today.
- VirtualizedList: `debugLogger.debug` when isReady=false so blank-
  viewport edge cases (tiny terminal / mid-resize race) become
  diagnosable from the debug log instead of looking like a hang.

Real perf (VP-only):
- MainContent: gated the progressive-Static-replay machinery behind
  `!useVirtualScroll`. The render-phase reset still consumes the
  remount-key bump so flag-off toggles mid-session catch up cleanly,
  but `setReplayCount` and the setImmediate chunking effect are now
  skipped for VP users. Saves ~M/CHUNK_SIZE wasted re-renders per
  Ctrl+O / model change on a 1000-turn session.

Belt-and-braces:
- useMouseEvents: added a `process.on('exit')` handler that writes
  the SGR mouse disable seq again. The React cleanup already covers
  normal unmount, but Ctrl+C / SIGTERM / parent kill bypass it and
  the terminal would otherwise stay in button-event-tracking mode
  after qwen exits.

Explicitly declined / deferred (with reasoning logged on the PR):
- requestAnimationFrame wheel throttle: rAF doesn't exist in Node;
  React 19 already batches state updates within a tick, and the
  renderedItems memo bounds the actual work to visible items. Will
  revisit if profiling shows it.
- Stable pending-item IDs (`p-N` keys shifting on completion): the
  observable jitter is at most one frame of estimated-vs-actual
  height delta. Moderate scope (creation-time ID allocation); fits
  better in a focused follow-up than in this PR.

Verified: tsc --noEmit -p packages/cli ✓, vitest 188/188 ✓ across
the full VP suite.

Generated with AI

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

* fix(cli): scrollBy bottom uses live end anchor in virtualized list

When keyboard scroll reaches the bottom, scrollBy set isStickingToBottom
but anchored via getAnchorForScrollTop(maxScroll), a fixed {index,offset}
pixel anchor. scrollTo/scrollToEnd instead use {index: last, offset:
SCROLL_TO_ITEM_END}, which recomputes the bottom from live item heights
each render. The fixed anchor did not track the last item growing during
streaming, so scroll-to-bottom via keyboard lagged behind new tokens.
Align scrollBy's bottom branch with the sibling methods.

Reported by wenshao in PR review.

* fix(cli): parse mouse events via ink useInput, not a stdin data listener

useMouseEvents attached its own stdin.on('data', ...) listener. Adding a
'data' listener switches stdin into flowing mode, which drains the buffer
before ink's readable + stdin.read() reader (ink App) can consume it, so
all keyboard input routed through useInput was silently starved while
mouse mode was active.

Parse mouse sequences from ink's existing input pipeline via useInput
instead, so there is only one stdin reader. ink captures a full SGR
sequence (ESC [ < .. M/m) as a single CSI event and delivers it with the
leading ESC stripped, so we re-prepend it before parsing. Non-mouse input
does not match and is ignored; ink still routes input to the app's other
useInput handlers, so keyboard navigation keeps working.

Only SGR mode (1006h, which we enable) is parsed via this path; the legacy
X11 encoding is not recoverable through ink's CSI parser, which is the
encoding modern terminals stop emitting once 1006h is set.

Reported by wenshao in PR review.

* fix(cli): parse only SGR in mouse hook to avoid X11 paste misfire

The useInput-based mouse hook called parseMouseEvent, which also tries the
X11 fallback (parseX11MouseEvent). An X11 prefix (ESC [ M + 3 bytes) can
reach the handler via pasted text — ink emits paste content as input when
no paste listener is registered — and would misfire a spurious mouse event.
Call parseSGRMouseEvent directly so only the SGR encoding we enable (1006h)
is parsed, matching the hook's documented contract.

Reported by wenshao in PR review.

* test(cli): assert SGR mouse parser rejects X11 sequences

Locks in the security property behind the parseMouseEvent ->
parseSGRMouseEvent switch in useMouseEvents: an X11 sequence arriving as
pasted text must not misfire a mouse event. Asserts a well-formed X11
sequence is a valid X11 event yet returns null from parseSGRMouseEvent, so
a future revert to parseMouseEvent fails this test.

Reported by wenshao in PR review.

* test(cli): add VP scroll coverage + eslint-disable for useBatchedScroll

Cover keyboard scroll commands (Shift+Up/Down, PageUp/Down, Ctrl+Home/End),
scrollBy/scrollTo imperative API (positive/negative/overflow/clamp), and
auto-scroll-during-streaming state machine (stick-to-bottom, disengage on
user scroll, re-engage on scrollToEnd). Add missing eslint-disable-next-line
for intentionally dep-free useLayoutEffect in useBatchedScroll.

Generated with AI

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

* chore(cli): remove trailing whitespace in useBatchedScroll

The eslint-disable-next-line comment was removed by eslint --fix as an
unused directive (exhaustive-deps does not flag a useLayoutEffect with
no dependency array). Clean up the residual blank line.

Generated with AI

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

---------

Co-authored-by: 秦奇 <gary.gq@alibaba-inc.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
…M#4414)

PR QwenLM#4064 introduced ~/.qwen/file-history/{sessionId}/ for /rewind but had
no cross-session cleanup — directories accumulated indefinitely. This adds
a generic background housekeeping framework with file-history cleanup as
its first user.

- 30-day mtime sweep, configurable via general.cleanupPeriodDays
- 10-min startup delay (1-min catch-up if last run >7d ago)
- 24h recurring cadence, idle-gated (defers if user typed in last 1 min)
- O_EXCL lockfile + marker mtime throttle (multi-process safe)
- Current session whitelisted via lazy config.getSessionId() — defends
  against long-idle active sessions and /clear minting a new session
- Negative cleanupPeriodDays values clamp to 1h minimum (defends against
  schema-bypass: a future cutoff would otherwise sweep everything)
- Zero new prod dependencies; ~70 lines of self-written O_EXCL throttle
  primitive in lieu of proper-lockfile (which pulls graceful-fs and
  monkey-patches every fs method on first require)
- All setTimeout(...).unref() — never blocks process exit

Closes QwenLM#4173.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
…king (QwenLM#4680)

* fix(core): loosen auto-mode classifier timeouts, disable stage-2 thinking

The AUTO-mode classifier fails closed on timeout — a timed-out judge call
blocks the action as "unavailable". The tight 3s/10s stage budgets turned
transient slowness (slow network, large transcript, model queueing) into
spurious blocks of otherwise-valid actions. Raise them to 10s/30s so a
slow-but-healthy call is not treated as a hard block.

Also disable thinking in stage 2 (previously the only stage with
includeThoughts: true). This is a latency-sensitive permission gate the
user is actively waiting on; allocating a reasoning budget made the review
path slower and more expensive, which directly worsened the fail-closed
timeout. The model still records its reasoning in the structured
`thinking` output field — it just no longer gets an allocated budget.

Closes QwenLM#4676

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

* docs(core): trim verbose comments in auto-mode classifier

Condense the three comments touched by this change (module docstring
stage-2 note, timeout-budget rationale, stage-2 thinkingConfig) while
keeping the essential "why". No logic changes.

Co-authored-by: Qwen-Coder <noreply@qwenlm.ai>

---------

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <noreply@qwenlm.ai>
…rt 1) (QwenLM#4439)

* fix(core): coerce hostile-provider usage token counts (QwenLM#4350 part 1)

Hostile providers (broken upstream, OpenAI-compat proxy returning
null/NaN, misconfigured override) can emit non-finite or negative
values for `usageMetadata.{prompt,candidates,cached,total}TokenCount`.
Captured unguarded in `processStreamResponse`, these poison the
compaction gate arithmetic:

- `lastPromptTokenCount + NaN >= hard` is always false → hard-rescue
  is silently disabled, eventually OOMing the V8 heap.
- `Infinity >= hard` is always true → hard-rescue fires every send.

Route the four API capture sites through a `coerceUsageCount` helper
that maps unknown / non-finite / negative to 0. `Number.isFinite(-1)`
is true, so an explicit `>= 0` is needed in addition to `isFinite`.

Part 1 of the hostile-provider hardening from QwenLM#4350. The companion
`computeThresholds` guard depends on the un-merged three-tier ladder
in QwenLM#4345 and is deferred until that lands.

Covered by parametrized tests in `geminiChat.test.ts` over NaN,
±Infinity, negative, null, undefined, and string inputs, plus a
fallback test asserting a hostile `promptTokenCount` falls through
to a coerced `totalTokenCount`.

* docs(core): narrow coerceUsageCount JSDoc to fields it actually coerces

The JSDoc for coerceUsageCount enumerated
{prompt,candidates,cached,total}TokenCount as the protected fields, but
candidatesTokenCount is never passed through coerceUsageCount in this PR --
only promptTokenCount, totalTokenCount, and cachedContentTokenCount are.
The original wording created a misleading impression of coverage.

Rewrite the JSDoc to (a) list exactly the three fields the function is
called on, (b) state explicitly that candidatesTokenCount is intentionally
left raw because it does not feed the compaction gate, and (c) call out
that candidatesTokenCount still flows unguarded into OTel spans via
loggingContentGenerator -- to be tightened separately.

No behavior change. Resolves the geminiChat.ts:109 review thread on this
PR.

* fix(core): address review feedback on coerceUsageCount

- Fix JSDoc: 'This PR' → 'This function' for long-term documentation
- Add optional field name parameter to coerceUsageCount for debug logging
- Log hostile values via debugLogger.warn when coercion fires
- Coerce candidatesTokenCount (was missing despite JSDoc mentioning it)
- Build sanitized usageMetadata with coerced values for recordAssistantTurn
  so JSONL persistence and --resume don't re-poison the compaction gate

* fix(core): reuse coerced usage values in recordAssistantTurn

The streaming loop was calling coerceUsageCount twice for the same
usageMetadata: once for telemetry updates and again inline when building
the tokens object for recordAssistantTurn. This left candidatesTokenCount
declared but unused in the first block (TS6133).

Now stashes all four coerced values in a coercedUsage object during the
streaming loop, then spreads it into the tokens object when recording.
This eliminates the duplicate coercion calls and uses candidatesTokenCount
consistently.

Resolves review thread: PRRT_kwDOPB-92c6Ed4WT

* test(core): assert debugLogger.warn for hostile usage counts

Address PR QwenLM#4439 review thread on geminiChat.test.ts: the hostile-provider
parametrized test asserted token-count coercion behaviour but never verified
the operator-facing diagnostic emitted by `coerceUsageCount`. A future
refactor could remove or misformat the warning with no test failure.

- Mock `createDebugLogger` via vi.hoisted/vi.mock so the module-level
  `debugLogger` in geminiChat.ts routes warnings to a spy.
- Inside the existing it.each, assert that hostile defined values
  (NaN/Infinity/-Infinity/negative/string) emit warns mentioning both
  `hostile promptTokenCount` and `hostile totalTokenCount`, and that the
  stringified bad value is included so logs are actionable.
- Add a negative assertion that the field-omitted cases (null, undefined)
  do NOT trigger any warn — verifying the `value != null` guard.
…ell subprocesses (QwenLM#4649)

* feat(core): inject context env vars (session/agent/prompt ID) into shell subprocesses

When SubAgents execute SQL or Python scripts via Bash tool, the scripts
have no way to know their execution context. This adds automatic injection
of QWEN_CODE_SESSION_ID, QWEN_CODE_AGENT_ID, and QWEN_CODE_PROMPT_ID
into all shell subprocess environments, enabling downstream scripts to
perform trace correlation, audit logging, and business context attribution.

Closes QwenLM#4645

* fix(core): use module-level flag to guard session env claim

Prevents nested qwen-code processes from inheriting the parent's
session ID. The previous `if (!process.env[...])` check would keep
the parent's value; a module-level flag ensures each process claims
its own session ID on first Config construction.

* fix(test): use bracket notation for index signature properties

CI tsc --build enforces noPropertyAccessFromIndexSignature; use
env['KEY'] instead of env.KEY to satisfy strict type checking.

* fix(core): guard process.env assignment for mocked process environments

Some test suites mock node:process without providing env, causing
TypeError when Config constructor assigns QWEN_CODE_SESSION_ID.
Add defensive check before env writes.

* test(config): add coverage for sessionEnvClaimed guard

Addresses reviewer feedback (wenshao) requesting test coverage for the
module-level `sessionEnvClaimed` guard in Config constructor.

Tests verify:
1. First Config instance sets process.env['QWEN_CODE_SESSION_ID']
2. Subsequent Config instances do not overwrite the env var

* test(config): add startNewSession env var test and clarify comment

- Add test verifying startNewSession updates process.env to new session ID
- Add comment explaining why startNewSession bypasses sessionEnvClaimed guard
  (only callable on the canonical Config instance that already claimed)
* feat(core): add auto-mode denial observability

* fix(core): prune unused auto denial reason

* fix(core): scope auto fallback counter resets

* test(core): cover denied fallback cancellation

* fix(core): tighten auto-mode denial fallback tracking

* test(core): cover permission denied hook events

* fix(core): preserve auto fallback reasons

* test(core): cover auto mode denial helpers

* fix(core): reset auto fallback after hook approval

* fix(core): log auto fallback reset recovery

* fix(core): clarify auto fallback reset logging

* test(core): assert auto fallback reset logging
QwenLM#4654)

* feat(core): auto-dump memory diagnostics to disk on pressure detection

When the MemoryPressureMonitor (QwenLM#4403) detects hard or critical pressure,
write a lightweight diagnostics JSON to .qwen/<project>/diagnostics/ before
running cleanup. The file survives even if a subsequent operation triggers
OOM, giving maintainers actionable data from bug reports without requiring
the user to manually run /doctor memory after a crash.

Design follows Claude Code's heapDumpService approach: write the cheap JSON
first (small write, won't OOM), heavy snapshot second. Diagnostics include
process memory stats, V8 heap stats, session history size, and an actionable
suggestion for the user.

Per-session limits: max 3 dumps, 30s cooldown between dumps.

Closes QwenLM#4651

* ci: retrigger CI after Windows flaky failure

* test(core): use path.join in memoryDiagnosticsDumper test for cross-platform

The assertion hard-coded POSIX separators ('/tmp/test-project/diagnostics/'),
which fails on Windows where path.join produces backslashes. Build the
expected substring with path.join + path.sep so it matches the dumper's
actual output on every platform.

* fix(core): two-phase memory diagnostics write to survive OOM

Two critical issues from review:

1. The async collectMemoryDiagnostics() runs before writeFileSync, but it
   spawns a `ps` subprocess and reads /proc — fork() under critical memory
   pressure can fail or be OOM-killed, leaving no file on disk despite the
   "cheap write first" design comment.

2. dumpCount and lastDumpTime were updated after the await, so concurrent
   dumps (e.g. hard→critical escalation) would both pass the cap/cooldown
   guards and overwrite each other.

Fix:

- Reserve the dump slot synchronously (++dumpCount, lastDumpTime) before
  any await, so concurrent calls correctly hit the cap.
- Phase 1: synchronously write a minimal JSON (process.memoryUsage +
  v8.getHeapStatistics, no fork/exec) with collectionComplete=false.
  Because async functions execute synchronously up to the first await,
  this is guaranteed on disk before the caller's next statement runs.
- Phase 2: enrich with full diagnostics asynchronously and overwrite the
  file with collectionComplete=true. If Phase 2 crashes, the minimal
  Phase 1 file still survives for debugging.

Tests updated for the two-phase write and gain two new cases covering the
sync-Phase-1 guarantee and the synchronous slot reservation.

* fix(core): point memory diagnostics suggestion at /compress (the actual command)

The suggestion text told users to run /compact, which does not exist in
this repository — the actual command is /compress (see compressCommand.ts).
Pointing users at a nonexistent slash command in a diagnostics report
makes the suggestion unactionable.
Merges upstream changes from QwenLM/qwen-code into HopCode, resolving
all branding conflicts (HopCode/@hoptrendy/hopcode-core vs Qwen Code/@qwen-code/qwen-code-core).

Key upstream changes adopted:
- Virtual viewport / VirtualizedList for large conversation histories
- Hooks UI overhaul: matcher-aware routing (HookEventMatcherListStep / HookEventHandlerListStep)
- New hook events: PostCompact, StopFailure; hookEventSupportsMatcher API
- Shell context env vars: getShellContextEnvVars() in hookRunner
- Memory diagnostics improvements
- AUTO mode improvements
- Cleanup housekeeping: general.cleanupPeriodDays setting
- Status line: respectUserColors + hideContextIndicator options
- /simplify bundled skill added
- Qualitative.tsx: conditional hasFeatureSuggestions / hasUsagePatterns guards
- docs-site updates and NavToc configurable sections

Branding preserved:
- Package names: @hoptrendy/hopcode-core
- Env vars: HOPCODE_PROJECT_DIR, HOPCODE_EMIT_TOOL_USE_SUMMARIES
- Paths: ~/.hopcode/, .hopcode/
- Skill exclusion: .hopcode dirs not misidentified as bundled skill dirs

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 2, 2026 09:20
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@TaimoorSiddiquiOfficial, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 18 minutes and 10 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 70b40a4d-9b64-4772-a197-a1a024449faf

📥 Commits

Reviewing files that changed from the base of the PR and between 82be410 and 42385a1.

📒 Files selected for processing (1)
  • packages/cli/src/ui/components/hooks/HooksManagementDialog.test.tsx
📝 Walkthrough

Walkthrough

Adds virtualized terminal viewport and input handling, matcher-grouped hooks UI, background housekeeping scheduler and diagnostics, trace capture/normalize/compare tooling, AUTO-mode denial-tracking refinements, shell-context env propagation, defensive core fixes (token coercion, atomic write ownership), extensive tests, and documentation/site updates.

Changes

CLI UI, Core, and Alignment Tooling

Layer / File(s) Summary
Virtual viewport and input plumbing
packages/cli/src/ui/components/shared/*, packages/cli/src/ui/components/MainContent.tsx, packages/cli/src/config/keyBindings.ts, packages/cli/src/ui/hooks/*
Introduces VirtualizedList/ScrollableList, StaticRender, animated scrollbar, batched scroll, mouse event parsing & useMouseEvents, integrates virtual viewport behind ui.useTerminalBuffer, and keybinding additions for viewport scrolling.
Hooks management refactor
packages/cli/src/ui/components/hooks/*, packages/cli/src/ui/components/hooks/matcherGrouping.ts, packages/cli/src/ui/components/hooks/sourceLabels.ts
Refactors hooks UI to matcher-grouped flow (matcher list/detail, handler list), adds matcher-group utilities, source label helpers, new types, and updated keyboard/navigation logic and tests.
Background housekeeping and diagnostics
packages/cli/src/utils/housekeeping/*, packages/cli/src/gemini.tsx, packages/core/src/services/memoryDiagnosticsDumper.*
Adds throttled runOnce, cleanupOldFileHistoryBackups, scheduler/startBackgroundHousekeeping, last-interaction tracking, memory diagnostics dumper with two-phase writes, and starts scheduler on interactive CLI.
Permissions and AUTO-mode updates
packages/core/src/permissions/*, packages/cli/src/acp-integration/session/Session.ts, packages/core/src/core/coreToolScheduler.ts
Introduces typed fallback reasons, total-denial cap, formatDenialStateLog, isDenialFallbackReason, tracks auto-mode fallback callIds, and resets denial counters when appropriate; also uses shallower history reads for some flows.
Trace capture and alignment tooling
.qwen/skills/agent-reproduce-*/*
Adds mitm proxy addon, run-with-mitm and tmux capture scripts, state snapshot/diff, normalize_trace.py and compare_traces.py, and orchestration scripts for paired captures and alignment docs.
Shell context env propagation
packages/core/src/utils/shellContextEnv.ts, packages/core/src/hooks/hookRunner.ts, packages/core/src/services/shellExecutionService.ts, packages/core/src/tools/monitor.ts
Adds getShellContextEnvVars() and injects session/agent/prompt env vars into spawned shells and hook child processes.
Defensive core behaviors
packages/core/src/core/geminiChat.ts, packages/cli/src/services/insight/generators/DataProcessor.ts, packages/cli/src/serve/httpAcpBridge.ts, packages/core/src/tools/mcp-client.ts, packages/core/src/utils/atomicFileWrite.ts
Coerces hostile token counts, normalizes cached insight facets, adds find/detach helpers for ACP bridge, adds Streamable HTTP compatibility fetch wrapper, and makes atomicWriteFile ownership-aware.
Docs, site gating, and tests
docs-site/*, docs/*, many packages/*/*.test.*
Updates docs and README, adds public-docs gating and tests, design doc for virtual viewport, settings schema/docs updates, and broad test additions across modules to cover new behavior.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant Mitm as mitmdump
  participant Normalizer as normalize_trace.py
  participant Comparator as compare_traces.py

  User->>CLI: run_pair_capture.sh (ref_cmd, qwen_cmd)
  CLI->>Mitm: start mitmdump with llm_dump.py
  Mitm-->>Normalizer: write http.jsonl
  CLI->>Normalizer: normalize reference/http.jsonl
  CLI->>Normalizer: normalize qwen/http.jsonl
  Normalizer->>Comparator: produce normalized JSONs
  Comparator-->>CLI: trace.diff (pass/fail)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A rabbit scrolls and tidies code, 🐇
Virtual views on history's road.
Hooks grouped by matchers, neat and kind,
Housekeeping hums in background mind.
Traces normalized, diffs align—hip hop!

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch merge/upstream-qwen-sync

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 322a162b06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

import { Box, Text } from 'ink';
import { theme } from '../../semantic-colors.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import { HookType } from '@qwen-code/qwen-code-core';

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use the HopCode core package name

This new file imports from @qwen-code/qwen-code-core, but this workspace only declares and maps @hoptrendy/hopcode-core in packages/cli/package.json and packages/cli/tsconfig.json. The same upstream package name appears in the new housekeeping and virtual-list files, so a normal CLI build/package install will fail module resolution before the CLI can start; switch these new imports to the HopCode core package name used elsewhere in packages/cli/src.

Useful? React with 👍 / 👎.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Syncs 19 upstream commits from QwenLM/qwen-code into HopCode, bringing in new UI/UX features (hooks UI + virtualized conversation viewport), new housekeeping/retention behavior, and additional bundled skills—while adapting changes to HopCode’s branding and package layout.

Changes:

  • Adds new settings + documentation for terminal-buffer virtualization and file-history cleanup retention.
  • Introduces shell subprocess context env var injection for tracing (session/agent/prompt) and updates monitor tool to pass them through.
  • Adds bundled /simplify skill and updates skill manager tests to include it.

Reviewed changes

Copilot reviewed 137 out of 138 changed files in this pull request and generated 17 comments.

Show a summary per file
File Description
packages/vscode-ide-companion/schemas/settings.schema.json Adds/updates settings schema entries (cleanup retention, terminal buffer virtualization, status line options).
packages/core/src/utils/shellContextEnv.ts New helper to inject context env vars into spawned shell subprocesses.
packages/core/src/utils/shellContextEnv.test.ts Unit tests for the new shell context env helper.
packages/core/src/utils/runtimeStatus.ts Updates runtime status file docs to reflect atomicWriteJSON behavior.
packages/core/src/utils/atomicFileWrite.ts Enhances atomic write to preserve ownership in more cases (uid-aware fallback).
packages/core/src/tools/monitor.ts Injects shell context env vars into hook subprocess environment.
packages/core/src/skills/skill-manager.test.ts Extends bundled-skill scanning tests to include simplify.
packages/core/src/skills/bundled/simplify/SKILL.md Adds new /simplify bundled skill definition and workflow.
packages/cli/src/config/settingsSchema.ts Adds settings descriptions (incl. cleanup retention + terminal buffer virtualization).
docs/users/reference/keyboard-shortcuts.md Documents virtualized scrolling behavior and selection bypass.
packages/cli/src/ui/components/hooks/HookEventHandlerListStep.tsx Hooks UI step text/flow updates as part of upstream hooks overhaul.
packages/cli/src/ui/components/hooks/HookEventMatcherListStep.tsx Hooks UI step text/flow updates as part of upstream hooks overhaul.
packages/cli/src/ui/components/hooks/matcherGrouping.test.ts Adds/updates matcher grouping test coverage for hooks UI changes.
packages/cli/src/ui/components/hooks/HandlerListBody.test.tsx Hooks handler list UI test updates.
packages/cli/src/ui/components/hooks/HookMatcherDetailStep.test.tsx Hooks matcher detail UI test updates.
packages/cli/src/utils/housekeeping/cleanup.ts Implements cleanup of old file-history backups based on retention settings.
packages/cli/src/utils/housekeeping/throttledOnce.ts Adds/updates “run at most once per day” throttling helper for housekeeping.
packages/cli/src/ui/components/hooks/HandlerListBody.tsx Hooks UI component updates for upstream hooks overhaul.
packages/cli/src/ui/components/hooks/sourceLabels.ts Adds/updates hook source labeling logic.
packages/cli/src/ui/components/hooks/sourceLabels.test.ts Tests for hook source labeling changes.

Comment on lines +9 to +13
import {
Storage,
FILE_HISTORY_DIR,
createDebugLogger,
} from '@qwen-code/qwen-code-core';
opts: CleanupOptions,
): Promise<CleanupResult> {
const result: CleanupResult = { removed: 0, errors: 0 };
const root = join(Storage.getGlobalQwenDir(), FILE_HISTORY_DIR);
Comment on lines +7 to +11
import { mkdir, open, stat, unlink, writeFile } from 'node:fs/promises';
import { dirname } from 'node:path';
import { createDebugLogger } from '@qwen-code/qwen-code-core';

const debugLogger = createDebugLogger('HOUSEKEEPING');
Comment on lines +7 to +12
import { Box, Text } from 'ink';
import { theme } from '../../semantic-colors.js';
import { useTerminalSize } from '../../hooks/useTerminalSize.js';
import { HookType } from '@qwen-code/qwen-code-core';
import type { HookConfigDisplayInfo } from './types.js';
import { getConfigSourceDisplay } from './sourceLabels.js';
Comment on lines +7 to +10
import { HooksConfigSource } from '@qwen-code/qwen-code-core';
import type { HookConfigDisplayInfo } from './types.js';
import { getTranslatedSourceDisplayMap } from './constants.js';
import { t } from '../../../i18n/index.js';
Comment on lines +44 to +48
<Box marginTop={1}>
<Text color={theme.text.secondary}>
{t('To add hooks, edit settings.json directly or ask Qwen.')}
</Text>
</Box>
Comment on lines +50 to +54
<Box minWidth={2}>
<Text
color={isSelected ? theme.text.accent : theme.text.primary}
>
{isSelected ? '❯' : ' '}
Comment on lines +4 to +12
allowedTools:
- agent
- run_shell_command
- grep_search
- read_file
- write_file
- edit
- glob
---
Comment on lines +40 to +44
## Step 2: Launch three review passes in parallel

Use the `agent` tool and launch all review passes in a single response so they run concurrently. Each pass must receive the same review scope and diff command. These passes are read-only: each one inspects and reports findings only and must not modify files — all edits happen later in Step 4.

Keep each review prompt short and focused. Do not paste the full diff into the prompt. Tell each pass to read the diff itself and inspect only files relevant to its findings.
Comment on lines +23 to +38
export function getShellContextEnvVars(): Record<string, string> {
const env: Record<string, string> = {};

const sessionId = process.env['QWEN_CODE_SESSION_ID'];
if (sessionId) {
env['QWEN_CODE_SESSION_ID'] = sessionId;
}

// For agent/prompt IDs: explicitly set empty string when no ALS context
// exists, so that stale values inherited from a parent qwen-code process
// (via process.env spread) are overwritten rather than leaked.
const agentId = getCurrentAgentId();
env['QWEN_CODE_AGENT_ID'] = agentId ?? '';

const promptId = promptIdContext.getStore();
env['QWEN_CODE_PROMPT_ID'] = promptId ?? '';

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
docs-site/README.md (1)

9-9: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix Node.js prerequisite in docs-site/README.md (line 9) to match Next.js 16

docs-site/README.md says Node.js 18+, but the app depends on next@^16.0.8, and Next.js 16.0.x requires Node.js 20.9+ (minimum supported). Update the setup prerequisites accordingly to avoid contributor install failures.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-site/README.md` at line 9, Update the Node.js prerequisite string
"Node.js 18+" in the README (the line containing that exact text) to "Node.js
20.9+" to match the project's Next.js dependency (next@^16.0.8); ensure any
adjacent setup notes or install commands referencing Node version are consistent
with Node.js 20.9+ and, if present, add a brief note that Next.js 16 requires
Node 20.9 or newer.
packages/cli/src/ui/commands/btwCommand.test.ts (1)

173-190: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert the tail-history API is the one actually used.

Right now these tests pass even if the implementation falls back to getHistory(), because both mocks return the same data. Please add assertions that getHistoryTail(40, true) is called and getHistory() is not, so this change really guards the new path.

As per coding guidelines, "Write tests for all new features and bug fixes" and "Ensure tests cover edge cases and error handling".

Also applies to: 232-247

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/commands/btwCommand.test.ts` around lines 173 - 190, The
tests currently mock both geminiClient.getHistory and getHistoryTail with
identical return values, so add explicit assertions that the tail API is used:
after exercising the code, assert that geminiClient.getHistoryTail was called
with (40, true) and that geminiClient.getHistory was not called; do the same for
the other test block referenced (the one around the second mock group). Locate
the mocks for geminiClient and the test cases in btwCommand.test.ts and add
vi.expect/expect assertions for getHistoryTail and getHistory to ensure the
implementation actually calls getHistoryTail(40, true) and never falls back to
getHistory.
packages/core/src/core/geminiChat.ts (1)

2678-2717: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Zero-valued coercions never clear the previous token state.

When hostile counts are coerced to 0, these truthy guards skip the assignment, so this.lastPromptTokenCount and lastCachedContentTokenCount keep their previous non-zero values. That means the next send can still make compaction decisions from stale metadata even though this response was explicitly sanitized.

Suggested fix
           coercedUsage = {
             promptTokenCount,
             totalTokenCount,
             candidatesTokenCount,
             cachedContentTokenCount,
           };
           const lastPromptTokenCount = promptTokenCount || totalTokenCount;
-          if (lastPromptTokenCount) {
-            // Always update the per-chat counter so this chat (including
-            // subagents) can make its own compaction decisions.
-            this.lastPromptTokenCount = lastPromptTokenCount;
-            // Mirror to the global telemetry only when wired — subagents
-            // pass `telemetryService=undefined` to keep their context usage
-            // out of the main session's UI counters.
-            this.telemetryService?.setLastPromptTokenCount(
-              lastPromptTokenCount,
-            );
-          }
-          if (cachedContentTokenCount && this.telemetryService) {
-            this.telemetryService.setLastCachedContentTokenCount(
-              cachedContentTokenCount,
-            );
-          }
+          this.lastPromptTokenCount = lastPromptTokenCount;
+          this.telemetryService?.setLastPromptTokenCount(lastPromptTokenCount);
+          this.telemetryService?.setLastCachedContentTokenCount(
+            cachedContentTokenCount,
+          );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/core/geminiChat.ts` around lines 2678 - 2717, The bug is
that falsy zero values from coerceUsageCount are skipped by truthy checks,
leaving previous token counters stale; update the guards to check for
null/undefined instead of truthiness so zeros are preserved: when handling
lastPromptTokenCount (the local variable) assign this.lastPromptTokenCount
whenever lastPromptTokenCount != null (not using if (lastPromptTokenCount)), and
call this.telemetryService.setLastPromptTokenCount only when telemetryService
exists (preserve the telemetryService? pattern) but still allow zero to be
passed; do the same for cachedContentTokenCount and
setLastCachedContentTokenCount — i.e., replace truthy checks with null/undefined
checks around lastPromptTokenCount and cachedContentTokenCount while keeping
coercedUsage, coerceUsageCount, and telemetryService references intact.
packages/core/src/skills/skill-manager.test.ts (1)

1063-1086: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Assert simplify.level in the precedence tests too.

These two cases only verify that simplify survives deduplication, not that it still reports level === 'bundled'. Adding that assertion would catch source-metadata regressions in the shadowing path.

As per coding guidelines, "Write tests for all new features and bug fixes" and "Ensure tests cover edge cases and error handling".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/skills/skill-manager.test.ts` around lines 1063 - 1086, Add
an assertion that the surviving 'simplify' skill still reports the expected
source level in both precedence tests: after obtaining skills from
manager.listSkills({ force: true }) in the "should prioritize project-level over
bundled skills with same name" and "should prioritize user-level over bundled
skills with same name" tests (which use mockReaddirForLevels and
setupReviewSkillMocks), assert that the skill with name 'simplify' has level ===
'bundled' to ensure shadowing preserves source metadata.
🟠 Major comments (29)
.qwen/skills/agent-reproduce-feature/scripts/run_tmux_capture.sh-25-34 (1)

25-34: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Keep the pane alive long enough to capture short-lived commands.

A detached tmux session exits as soon as COMMAND finishes, so after the default 2-second settle a quick command like echo hi is usually gone and Line 34 fails with “can't find pane/session”. Please enable remain-on-exit or wrap the command so the pane survives until capture completes.

Possible fix
 tmux new-session -d -s "${session}" "$@"
+tmux set-option -t "${session}" remain-on-exit on
 cleanup() {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-feature/scripts/run_tmux_capture.sh around
lines 25 - 34, The detached tmux session may exit before capture, causing "can't
find pane/session"; modify the session creation in run_tmux_capture.sh so the
pane survives until capture—either start the session with remain-on-exit enabled
(use tmux option remain-on-exit for the created session) or wrap the user
command so it blocks until capture completes (e.g., run a shell that executes
"$@" then sleeps or waits on a sentinel); ensure the change is applied where
tmux new-session -d -s "${session}" "$@" is invoked and keep cleanup(), trap
cleanup EXIT and tmux capture-pane -t "${session}" -p -S - >
"${out_dir}/tmux-pane.txt" intact.
packages/cli/src/services/insight/generators/DataProcessor.ts-164-168 (1)

164-168: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Normalize the same helpfulness key that the analysis schema requests.

analyzeSession() asks the model for HOPCODE_helpfulness, but this normalizer only reads Qwen_helpfulness. In the real path that means every freshly generated facet falls back to 'moderately_helpful', so the helpfulness metric is silently lost before caching and aggregation.

Possible fix
-    Qwen_helpfulness: normalizeInsightEnum(
-      rawFacet['Qwen_helpfulness'],
+    Qwen_helpfulness: normalizeInsightEnum(
+      rawFacet['HOPCODE_helpfulness'] ?? rawFacet['Qwen_helpfulness'],
       QWEN_HELPFULNESS_LEVELS,
       'moderately_helpful',
     ),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/services/insight/generators/DataProcessor.ts` around lines
164 - 168, The normalizer in DataProcessor.ts is reading
rawFacet['Qwen_helpfulness'] but analyzeSession() produces
'HOPCODE_helpfulness', causing value loss; update the normalization for
Qwen_helpfulness to pull the actual key used by the analysis schema (read
rawFacet['HOPCODE_helpfulness'] instead of rawFacet['Qwen_helpfulness'], or
defensively check both keys and prefer HOPCODE_helpfulness) when calling
normalizeInsightEnum(..., QWEN_HELPFULNESS_LEVELS, 'moderately_helpful'); ensure
this change is applied where Qwen_helpfulness is constructed so
normalizeInsightEnum receives the real helpfulness value.
docs-site/scripts/link-public-docs.mjs-6-16 (1)

6-16: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Resolve script paths from the module, not process.cwd().

These paths are all cwd-relative today. Running node docs-site/scripts/link-public-docs.mjs from the repo root will delete/create the wrong content/ directory and then miss ../docs/.... Anchor everything to import.meta.url so the script behaves the same regardless of where it is invoked from.

Suggested fix
 import { cp, mkdir, rm, symlink } from 'node:fs/promises';
-import { join } from 'node:path';
+import { dirname, join, resolve } from 'node:path';
+import { fileURLToPath } from 'node:url';
 
 import { PUBLIC_DOC_ROOTS } from '../src/app/public-docs.js';
 
-const contentDir = 'content';
+const scriptDir = dirname(fileURLToPath(import.meta.url));
+const docsSiteDir = resolve(scriptDir, '..');
+const repoDocsDir = resolve(docsSiteDir, '..', 'docs');
+const contentDir = resolve(docsSiteDir, 'content');
 
 async function linkPublicDocs() {
   try {
     await rm(contentDir, { force: true, recursive: true });
     await mkdir(contentDir);
-    await cp('../docs/index.md', join(contentDir, 'index.md'));
-    await cp('../docs/_meta.ts', join(contentDir, '_meta.ts'));
+    await cp(resolve(repoDocsDir, 'index.md'), join(contentDir, 'index.md'));
+    await cp(resolve(repoDocsDir, '_meta.ts'), join(contentDir, '_meta.ts'));
 
     for (const root of PUBLIC_DOC_ROOTS) {
-      await symlink(join('..', '..', 'docs', root), join(contentDir, root));
+      await symlink(resolve(repoDocsDir, root), join(contentDir, root));
     }
   } catch (error) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs-site/scripts/link-public-docs.mjs` around lines 6 - 16, The script uses
cwd-relative paths causing wrong files to be manipulated; in linkPublicDocs
change path resolution to be anchored to the script module by deriving a baseDir
from import.meta.url (e.g., using fileURLToPath and dirname) and then compute
contentDir and docs paths from that baseDir instead of relying on process.cwd();
update the uses of contentDir, the cp source paths ('../docs/index.md',
'../docs/_meta.ts') and the symlink target join('..','..','docs', root) to use
path.join(baseDir, ...) or a docsDir variable so all rm/mkdir/cp/symlink
operations reference resolved absolute paths, and keep PUBLIC_DOC_ROOTS
iteration but join each root against the resolved docsDir.
packages/cli/src/ui/components/hooks/sourceLabels.test.ts-8-8 (1)

8-8: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use the branded core package import here.

This test still pulls enums from @qwen-code/qwen-code-core, but the PR objective says the upstream sync should preserve HopCode package names. Leaving the upstream package here can break install/typecheck in the branded workspace.

Suggested fix
-import { HooksConfigSource, HookType } from '`@qwen-code/qwen-code-core`';
+import { HooksConfigSource, HookType } from '`@hoptrendy/hopcode-core`';

Verify that this workspace no longer depends on the upstream package name and that this import is just a leftover:

#!/bin/bash
set -euo pipefail

rg -n '`@qwen-code/qwen-code-core`|`@hoptrendy/hopcode-core`' \
  --glob 'package.json' \
  --glob '*.ts' \
  --glob '*.tsx'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/hooks/sourceLabels.test.ts` at line 8, The
test imports enums from the upstream package name; replace the import source so
it uses the branded core package instead: change the import that brings in
HooksConfigSource and HookType to import them from '`@hoptrendy/hopcode-core`'
(ensuring the named symbols HooksConfigSource and HookType remain unchanged) and
run the workspace search to confirm no other references to
'`@qwen-code/qwen-code-core`' remain.
packages/cli/src/ui/components/hooks/HookMatcherDetailStep.test.tsx-9-13 (1)

9-13: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace upstream @qwen-code/qwen-code-core imports with @hoptrendy/hopcode-core in hook tests

packages/cli/src/ui/components/hooks/HookMatcherDetailStep.test.tsx still imports the enums from @qwen-code/qwen-code-core; this should come from the branded @hoptrendy/hopcode-core. rg also found remaining @qwen-code/qwen-code-core imports in sourceLabels.test.ts, matcherGrouping.test.ts, and HandlerListBody.test.tsx.

Suggested fix
 import {
   HookEventName,
   HooksConfigSource,
   HookType,
-} from '`@qwen-code/qwen-code-core`';
+} from '`@hoptrendy/hopcode-core`';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/hooks/HookMatcherDetailStep.test.tsx` around
lines 9 - 13, The tests import HookEventName, HooksConfigSource, and HookType
from the wrong package; update the import source in
HookMatcherDetailStep.test.tsx (and the other listed tests:
sourceLabels.test.ts, matcherGrouping.test.ts, HandlerListBody.test.tsx) to
import these enums from `@hoptrendy/hopcode-core` instead of
`@qwen-code/qwen-code-core`; locate the import statements that reference
HookEventName, HooksConfigSource, or HookType and change only the package
specifier to `@hoptrendy/hopcode-core` so the symbols remain the same but come
from the branded core package.
packages/cli/src/ui/components/hooks/matcherGrouping.test.ts-8-12 (1)

8-12: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace @qwen-code/qwen-code-core import with @hoptrendy/hopcode-core.

packages/cli/src/ui/components/hooks/matcherGrouping.test.ts imports HookEventName, HooksConfigSource, and HookType from @qwen-code/qwen-code-core, but this workspace doesn’t have that package as a dependency and doesn’t alias it in packages/cli/tsconfig.json or packages/cli/vitest.config.ts, so the import can fail to resolve/typecheck.

Suggested fix
 import {
   HookEventName,
   HooksConfigSource,
   HookType,
-} from '`@qwen-code/qwen-code-core`';
+} from '`@hoptrendy/hopcode-core`';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/hooks/matcherGrouping.test.ts` around lines 8
- 12, The test imports HookEventName, HooksConfigSource, and HookType from the
wrong package; update the import source in
packages/cli/src/ui/components/hooks/matcherGrouping.test.ts to import those
symbols from "`@hoptrendy/hopcode-core`" instead of "`@qwen-code/qwen-code-core`"
(update the import statement that references HookEventName, HooksConfigSource,
HookType), then run typecheck/tests to confirm the symbols resolve correctly.
packages/core/src/services/memoryDiagnosticsDumper.ts-67-132 (1)

67-132: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Freeze session-scoped fields before the first await.

resetForNewSession() can run while collectMemoryDiagnostics() is in flight. Line 128 then re-reads this.collectSessionStats() from the new session and overwrites the old dump file with mixed-session metadata. Capture the session stats once up front (or guard phase 2 with a dumper generation/session token) so a pressure event from session A cannot be rewritten with session B state.

Suggested fix
   async dump(
     trigger: 'hard' | 'critical',
   ): Promise<MemoryDumpResult | undefined> {
@@
     try {
       const diagnosticsDir = this.ensureDiagnosticsDir();
       const sessionId = this.config.getSessionId();
+      const sessionStats = this.collectSessionStats();
       const timestamp = new Date()
         .toISOString()
         .replace(/:/g, '-')
         .replace(/\./g, '_');
@@
       const minimalPayload = {
         trigger,
         dumpNumber,
         timestamp: new Date().toISOString(),
         memoryUsage: process.memoryUsage(),
         v8HeapStats: v8.getHeapStatistics(),
-        session: this.collectSessionStats(),
+        session: sessionStats,
         suggestion: this.getSuggestion(trigger),
         collectionComplete: false,
       };
@@
       const fullPayload = {
         trigger,
         dumpNumber,
         ...diagnostics,
-        session: this.collectSessionStats(),
+        session: sessionStats,
         suggestion: this.getSuggestion(trigger),
         collectionComplete: true,
       };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/services/memoryDiagnosticsDumper.ts` around lines 67 - 132,
The dump() implementation currently calls collectMemoryDiagnostics() and then
re-reads session-scoped data (this.collectSessionStats(), this.getSuggestion())
after the await, allowing resetForNewSession() to change session state and
corrupt the file; fix by capturing all session-scoped fields before the await
(e.g. call and store sessionStats = this.collectSessionStats(), suggestion =
this.getSuggestion(trigger), sessionId = this.config.getSessionId(), qwenVersion
= this.config.getCliVersion() prior to calling collectMemoryDiagnostics()) and
then use those captured values when building fullPayload, or alternatively add a
dumper-generation token checked before writing Phase 2 to ensure the same
session that started the dump is still active; update references in dump(),
collectMemoryDiagnostics() call site, and where fullPayload is assembled (use
the frozen variables instead of re-calling
this.collectSessionStats()/this.getSuggestion()).
packages/core/src/services/backgroundShellRegistry.ts-424-490 (1)

424-490: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Only mark a shell as notified after delivery succeeds.

Right now a missing callback or a thrown callback still flips entry.notified to true, so that terminal transition is dropped forever. Since this feature is the only completion side-channel for background shells, a transient delivery failure becomes permanent data loss.

Suggested fix
   private emitNotification(entry: ShellTask): void {
     if (entry.notified) return;
-    entry.notified = true;
 
     if (!this.notificationCallback) {
       debugLogger.debug(
         `Notification dropped for shell ${entry.shellId}: no callback registered`,
       );
@@
     try {
       this.notificationCallback(displayText, xmlParts.join('\n'), meta);
+      entry.notified = true;
     } catch (error) {
       debugLogger.error('Failed to emit shell notification:', error);
     }
   }

If you want late subscribers to recover missed events too, setNotificationCallback() should also sweep terminal !notified entries and emit them on registration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/services/backgroundShellRegistry.ts` around lines 424 -
490, emitNotification currently sets entry.notified = true before delivery,
causing lost terminal notifications when delivery fails or no callback is
registered; change emitNotification so it does not mark entry.notified until
after a successful invocation of this.notificationCallback (i.e., verify
this.notificationCallback exists, call it inside try/catch, and only set
entry.notified = true after the call completes without throwing), and ensure
that if no callback is registered you do not flip notified; additionally, update
setNotificationCallback (or on registering a callback) to sweep existing
ShellTask entries where !notified and call emitNotification for each so late
subscribers receive missed terminal events.
packages/cli/src/utils/housekeeping/throttledOnce.ts-53-62 (1)

53-62: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Stale-lock takeover can steal an actively running task.

The lock file’s mtime is never refreshed after acquisition, so any task that runs longer than staleLockMs can have its live lock unlinked by a second process and execute twice. That violates the cross-process exclusivity this helper promises. Please switch this to a renewable lease/heartbeat, or store owner metadata and only steal locks from definitively dead processes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/utils/housekeeping/throttledOnce.ts` around lines 53 - 62,
The stale-lock takeover currently unlinks opts.lockPath based solely on mtime
and can steal locks from active tasks; update the locking in tryAcquire/where
lock is created to write owner metadata (e.g., PID and a heartbeat timestamp)
into the lock file and either (a) refresh that heartbeat periodically while the
owner task runs or (b) on takeover, verify the owner is dead (e.g., check PID
liveness) before unlinking; ensure the staleLockMs check uses the heartbeat
timestamp from the lock file (not stale mtime), and only perform
unlink/tryAcquire when verification fails to confirm the original process is not
alive.
packages/cli/src/utils/housekeeping/cleanup.ts-56-61 (1)

56-61: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Propagate unexpected root scan failures instead of treating them as a successful pass.

If readdir(root) fails with anything other than ENOENT, this function logs and returns a normal { removed: 0, errors: 0 } result. In scheduler.ts, that means runThrottledOnce() still records the housekeeping marker, so retries are suppressed for the next interval even though nothing was scanned. Please let unexpected root access failures reject (or surface them distinctly to the caller) so the pass is not marked successful.

Suggested direction
   try {
     entries = await readdir(root, { withFileTypes: true });
   } catch (e) {
     if (isENOENT(e)) return result;
-    debugLogger.error('readdir failed', e);
-    return result;
+    debugLogger.error('readdir failed', e);
+    throw e;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/utils/housekeeping/cleanup.ts` around lines 56 - 61, The
catch in the cleanup routine that calls readdir(root, { withFileTypes: true })
currently logs unexpected errors and returns a normal result; instead, after
checking if isENOENT(e) and returning the empty result, rethrow any other errors
so callers (e.g., scheduler.ts's runThrottledOnce) can detect and handle scan
failures; keep the debugLogger.error call but follow it with throw e for
non-ENOENT exceptions so the pass is not marked successful.
packages/cli/src/ui/components/shared/VirtualizedList.tsx-522-540 (1)

522-540: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Add a row-level ErrorBoundary around each item’s rendered content (VirtualizedList.tsx ~522-540)

  • The current try/catch only guards the synchronous renderItem(...) call; it won’t catch exceptions thrown later while React renders the returned subtree.
  • VirtualizedListItem renders {content} directly with no error boundary, so a render-time failure can still unmount the whole list.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/shared/VirtualizedList.tsx` around lines 522 -
540, The per-item try/catch only catches synchronous errors from renderItem but
not errors thrown later during React rendering, so add a row-level ErrorBoundary
class (e.g., ItemErrorBoundary) and wrap each item's rendered output with it
(where VirtualizedListItem renders {content}); on error the boundary should log
via debugLogger.debug(`renderItem threw at index ${i}`, err) and render the same
fallback Box/Text ("[render error]") to preserve the viewport and avoid leaking
details. Ensure the ErrorBoundary accepts an index prop to include in logs and
is used around the result of renderItem({ item, index: i }) instead of relying
solely on the try/catch.
packages/web-templates/src/insight/src/App.tsx-161-164 (1)

161-164: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The feature gate is checking the wrong branded field name.

This looks for Qwen_md_additions, but the branded renderer path uses Hopcode_md_additions. If a report only contains HOPCODE.md suggestions, showFeatures stays false and the Improvements section never renders. Qualitative.tsx's hasFeatureSuggestions check needs the same rename.

Suggested change
   const showFeatures =
     !!data.qualitative &&
-    (hasMeaningfulArray(data.qualitative.improvements?.Qwen_md_additions) ||
+    (hasMeaningfulArray(data.qualitative.improvements?.Hopcode_md_additions) ||
       hasMeaningfulArray(data.qualitative.improvements?.features_to_try));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/web-templates/src/insight/src/App.tsx` around lines 161 - 164, The
feature-gate is checking the wrong branded field: change references of
Qwen_md_additions to Hopcode_md_additions so the Improvements section renders
when only HOPCODE.md suggestions exist; update the conditional assigning
showFeatures (replace data.qualitative.improvements?.Qwen_md_additions) and the
helper hasFeatureSuggestions in Qualitative.tsx to check
data.qualitative.improvements?.Hopcode_md_additions instead, keeping the
existing hasMeaningfulArray validation and logic intact.
.qwen/skills/agent-reproduce-align/scripts/normalize_trace.py-190-192 (1)

190-192: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stream the trace file instead of reading it all at once.

read_text().splitlines() loads the entire capture into memory before you normalize anything. Large MITM traces can get big enough to make this tool slow or fail outright.

Suggested change
 def normalize(path: Path) -> dict[str, Any]:
     requests = []
-    for line_num, line in enumerate(path.read_text(encoding="utf-8").splitlines(), 1):
+    with path.open(encoding="utf-8") as handle:
+        for line_num, line in enumerate(handle, 1):
             if not line.strip():
                 continue
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-align/scripts/normalize_trace.py around lines
190 - 192, The normalize function currently calls path.read_text().splitlines()
which loads the whole file into memory; change it to stream the file by opening
the Path (path.open(encoding="utf-8")) and iterate over the file object with
enumerate(file, 1) so you process one line at a time (preserve line_num usage
and existing logic that consumes each line) to avoid high memory usage for large
traces; update any assumptions about trailing newlines accordingly and ensure
the file is closed (use context manager) while keeping the function signature
normalize(path: Path) unchanged.
.qwen/skills/agent-reproduce-align/scripts/normalize_trace.py-212-218 (1)

212-218: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard nested record shapes before calling .get().

You skip malformed JSON and non-object top-level lines, but a record like {"request": "oops"} still throws here and aborts the whole run. Coerce non-dict request/response values to {} or skip that record with a warning.

Suggested change
-        req = raw.get("request") or {}
-        resp = raw.get("response") or {}
+        req = raw.get("request")
+        resp = raw.get("response")
+        if not isinstance(req, dict) or not isinstance(resp, dict):
+            print(
+                f"Warning: skipping invalid record shape on line {line_num} in {path}",
+                file=sys.stderr,
+            )
+            continue
         parsed = urlparse(req.get("url", ""))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-align/scripts/normalize_trace.py around lines
212 - 218, The request/response extraction in normalize_trace.py still assumes
nested objects and can crash on records like {"request": "oops"}; update the
parsing around the req/resp handling in the trace normalization path to validate
that raw.get("request") and raw.get("response") are dicts before using .get(),
coercing invalid shapes to {} or skipping the record with a warning so the run
continues safely.
packages/cli/src/ui/components/hooks/sourceLabels.ts-7-7 (1)

7-7: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace HooksConfigSource import with the HopCode core package: packages/cli/src/ui/components/hooks/sourceLabels.ts imports HooksConfigSource from @qwen-code/qwen-code-core (line 7), but repo manifests only depend on @hoptrendy/hopcode-core, so this import can break builds / cause enum drift. The same @qwen-code/qwen-code-core import appears in several hooks UI tests/components, so keep them consistent.

Suggested fix
-import { HooksConfigSource } from '`@qwen-code/qwen-code-core`';
+import { HooksConfigSource } from '`@hoptrendy/hopcode-core`';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/hooks/sourceLabels.ts` at line 7, The file
imports the enum HooksConfigSource from the wrong package; replace the import of
HooksConfigSource from '`@qwen-code/qwen-code-core`' with the equivalent from
'`@hoptrendy/hopcode-core`' so the UI component and related hooks/tests use the
repo's actual core package (update the import statement that references
HooksConfigSource in sourceLabels.ts and any other hooks UI files/tests that
import from '`@qwen-code/qwen-code-core`' to instead import from
'`@hoptrendy/hopcode-core`').
packages/cli/src/config/keyBindings.ts-232-238 (1)

232-238: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make Shift+arrow scroll bindings exclusive.

SCROLL_UP/SCROLL_DOWN currently overlap with the existing up/down commands because this matcher system ignores unspecified modifiers. As a result, Shift+Up and Shift+Down still satisfy NAVIGATION_*, SELECTION_*, and COMPLETION_*, so the new viewport scroll commands can be swallowed before they ever run.

Suggested fix
   [Command.NAVIGATION_UP]: [{ key: 'up' }],
-  [Command.NAVIGATION_DOWN]: [{ key: 'down' }],
+  [Command.NAVIGATION_DOWN]: [{ key: 'down', shift: false }],

   // Selection-list nav: arrows + k/j + Ctrl+P/Ctrl+N
   // ctrl: false on bare k/j skips Ctrl+K and Ctrl+J
   [Command.SELECTION_UP]: [
-    { key: 'up' },
+    { key: 'up', shift: false },
     { key: 'k', ctrl: false },
     { key: 'p', ctrl: true },
   ],
   [Command.SELECTION_DOWN]: [
-    { key: 'down' },
+    { key: 'down', shift: false },
     { key: 'j', ctrl: false },
     { key: 'n', ctrl: true },
   ],

   // Auto-completion
   [Command.ACCEPT_SUGGESTION]: [{ key: 'tab' }, { key: 'return', ctrl: false }],
   // Completion navigation uses only arrow keys
-  [Command.COMPLETION_UP]: [{ key: 'up' }],
-  [Command.COMPLETION_DOWN]: [{ key: 'down' }],
+  [Command.COMPLETION_UP]: [{ key: 'up', shift: false }],
+  [Command.COMPLETION_DOWN]: [{ key: 'down', shift: false }],

   // History navigation
-  [Command.NAVIGATION_UP]: [{ key: 'up' }],
-  [Command.NAVIGATION_DOWN]: [{ key: 'down' }],
+  [Command.NAVIGATION_UP]: [{ key: 'up', shift: false }],
+  [Command.NAVIGATION_DOWN]: [{ key: 'down', shift: false }],
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/config/keyBindings.ts` around lines 232 - 238, The
Shift+arrow scroll bindings (Command.SCROLL_UP / Command.SCROLL_DOWN) are
currently non-exclusive because unspecified modifiers are ignored, so create
explicit modifier constraints to prevent matching when other modifiers are
present; update the key descriptors for Command.SCROLL_UP and
Command.SCROLL_DOWN to include shift: true and explicitly set ctrl: false, meta:
false, alt: false (and similarly ensure any other scroll bindings like
Command.PAGE_UP, Command.PAGE_DOWN, Command.SCROLL_HOME, Command.SCROLL_END
explicitly declare all modifier booleans where needed) so Shift+Up/Down only
match the intended SCROLL_* handlers and won’t be swallowed by
NAVIGATION_/SELECTION_/COMPLETION_* matchers.
.qwen/skills/agent-reproduce-align/scripts/compare_traces.py-17-21 (1)

17-21: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not collapse duplicate tool names during comparison.

Lines 17-21 reduce tools to a single entry per name, so compare_request() only inspects the last occurrence for any duplicated tool. If both traces contain two tools with the same name but different schemas/required fields, tool_name_counts() still matches and this script can silently miss a real diff.

Compare duplicate names per occurrence instead of overwriting them in a flat dict.

Also applies to: 88-108

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-align/scripts/compare_traces.py around lines 17
- 21, The current tool_index function collapses duplicate tool names into one
entry, losing earlier occurrences; change tool_index (and the similar
construction around lines 88-108) to preserve duplicate tools by occurrence
instead of overwriting by name — e.g., return a list of tools or a dict keyed by
(name, occurrence_index) or otherwise include the occurrence index in the key so
compare_request() and tool_name_counts() iterate and compare tools by
position/occurrence rather than by unique name; update any callers
(compare_request, tool_name_counts) to consume the per-occurrence structure so
differences between tools with identical names are detected.
packages/cli/src/ui/components/MainContent.tsx-101-103 (1)

101-103: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Treat id === 0 as a static history item here too.

The virtual path reserves negative IDs for pending entries, but virtualIsStaticItem uses item.id > 0. That misclassifies completed history row id === 0 as non-static, even though virtualKeyExtractor still treats it as a history item (h-0). The result is an inconsistent contract for the first row whenever zero-based history IDs are present.

Suggested fix
-const virtualIsStaticItem = (item: HistoryItem) => item.id > 0;
+const virtualIsStaticItem = (item: HistoryItem) => item.id >= 0;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/MainContent.tsx` around lines 101 - 103, The
virtual history item classification in MainContent is inconsistent:
`virtualKeyExtractor` already treats `id === 0` as a history entry, but
`virtualIsStaticItem` only returns true for `item.id > 0`. Update
`virtualIsStaticItem` so zero-valued history IDs are also considered static,
keeping it aligned with the `HistoryItem` ID contract and the existing
`virtualKeyExtractor` behavior.
.qwen/skills/agent-reproduce-feature/scripts/run_with_mitm.sh-82-96 (1)

82-96: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Redaction misses common flag-style credentials before writing env.txt.

The sanitizer only catches token literals and KEY=value patterns. Secrets passed as --api-key <secret>, --token <secret>, or bearer headers can still be persisted in clear text via command=${redacted_command}.

🔒 Proposed hardening for command redaction
 redacted_command="$(
   # Note: avoid the GNU-only /I (case-insensitive) sed flag — BSD sed
   # (macOS pre-Sequoia) silently fails to match with /I, so previously
   # `API_KEY=…`, `Secret=…`, etc. would not be redacted on macOS. Use
   # explicit per-letter character classes for the case-insensitive
   # token-name matches; both BSD and GNU sed accept them.
   printf '%q ' "$@" |
     sed -E \
       -e 's/sk-[A-Za-z0-9_-]{12,}/sk-<redacted>/g' \
       -e 's/AKIA[0-9A-Z]{16}/AKIA<redacted>/g' \
       -e 's/AIza[0-9A-Za-z_-]{20,}/AIza<redacted>/g' \
       -e 's/(ghp|gho|ghu|ghs)_[A-Za-z0-9_]{20,}/gh_<redacted>/g' \
       -e 's/github_pat_[A-Za-z0-9_]{20,}/github_pat_<redacted>/g' \
-      -e 's/([A-Za-z0-9_.-]*([Aa][Pp][Ii][-_]?[Kk][Ee][Yy]|[Tt][Oo][Kk][Ee][Nn]|[Ss][Ee][Cc][Rr][Ee][Tt]|[Cc][Rr][Ee][Dd][Ee][Nn][Tt][Ii][Aa][Ll])[A-Za-z0-9_.-]*=)[^[:space:]]+/\1<redacted>/g'
+      -e 's/([A-Za-z0-9_.-]*([Aa][Pp][Ii][-_]?[Kk][Ee][Yy]|[Tt][Oo][Kk][Ee][Nn]|[Ss][Ee][Cc][Rr][Ee][Tt]|[Cc][Rr][Ee][Dd][Ee][Nn][Tt][Ii][Aa][Ll])[A-Za-z0-9_.-]*=)[^[:space:]]+/\1<redacted>/g' \
+      -e 's/(--?[Aa][Pp][Ii][-_]?[Kk][Ee][Yy]|--?[Tt][Oo][Kk][Ee][Nn]|--?[Ss][Ee][Cc][Rr][Ee][Tt]|--?[Pp][Aa][Ss][Ss][Ww][Oo][Rr][Dd])(=|\\[[:space:]]+)[^[:space:]]+/\1\2<redacted>/g' \
+      -e 's/([Aa]uthorization:\\[[:space:]]+[Bb]earer\\[[:space:]]+)[^[:space:]]+/\1<redacted>/g'
 )"

Also applies to: 98-103

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-feature/scripts/run_with_mitm.sh around lines
82 - 96, The redaction in redacted_command misses flag-style secrets (e.g.
--api-key VALUE, --token VALUE) and bearer/header forms, so update the sanitizer
(around redacted_command and the sed -E expressions) to also strip flag/value
pairs and common header formats before writing env.txt: add regexes that match
(case-insensitively) flag names like --api-?key|--token|--secret|--password
followed by a non-space token and replace the value with <redacted>, and add
patterns for Authorization: Bearer <token> and --header 'Authorization: Bearer
...' or -H forms; ensure these new sed rules run after the existing token and
KEY= patterns so all variants are covered.
packages/core/src/core/coreToolScheduler.ts-2295-2297 (1)

2295-2297: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't clear AUTO fallback state before the abort check.

Line 2295 resets fallback tracking based only on outcome, but Lines 2297-2318 can still turn that same confirmation into a cancellation when signal.aborted races in after originalOnConfirm() resolves. That means an aborted approval incorrectly clears the AUTO denial counters even though this path ultimately records the call as cancelled. Move recordAutoModeFallbackResolution() after the cancel/abort branch, or gate it on !signal.aborted.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/core/coreToolScheduler.ts` around lines 2295 - 2297, The
code currently calls recordAutoModeFallbackResolution(callId, outcome) before
checking cancellation, which can clear AUTO fallback counters when
signal.aborted later flips the result to Cancel; update the logic in
coreToolScheduler (around the confirmation handling where originalOnConfirm() is
awaited) to either move the recordAutoModeFallbackResolution(callId, outcome)
call to after the if (outcome === ToolConfirmationOutcome.Cancel ||
signal.aborted) branch so it only runs for final non-cancelled outcomes, or wrap
that call with a guard that checks !signal.aborted before invoking it; ensure
you reference the existing outcome variable, the signal.aborted check, and the
recordAutoModeFallbackResolution(callId, outcome) call so the change is applied
in the same confirmation handling flow.
packages/core/src/config/config.ts-1170-1179 (1)

1170-1179: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Track session-env ownership per instance, not by “first Config wins”.

sessionEnvClaimed makes whichever Config happens to be constructed first the permanent owner of QWEN_CODE_SESSION_ID. If a bootstrap/throwaway instance is created before the real interactive session, the interactive Config never claims the env var, and startNewSession() can later overwrite it from a non-owner instance because ownership is not stored on the instance. That breaks the cross-process/session contract for anything reading this env marker.

Also applies to: 2104-2109

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/config/config.ts` around lines 1170 - 1179, The
module-level sessionEnvClaimed causes the first-constructed Config to
permanently own QWEN_CODE_SESSION_ID; change this to instance-owned tracking by
replacing the module flag with an instance property (e.g.
this.sessionEnvClaimed) in the Config constructor and related methods, set
process.env['QWEN_CODE_SESSION_ID']=this.sessionId only when this instance
claims it and mark this.sessionEnvClaimed=true, and update startNewSession() to
check and honor the instance ownership flag before overwriting the env var (only
allow overwrite if the current instance is the owner or explicitly reclaims it),
so ownership is tracked per Config instance rather than by a global first-wins
flag.
packages/cli/src/ui/components/hooks/matcherGrouping.ts-29-41 (1)

29-41: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t merge mixed sequential and non-sequential handlers into one matcher group.

Right now the group lookup keys only on matcher, so a later sequential: true config upgrades the entire existing group to sequential. That loses the original per-config behavior for same-matcher mixed setups and can make the matcher-detail UI report the wrong execution mode. Key the group on both matcher and sequential, or stop storing sequential at the group level.

Suggested fix
-  let group = hookInfo.matcherGroups.find(
-    (candidate) => candidate.matcher === normalizedMatcher,
-  );
+  let group = hookInfo.matcherGroups.find(
+    (candidate) =>
+      candidate.matcher === normalizedMatcher &&
+      (candidate.sequential ?? false) === normalizedSequential,
+  );
   if (!group) {
     group = {
       matcher: normalizedMatcher,
       sequential: normalizedSequential,
       configs: [],
     };
     hookInfo.matcherGroups.push(group);
-  } else if (normalizedSequential) {
-    group.sequential = true;
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/hooks/matcherGrouping.ts` around lines 29 -
41, The current grouping finds by matcher only (hookInfo.matcherGroups.find
comparing candidate.matcher to normalizedMatcher) and then mutates
group.sequential when a later config has normalizedSequential=true, which mixes
sequential and non-sequential handlers; update the grouping so groups are keyed
by both matcher and sequential (change the find predicate to compare
candidate.matcher === normalizedMatcher && candidate.sequential ===
normalizedSequential) and push a new group when either differs, ensuring you set
sequential on the new group via normalizedSequential; alternatively, remove
group.sequential entirely and keep sequential on each config in
group.configs—use the symbols hookInfo.matcherGroups, normalizedMatcher,
normalizedSequential, and group.sequential to locate and modify the logic.
packages/cli/src/ui/components/hooks/HandlerListBody.tsx-10-10 (1)

10-10: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Switch HookType imports back to @hoptrendy/hopcode-core

  • packages/cli/src/ui/components/hooks/HandlerListBody.tsx imports HookType from @qwen-code/qwen-code-core; switch it to @hoptrendy/hopcode-core to match the rest of the hook UI.
  • packages/cli/src/ui/components/hooks/HandlerListBody.test.tsx has the same dependency mismatch; update it in the same patch.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/ui/components/hooks/HandlerListBody.tsx` at line 10, The
import for HookType is pointing to the wrong package; update the import
statement that currently reads "import { HookType } from
'`@qwen-code/qwen-code-core`';" in the HandlerListBody component (file containing
the HandlerListBody React component) and the corresponding
HandlerListBody.test.tsx to instead import HookType from
'`@hoptrendy/hopcode-core`' so the HookType source matches the rest of the hook
UI.
.qwen/skills/agent-reproduce-feature/scripts/llm_dump.py-98-104 (1)

98-104: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Redact URL userinfo credentials before writing captures.

_redact_url currently preserves credentials embedded in URLs (for example, https://user:pass@host/...), which can leak directly into the JSONL output.

🔧 Proposed fix
 def _redact_url(url: str) -> str:
     parsed = urlparse(url)
     query = []
     for key, value in parse_qsl(parsed.query, keep_blank_values=True):
         query.append((key, "[REDACTED]" if SENSITIVE_KEY_RE.search(key) else value))
-    return urlunparse(parsed._replace(query=urlencode(query, doseq=True)))
+    netloc = parsed.netloc
+    if "@" in netloc:
+        _, host_part = netloc.rsplit("@", 1)
+        netloc = f"[REDACTED]@{host_part}"
+    return urlunparse(
+        parsed._replace(netloc=netloc, query=urlencode(query, doseq=True))
+    )

As per coding guidelines, "Never echo or log secrets (environment variables, tokens, passwords); use masked secrets in CI/CD logs."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-feature/scripts/llm_dump.py around lines 98 -
104, _redact_url currently leaves URL userinfo (username:password@) intact;
update the function (_redact_url) to strip or mask any credentials in the parsed
URL's netloc before reassembling. Specifically, detect parsed.username and
parsed.password and replace the userinfo portion of netloc with a masked value
(e.g. "[REDACTED]" or omit it) while preserving host and port, then use
parsed._replace(netloc=clean_netloc, query=...) when calling
urlunparse/urlencode so no credentials are written to the JSONL output.
.qwen/skills/agent-reproduce-feature/scripts/llm_dump.py-106-121 (1)

106-121: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Non-UTF8 fallback writes unredacted raw payloads.

On Line 117-Line 121, decode failures are stored as base64 without redaction. That bypasses token masking and can leak secrets present in binary/compressed bodies.

🔧 Proposed fix
 def _decode(content: bytes | None) -> dict[str, Any]:
     if not content:
         return {"kind": "empty", "text": ""}
     truncated = len(content) > MAX_BODY
     content_sample = content[:MAX_BODY]
     try:
         text = content_sample.decode("utf-8")
     except UnicodeDecodeError:
-        if truncated:
-            text = content_sample.decode("utf-8", errors="ignore")
-        else:
-            return {
-                "kind": "base64",
-                "base64": base64.b64encode(content_sample).decode("ascii"),
-                "truncated": truncated,
-            }
+        return {
+            "kind": "binary",
+            "size": len(content_sample),
+            "truncated": truncated,
+        }

As per coding guidelines, "Never echo or log secrets (environment variables, tokens, passwords); use masked secrets in CI/CD logs."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-feature/scripts/llm_dump.py around lines 106 -
121, The _decode function returns raw base64 for non-UTF8 content which can leak
secrets; update the except UnicodeDecodeError branch so it never emits
unredacted raw payloads: instead of returning base64(...) directly, either (a)
run the base64 string through the project’s secret-masking routine (e.g.,
mask_secrets(...) or whatever redaction helper exists) before placing it in the
"base64" field, or (b) replace the base64 output with a safe placeholder (e.g.,
{"kind":"binary","text":"<redacted-binary>","truncated":truncated}) if no masker
is available; apply this change in the _decode function where the current base64
return is created and ensure the "truncated" flag is preserved.
packages/core/src/tools/mcp-client.ts-168-177 (1)

168-177: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Do not log raw server error bodies here.

This warning logs arbitrary response text from a remote MCP server on a normal fallback path. Those bodies can include tokens, stack traces, or tenant data, so emitting them at warn level creates a production log-leak surface. Log only the status/server name here, or gate/redact the excerpt behind a debug-only path.

As per coding guidelines, "Never log sensitive data (passwords, tokens, secrets, SSN, credit card numbers); use structured logging with redaction rules."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/tools/mcp-client.ts` around lines 168 - 177, The warning
currently logs the raw responseBody from readResponseBodyExcerpt which can leak
sensitive data; update the block around debugLogger.warn in mcp-client.ts to
stop including responseBody in the warn message and instead log only the
mcpServerName and response.status; if you still want the body for debugging,
emit it at debug level (e.g., debugLogger.debug) or apply a
redaction/sanitization step before logging and reference the same symbols
(readResponseBodyExcerpt, responseBody, debugLogger.warn, mcpServerName) when
making the change.
packages/core/src/tools/mcp-client.ts-129-145 (1)

129-145: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor Request inputs in the compatibility wrapper.

This wrapper only inspects init, so fetch(new Request(url, { method: 'GET', headers: { Accept: 'text/event-stream' } })) bypasses the 400→405 fallback entirely. That makes the exported typeof fetch wrapper diverge from normal fetch semantics and could disable the compatibility path if the SDK starts passing Request objects instead of URL+init.

Suggested fix
-function isStreamableHttpGetSseRequest(init?: RequestInit): boolean {
-  const method = (init?.method ?? 'GET').toUpperCase();
+function isStreamableHttpGetSseRequest(
+  input: RequestInfo | URL,
+  init?: RequestInit,
+): boolean {
+  const request = input instanceof Request ? input : undefined;
+  const method = (init?.method ?? request?.method ?? 'GET').toUpperCase();
   if (method !== 'GET') {
     return false;
   }
 
-  const headers = new Headers(init?.headers);
+  const headers = new Headers(request?.headers);
+  if (init?.headers) {
+    for (const [key, value] of new Headers(init.headers).entries()) {
+      headers.set(key, value);
+    }
+  }
   if (headers.has('last-event-id')) {
     return false;
   }
@@
 export function createStreamableHttpCompatibilityFetch(
   mcpServerName: string,
   fetchFn: typeof fetch = globalThis.fetch.bind(globalThis),
 ): typeof fetch {
   return async (input, init) => {
     const response = await fetchFn(input, init);
     if (
-      !isStreamableHttpGetSseRequest(init) ||
+      !isStreamableHttpGetSseRequest(input, init) ||
       !STREAMABLE_HTTP_GET_SSE_FALLBACK_STATUSES.has(response.status)
     ) {
       return response;
     }
In the WHATWG fetch API, when `fetch` is called with a `Request` object plus an optional `init`, should method and headers default from the `Request` input and then be overridden by `init`? Also, in `@modelcontextprotocol/sdk` v1.29.0, does `StreamableHTTPClientTransport` call the injected `fetch` with a `Request` object or with `url, init`?

Also applies to: 159-163

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/tools/mcp-client.ts` around lines 129 - 145,
isStreamableHttpGetSseRequest currently only inspects the init object and
ignores when callers pass a Request, so update it to accept and honor a Request
input by first deriving method and headers from the Request (if the first arg is
a Request) and then applying overrides from the optional init per fetch
semantics (init.method and init.headers should override Request values); ensure
header merging follows the same precedence and then detect 'text/event-stream'
exactly as before. Apply the same change to the analogous streamability check
around lines referenced (the function used at 159-163) so both code paths treat
Request objects and url+init calls identically.
.qwen/skills/agent-reproduce-feature/scripts/capture_state.py-255-291 (1)

255-291: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Symlink TOCTOU gap can make snapshot read outside the intended root.

collect_entries() decides file-vs-symlink first, but entry_for_file() later re-opens the same path by name. A concurrent symlink swap between those steps can redirect reads/hashes to a different target, bypassing the initial classification and potentially leaking unexpected content.

Also applies to: 223-244, 129-137

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.qwen/skills/agent-reproduce-feature/scripts/capture_state.py around lines
255 - 291, collect_entries has a TOCTOU: it checks path.is_symlink() then
re-opens the same path by name in entry_for_file, which a concurrent symlink
swap can exploit; fix by using lstat + safe open-by-fd semantics: replace the
name-based open with os.lstat(path) to decide symlink vs file, and for
non-symlinks open the file with os.open(..., os.O_RDONLY | getattr(os,
"O_NOFOLLOW", 0)) then fstat the returned fd to ensure it's a regular file
(S_ISREG) before reading/hashing; update entry_for_file (or add entry_for_fd) to
accept a file descriptor (or handle reading from the fd) and close the fd after
use; apply the same lstat+open-by-fd pattern wherever collect_entries or
entry_for_file is used (also at the other mentioned ranges).
packages/cli/src/acp-integration/session/Session.test.ts-31-43 (1)

31-43: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix Vitest mock target so debugLoggerWarnSpy captures Session.ts warnings

  • packages/cli/src/acp-integration/session/Session.ts imports createDebugLogger from @hoptrendy/hopcode-core (then calls debugLogger.warn(...)).
  • packages/cli/src/acp-integration/session/Session.test.ts mocks @qwen-code/qwen-code-core, so the spy will only be hit if @hoptrendy/hopcode-core delegates/re-exports to that module; otherwise the warning assertion can miss.
Proposed fix
-vi.mock('`@qwen-code/qwen-code-core`', async (importOriginal) => {
+vi.mock('`@hoptrendy/hopcode-core`', async (importOriginal) => {
   const actual =
-    await importOriginal<typeof import('`@qwen-code/qwen-code-core`')>();
+    await importOriginal<typeof import('`@hoptrendy/hopcode-core`')>();
   return {
     ...actual,
     createDebugLogger: () => ({
       debug: vi.fn(),
       info: vi.fn(),
       warn: debugLoggerWarnSpy,
       error: vi.fn(),
     }),
   };
 });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/acp-integration/session/Session.test.ts` around lines 31 -
43, The test currently mocks createDebugLogger on `@qwen-code/qwen-code-core` so
debugLoggerWarnSpy never captures warnings from Session.ts which imports
createDebugLogger from `@hoptrendy/hopcode-core`; update the mock in
Session.test.ts to target the actual module imported by Session.ts by mocking
'`@hoptrendy/hopcode-core`' (not '`@qwen-code/qwen-code-core`') and return
createDebugLogger that uses debugLoggerWarnSpy (preserving other original
exports via importOriginal if needed) so calls to createDebugLogger and
subsequent debugLogger.warn(...) in Session.ts hit the spy.

- Replace @qwen-code/qwen-code-core with @hoptrendy/hopcode-core in 12 files
- Fix Storage.getGlobalQwenDir() → getGlobalHopCodeDir() in cleanup.ts and scheduler.ts
- Fix qwenVersion → hopcodeVersion in memoryDiagnosticsDumper.ts
- Fix Qwen_helpfulness → HOPCODE_helpfulness in DataProcessor.ts and test

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 74.22% 74.22% 76.25% 79.78%
Core 74.8% 74.8% 82.01% 83.34%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   74.22 |    79.78 |   76.25 |   74.22 |                   
 src               |    69.9 |    65.54 |   73.68 |    69.9 |                   
  gemini.tsx       |   62.68 |    63.08 |   71.42 |   62.68 | ...1163-1166,1178 
  interactive.tsx  |   60.55 |    60.22 |   66.66 |   60.55 | ...87,695-698,706 
  ...ractiveCli.ts |   78.61 |    66.66 |      75 |   78.61 | ...1299-1300,1336 
  ...liCommands.ts |   73.23 |    72.09 |     100 |   73.23 | ...52-276,301,402 
  ...ActiveAuth.ts |     100 |    88.23 |     100 |     100 | 66,80             
 ...cp-integration |   65.34 |    65.74 |   85.24 |   65.34 |                   
  acpAgent.ts      |   65.07 |    65.95 |   85.96 |   65.07 | ...2077,2091-2099 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  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 |   77.33 |    72.02 |   86.58 |   77.33 |                   
  ...ryReplayer.ts |   67.34 |     75.6 |   81.81 |   67.34 | ...54-269,282-283 
  Session.ts       |   76.83 |    70.79 |   88.88 |   76.83 | ...2729,2735-2738 
  ...entTracker.ts |   90.85 |    84.84 |      90 |   90.85 | ...35,199,251-260 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   84.21 |    77.77 |     100 |   84.21 | ...37-153,209-211 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ssion/emitters |   96.01 |    90.75 |    92.3 |   96.01 |                   
  BaseEmitter.ts   |   76.92 |    66.66 |      80 |   76.92 | 23-24,39-40,55-56 
  ...ageEmitter.ts |     100 |    89.47 |     100 |     100 | 109,111           
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   98.06 |     92.3 |     100 |   98.06 | 227-228,327,335   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |   90.36 |    87.83 |   94.11 |   90.36 |                   
  LlmRewriter.ts   |      81 |       84 |     100 |      81 | ...,88-89,155-159 
  ...Middleware.ts |   95.83 |    85.71 |     100 |   95.83 | 119,127-129       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/auth          |   91.42 |    94.35 |      75 |   91.42 |                   
  allProviders.ts  |   71.69 |      100 |       0 |   71.69 | 73-74,78-84,88-93 
  ...veSelector.ts |      50 |      100 |       0 |      50 | 13-15,19-20       
  ...iderConfig.ts |    97.6 |       95 |     100 |    97.6 | ...61,411,433-434 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/auth/install  |   92.25 |    84.37 |   66.66 |   92.25 |                   
  ...nstallPlan.ts |   92.25 |    84.37 |   66.66 |   92.25 | 24-29,47-49,85,98 
 ...viders/alibaba |   96.96 |    66.66 |   66.66 |   96.96 |                   
  ...baStandard.ts |     100 |      100 |     100 |     100 |                   
  codingPlan.ts    |   93.67 |    66.66 |   66.66 |   93.67 | 83,87-89,94       
  tokenPlan.ts     |     100 |      100 |     100 |     100 |                   
 ...oviders/custom |     100 |      100 |     100 |     100 |                   
  ...omProvider.ts |     100 |      100 |     100 |     100 |                   
 ...roviders/oauth |    91.5 |    77.03 |   97.05 |    91.5 |                   
  openrouter.ts    |   84.37 |    33.33 |     100 |   84.37 | 43-48             
  ...outerOAuth.ts |    91.9 |    79.06 |   96.87 |    91.9 | ...53-655,699-701 
 ...ers/thirdParty |     100 |      100 |     100 |     100 |                   
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/commands      |    20.3 |    85.71 |    12.5 |    20.3 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  cron.ts          |    22.9 |      100 |       0 |    22.9 | ...21-228,237-247 
  dashboard.ts     |   12.35 |      100 |       0 |   12.35 | ...05-118,120-121 
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  grpc.ts          |   12.16 |      100 |       0 |   12.16 | ...94-111,113-114 
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  learn.ts         |    4.68 |      100 |       0 |    4.68 | ...02-325,327-328 
  mcp.ts           |   95.23 |      100 |      50 |   95.23 | 30                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
  search.ts        |    5.18 |      100 |       0 |    5.18 | ...62-190,192-274 
  serve.ts         |    8.02 |      100 |       0 |    8.02 | ...56-152,154-266 
  skills.ts        |   15.64 |      100 |       0 |   15.64 | ...42,351-360,363 
 src/commands/auth |   48.07 |    33.33 |      20 |   48.07 |                   
  handler.ts       |       0 |        0 |       0 |       0 |                   
  ...veSelector.ts |       0 |        0 |       0 |       0 | 1-56              
  providers.ts     |       0 |        0 |       0 |       0 | 1-333             
  registry.ts      |   95.27 |      100 |       0 |   95.27 | 317-318,325-335   
 ...mmands/channel |    39.2 |    79.45 |      50 |    39.2 |                   
  ...l-registry.ts |    8.33 |      100 |       0 |    8.33 | 6-22,25-43        
  config-utils.ts  |      92 |      100 |   66.66 |      92 | 21-26             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   30.98 |       52 |   69.23 |   30.98 | ...72-475,484-486 
  status.ts        |   17.85 |      100 |       0 |   17.85 | 15-26,32-76       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   84.89 |    88.52 |   81.81 |   84.89 |                   
  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 | ...36-139,142-150 
  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         |   65.06 |    31.25 |     100 |   65.06 | ...85,87-91,93-97 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...ommands/github |   12.61 |      100 |       0 |   12.61 |                   
  auth.ts          |    9.44 |      100 |       0 |    9.44 | ...63-267,269-279 
  commit.ts        |    6.28 |      100 |       0 |    6.28 | ...44-261,263-275 
  index.ts         |   54.16 |      100 |       0 |   54.16 | 30-40             
  issues.ts        |   21.83 |      100 |       0 |   21.83 | ...58-162,171-175 
  pr.ts            |   12.08 |      100 |       0 |   12.08 | ...77-309,318-322 
  status.ts        |   10.25 |      100 |       0 |   10.25 | 24-131,138-146    
 src/commands/mcp  |   86.98 |    86.08 |      80 |   86.98 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 290               
  list.ts          |   91.22 |    80.76 |      80 |   91.22 | ...19-121,146-147 
  presets.ts       |   64.33 |      100 |       0 |   64.33 | 108-118,120-165   
  reconnect.ts     |   76.72 |    71.42 |   85.71 |   76.72 | 35-48,153-175     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...commands/model |   79.26 |       35 |   35.29 |   79.26 |                   
  catalog.ts       |   99.84 |      100 |      50 |   99.84 | 1371-1372         
  discovery.ts     |      25 |       40 |      50 |      25 | ...04-141,156-237 
  index.ts         |    9.65 |      100 |       0 |    9.65 | ...31-236,238-247 
  ollama.ts        |      24 |    23.07 |      50 |      24 | ...87-193,196-210 
 ...mmands/profile |   27.55 |    26.66 |   13.33 |   27.55 |                   
  handler.ts       |    2.98 |      100 |       0 |    2.98 | 22-179            
  index.ts         |    55.4 |      100 |       0 |    55.4 | ...-87,94-101,104 
  ...eBootstrap.ts |   49.01 |       10 |     100 |   49.01 | 31-38,43-65,69    
  profileStore.ts  |   29.68 |       60 |    37.5 |   29.68 | 40,47-96,102-103  
 ...ommands/review |   11.48 |      100 |       0 |   11.48 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   10.34 |      100 |       0 |   10.34 | ...52-164,166-167 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 src/config        |    92.2 |     83.4 |   89.58 |    92.2 |                   
  auth.ts          |   86.98 |    80.32 |     100 |   86.98 | ...26-227,243-244 
  config.ts        |   86.34 |    82.82 |   81.48 |   86.34 | ...2052,2054-2062 
  keyBindings.ts   |   96.87 |       50 |     100 |   96.87 | 201-204           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  settings.ts      |   86.56 |    87.82 |   89.47 |   86.56 | ...1292,1307-1310 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.22 |       94 |     100 |   96.22 | ...88-190,205-206 
  webSearch.ts     |   71.27 |    33.33 |     100 |   71.27 | ...44-145,157-158 
 ...nfig/migration |   94.89 |    78.94 |   83.33 |   94.89 |                   
  index.ts         |   94.87 |    88.88 |     100 |   94.87 | 91-92             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.74 |       96 |     100 |   94.74 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.19 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
 src/constants     |      25 |      100 |       0 |      25 |                   
  codingPlan.ts    |      25 |      100 |       0 |      25 | 18-27             
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   63.09 |    64.51 |   55.55 |   63.09 |                   
  ...tputBridge.ts |   62.94 |    65.51 |   56.25 |   62.94 | ...22-323,331-334 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   79.95 |    72.28 |   52.27 |   79.95 |                   
  index.ts         |   61.68 |       64 |      40 |   61.68 | ...88-289,299-304 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,184   
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |   72.57 |    71.12 |   74.07 |   72.57 |                   
  session.ts       |   76.64 |     69.4 |   85.71 |   76.64 | ...20-821,830-840 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...96-597,600-601 
 ...active/control |   76.79 |    91.83 |      80 |   76.79 |                   
  ...rolContext.ts |    6.89 |      100 |       0 |    6.89 | 50-86             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...54-372,388,391 
  ...rolService.ts |       8 |      100 |       0 |       8 | 46-179            
 ...ol/controllers |   27.28 |    35.71 |   36.66 |   27.28 |                   
  ...Controller.ts |   36.97 |       80 |      80 |   36.97 | ...15-117,127-210 
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    33.8 |    34.48 |   44.44 |    33.8 | ...53-462,477-482 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |   21.97 |    28.57 |   27.27 |   21.97 | ...39-451,460-489 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.01 |    93.77 |   95.23 |   98.01 |                   
  ...putAdapter.ts |   97.89 |    92.82 |   98.07 |   97.89 | ...1303,1398-1399 
  ...putAdapter.ts |      96 |     90.9 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 83-84,124-125     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |   79.64 |    79.04 |   93.44 |   79.64 |                   
  auth.ts          |   88.49 |    88.63 |     100 |   88.49 | ...49-150,153-155 
  capabilities.ts  |     100 |     90.9 |     100 |     100 | 264               
  ...usProvider.ts |   67.01 |    51.42 |     100 |   67.01 | ...40-245,278-286 
  debugMode.ts     |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  envSnapshot.ts   |    92.3 |       84 |     100 |    92.3 | 105-108,167-174   
  eventBus.ts      |     100 |      100 |     100 |     100 |                   
  httpAcpBridge.ts |   79.99 |    79.16 |   96.47 |   79.99 | ...4270,4301-4342 
  ...oryChannel.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  loopbackBinds.ts |     100 |      100 |     100 |     100 |                   
  ...pCodeServe.ts |   73.98 |    87.83 |   55.55 |   73.98 | ...94-710,735-737 
  server.ts        |   86.21 |    82.94 |   90.62 |   86.21 | ...2481,2546-2555 
  status.ts        |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...paceAgents.ts |   64.87 |    70.83 |    90.9 |   64.87 | ...1306,1316-1326 
  ...paceMemory.ts |   87.13 |    78.46 |     100 |   87.13 | ...54-361,421-428 
 src/serve/auth    |   86.54 |    78.75 |   93.75 |   86.54 |                   
  deviceFlow.ts    |   96.33 |    79.51 |    97.5 |   96.33 | ...1526,1630,1700 
  ...owProvider.ts |   45.23 |    74.07 |      75 |   45.23 | ...90-359,375,379 
 src/serve/fs      |   84.85 |    79.75 |     100 |   84.85 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 201               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.82 |    77.08 |     100 |   77.82 | ...64,493-497,510 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...FileSystem.ts |   83.55 |    76.22 |     100 |   83.55 | ...1859,1886-1887 
 src/serve/routes  |   89.41 |       70 |     100 |   89.41 |                   
  ...ceFileRead.ts |   94.41 |    76.92 |     100 |   94.41 | ...28-329,390-392 
  ...eFileWrite.ts |    82.1 |    60.52 |     100 |    82.1 | ...42-244,247-249 
 src/services      |   91.66 |    91.21 |   97.56 |   91.66 |                   
  ...mandLoader.ts |     100 |    93.75 |     100 |     100 | 92                
  ...killLoader.ts |     100 |    96.15 |     100 |     100 | 47                
  ...andService.ts |    98.7 |      100 |     100 |    98.7 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.84 |    80.64 |   83.33 |   75.84 | ...07-208,274-275 
  ...mandLoader.ts |     100 |      100 |     100 |     100 |                   
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.21 |    96.66 |     100 |   98.21 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 60-63             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |    88.3 |    85.49 |   92.59 |    88.3 |                   
  DataProcessor.ts |   88.22 |    85.48 |      95 |   88.22 | ...1341,1345-1352 
  ...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.33 |    94.04 |     100 |   97.33 |                   
  ...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.51 |    95.65 |     100 |   97.51 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.36 |    84.84 |     100 |   97.36 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.66 |       70 |     100 |   92.66 | ...22,147,154,163 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   66.82 |    78.94 |   66.66 |   66.82 |                   
  ...reeStartup.ts |   66.82 |    78.94 |   66.66 |   66.82 | ...08-312,363-426 
 src/test-utils    |   86.44 |    89.47 |   80.76 |   86.44 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |   84.25 |     91.3 |   81.81 |   84.25 | ...62-270,272-279 
 src/ui            |   64.79 |    73.23 |   58.73 |   64.79 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   63.65 |    64.85 |   47.36 |   63.65 | ...3199,3203-3207 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.05 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...inePresets.ts |   98.28 |       90 |     100 |   98.28 | ...34,261,420-422 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   52.23 |    51.21 |   42.42 |   52.23 |                   
  AuthDialog.tsx   |   63.01 |     42.1 |   18.18 |   63.01 | ...02,309-331,335 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |    39.4 |       32 |   38.46 |    39.4 | ...68,471,477,480 
  useAuth.ts       |   87.44 |    73.52 |     100 |   87.44 | ...35-241,243-258 
  ...rSetupFlow.ts |   43.45 |    33.33 |      50 |   43.45 | ...68-389,406-449 
 src/ui/commands   |   54.92 |    80.71 |   81.81 |   54.92 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  ...nceCommand.ts |       0 |        0 |       0 |       0 | 1-771             
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.04 |    81.25 |     100 |   89.04 | 91-92,94-99       
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...91-596,681-689 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |    96.1 |    74.07 |     100 |    96.1 | 149-154           
  bugCommand.ts    |   81.13 |    71.42 |     100 |   81.13 | 60-69             
  ciCommand.ts     |       0 |        0 |       0 |       0 | 1-346             
  clearCommand.ts  |      92 |    76.47 |     100 |      92 | 43-44,72-73,91-92 
  ...essCommand.ts |    64.7 |       50 |      75 |    64.7 | ...48-149,163-166 
  ...extCommand.ts |   65.06 |    67.24 |   84.61 |   65.06 | ...39-574,585-586 
  copyCommand.ts   |   98.28 |    94.89 |     100 |   98.28 | ...80,280,321,327 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |     87.5 |     100 |     100 | ...61,224-225,238 
  ...ryCommand.tsx |   77.02 |    79.03 |   88.88 |   77.02 | ...65-270,324-332 
  docsCommand.ts   |     100 |    88.88 |     100 |     100 | 25                
  doctorCommand.ts |   95.06 |    88.28 |     100 |   95.06 | ...92-293,320-321 
  dreamCommand.ts  |      75 |    66.66 |   66.66 |      75 | 22-27,44-47       
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   49.33 |     90.9 |   63.63 |   49.33 | ...06-110,163-215 
  forgetCommand.ts |   26.82 |      100 |      50 |   26.82 | 18-51             
  ...uthCommand.ts |       0 |        0 |       0 |       0 | 1-295             
  githubCommand.ts |       0 |        0 |       0 |       0 | 1-248             
  ...uthCommand.ts |       0 |        0 |       0 |       0 | 1-191             
  goalCommand.ts   |   91.41 |    84.44 |      90 |   91.41 | ...86-189,201-204 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-246             
  hooksCommand.ts  |   79.14 |    65.71 |   85.71 |   79.14 | ...31-132,214-217 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  initCommand.ts   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |   74.56 |    68.42 |     100 |   74.56 | ...31-245,250-273 
  ...ageCommand.ts |   92.17 |    82.69 |     100 |   92.17 | ...43,164,173-183 
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  ...ateCommand.ts |       0 |        0 |       0 |       0 | 1-920             
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  ...ditCommand.ts |       0 |        0 |       0 |       0 | 1-795             
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   75.09 |    78.18 |      75 |   75.09 | ...20-225,262-267 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  ...verCommand.ts |       0 |        0 |       0 |       0 | 1-1109            
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...berCommand.ts |   32.43 |      100 |      50 |   32.43 | 23-57             
  renameCommand.ts |   85.48 |    86.36 |     100 |   85.48 | ...99-206,213-218 
  ...oreCommand.ts |    92.3 |    87.87 |     100 |    92.3 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |      80 |      100 |      50 |      80 | 19-21             
  ...iewCommand.ts |       0 |        0 |       0 |       0 | 1-797             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |   36.52 |       50 |      50 |   36.52 | ...98-114,117-144 
  statsCommand.ts  |   88.19 |    84.21 |     100 |   88.19 | ...,58-61,143-146 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.46 |      100 |      50 |    6.46 | 31-329            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
 src/ui/components |   58.55 |    74.78 |   63.34 |   58.55 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 65-86             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |   89.06 |       75 |     100 |   89.06 | 37,39-44,46       
  ...odeDialog.tsx |     9.7 |      100 |       0 |     9.7 | 35-47,50-182      
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   13.04 |      100 |       0 |   13.04 | 18-61             
  ...TextInput.tsx |   77.01 |       76 |     100 |   77.01 | ...20,234-236,263 
  Composer.tsx     |    81.6 |     64.7 |     100 |    81.6 | ...90,108,160,173 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,85,90-105,110 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.92 |      100 |       0 |   11.92 | 65-510            
  DiffDialog.tsx   |    2.47 |      100 |       0 |    2.47 | 68-732            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 34-192            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   77.18 |    55.81 |     100 |   77.18 | ...33,157,178-183 
  ...ngSpinner.tsx |   56.14 |       40 |      50 |   56.14 | ...3,80-81,95-100 
  GoalPill.tsx     |   76.19 |    81.81 |     100 |   76.19 | 24-30,46-50       
  Header.tsx       |   98.62 |    94.28 |     100 |   98.62 | 162,164           
  Help.tsx         |   98.32 |       90 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |    61.7 |       36 |     100 |    61.7 | ...42,345,348-354 
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...ngSpinner.tsx |    22.8 |      100 |       0 |    22.8 | 35-52,60-100      
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |    80.5 |    79.84 |   83.33 |    80.5 | ...1461,1592,1642 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |     100 |    91.42 |     100 |     100 | 65,74             
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   79.06 |    77.27 |   66.66 |   79.06 | ...51,505,508-527 
  ...elsDialog.tsx |   16.07 |    89.18 |      50 |   16.07 | ...58-159,162-648 
  MemoryDialog.tsx |   61.87 |    76.05 |    62.5 |   61.87 | ...72,391,428-430 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   77.34 |    52.17 |     100 |   77.34 | ...09-914,942-946 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...derDialog.tsx |       0 |        0 |       0 |       0 | 1-625             
  ...atePrompt.tsx |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...dSelector.tsx |   41.26 |    61.53 |   71.42 |   41.26 | ...74-472,476-520 
  ...ionPicker.tsx |   87.58 |    75.38 |     100 |   87.58 | ...96,402,444-466 
  ...onPreview.tsx |   92.42 |    84.37 |     100 |   92.42 | ...,70-71,143-145 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   66.27 |    71.16 |      75 |   66.27 | ...12-820,826-827 
  ...ionDialog.tsx |    87.8 |      100 |   33.33 |    87.8 | 36-39,44-51       
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |      28 |      100 |       0 |      28 | 18-40             
  ...ionPicker.tsx |   17.59 |      100 |       0 |   17.59 | 55-172            
  StatsDisplay.tsx |   97.44 |    94.11 |     100 |   97.44 | 296-301           
  ...ineDialog.tsx |    93.5 |    83.63 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.33 |    88.23 |     100 |   96.33 | 137-140           
  ...nsDisplay.tsx |   87.25 |       64 |     100 |   87.25 | ...47-149,156-158 
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
 ...nts/agent-view |   38.31 |    70.83 |   36.36 |   38.31 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   10.28 |      100 |       0 |   10.28 | 58-311            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.8 |    27.27 |     100 |    87.8 | ...,85,95-103,121 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.72 |    70.53 |   60.86 |   45.72 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |   10.15 |      100 |       0 |   10.15 | 27-161            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   75.84 |    82.66 |   85.29 |   75.84 |                   
  ...sksDialog.tsx |   71.38 |    80.48 |   76.19 |   71.38 | ...1132,1208-1210 
  ...TasksPill.tsx |   63.75 |    86.95 |     100 |   63.75 | 44,86-106,114-122 
  ...gentPanel.tsx |    97.4 |    86.31 |     100 |    97.4 | 123,434-438       
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.88 |    94.23 |   66.66 |   54.88 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 17-128            
  ...nListStep.tsx |   88.43 |    94.73 |      80 |   88.43 | 52-53,59-72,106   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   86.54 |     81.3 |   91.89 |   86.54 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.24 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   20.98 |    86.36 |   83.33 |   20.98 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |    3.64 |      100 |       0 |    3.64 | 41-717            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-30              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   95.83 |    88.88 |     100 |   95.83 | 16,20,109-110     
 ...ents/mcp/steps |   26.74 |    54.54 |   42.85 |   26.74 |                   
  ...icateStep.tsx |    5.88 |      100 |       0 |    5.88 | 40-55,58-296      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.26 |      100 |       0 |    5.26 | 31-247            
  ...rListStep.tsx |   75.18 |    59.37 |     100 |   75.18 | ...53-158,169-173 
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |   69.02 |       50 |     100 |   69.02 | ...22,125,134-143 
 ...nents/messages |   83.23 |    80.55 |    75.6 |   83.23 |                   
  ...ionDialog.tsx |   80.84 |     77.6 |    62.5 |   80.84 | ...98,516,534-536 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.72 |     100 |   97.67 | 118,141,149       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   79.06 |      100 |      70 |   79.06 | ...51-264,268-280 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...tsDisplay.tsx |    95.1 |    88.05 |     100 |    95.1 | ...29,131,164-169 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   55.67 |       40 |   28.57 |   55.67 | ...20-125,133-145 
  ...ryMessage.tsx |   14.28 |      100 |       0 |   14.28 | 23-62             
  ...onMessage.tsx |   81.98 |     72.6 |   33.33 |   81.98 | ...65-467,474-476 
  ...upMessage.tsx |   82.63 |    92.85 |     100 |   82.63 | ...85-412,434-449 
  ToolMessage.tsx  |   88.84 |    75.71 |    92.3 |   88.84 | ...44-749,776-778 
 ...ponents/shared |   86.27 |    80.01 |   95.45 |   86.27 |                   
  ...ctionList.tsx |   99.03 |    95.65 |     100 |   99.03 | 85                
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   83.01 |    86.25 |   88.88 |   83.01 | ...12-513,618-619 
  MultiSelect.tsx  |   93.46 |       75 |     100 |   93.46 | ...37,193-195,205 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   76.25 |    81.81 |     100 |   76.25 | 44-58,65-68       
  StaticRender.tsx |   72.72 |      100 |     100 |   72.72 | 31-33             
  TextInput.tsx    |   78.02 |    47.61 |      80 |   78.02 | ...19-223,235-241 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   84.26 |    80.88 |      90 |   84.26 | ...68-696,743-765 
  text-buffer.ts   |   85.84 |    80.97 |   97.91 |   85.84 | ...2574,2702-2703 
  ...er-actions.ts |   86.71 |    67.79 |     100 |   86.71 | ...07-608,809-811 
 ...ents/subagents |   30.87 |        0 |       0 |   30.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   10.95 |      100 |       0 |   10.95 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 24-328            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |   21.51 |    59.52 |   27.27 |   21.51 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   70.21 |    67.32 |    64.7 |   70.21 |                   
  ContextUsage.tsx |   70.88 |    63.88 |      80 |   70.88 | ...20-426,463-557 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   77.64 |    77.17 |   82.14 |   77.64 |                   
  ...ewContext.tsx |    64.7 |    85.71 |      50 |    64.7 | ...22-225,231-241 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |    93.3 |    64.28 |      50 |    93.3 | ...35-236,263-267 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   82.35 |    82.41 |     100 |   82.35 | ...1159,1165-1167 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   43.28 |     62.5 |    62.5 |   43.28 | ...58-261,265-268 
  ...gsContext.tsx |   83.33 |       50 |     100 |   83.33 | 17-18             
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...nsContext.tsx |   88.23 |       50 |     100 |   88.23 | 118-119           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 195-196           
  ...deContext.tsx |   76.08 |    72.72 |     100 |   76.08 | 47-48,52-59,77-78 
 src/ui/daemon     |   90.76 |    73.73 |   95.45 |   90.76 |                   
  ...TuiAdapter.ts |   90.76 |    73.73 |   95.45 |   90.76 | ...53,771-772,858 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/history    |   41.21 |    83.33 |   41.17 |   41.21 |                   
  HistoryVault.ts  |   41.21 |    83.33 |   41.17 |   41.21 | ...21-250,255-263 
 src/ui/hooks      |   82.56 |    82.65 |   86.89 |   82.56 |                   
  ...dProcessor.ts |   83.23 |    82.56 |     100 |   83.23 | ...90-391,410-437 
  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 |   78.06 |    63.22 |   71.42 |   78.06 | ...37,961,982-986 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   19.81 |    66.66 |      25 |   19.81 | 57-175            
  ...Completion.ts |   92.81 |    89.09 |     100 |   92.81 | ...86-187,224-227 
  ...ifications.ts |   92.07 |    96.29 |     100 |   92.07 | 116-124           
  ...tIndicator.ts |   83.49 |    70.96 |     100 |   83.49 | ...60,168,170-178 
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   94.21 |    76.08 |     100 |   94.21 | 122-126,213,219   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   94.36 |    74.35 |     100 |   94.36 | ...60,168-169,209 
  ...ompletion.tsx |   96.01 |    83.87 |     100 |   96.01 | ...22-223,225-226 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   77.27 |       50 |     100 |   77.27 | ...2,75-79,93-101 
  ...eteCommand.ts |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...ialogClose.ts |   13.33 |      100 |     100 |   13.33 | 82-173            
  useDiffData.ts   |   11.62 |      100 |       0 |   11.62 | 44-87             
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |   57.89 |    71.42 |      50 |   57.89 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   89.15 |     62.5 |      50 |   89.15 | ...22-124,149-150 
  ...miniStream.ts |   78.52 |    76.16 |   91.66 |   78.52 | ...2560,2587-2592 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   90.29 |    94.11 |     100 |   90.29 | ...60-161,171-173 
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...opCodeAuth.ts |     100 |      100 |     100 |     100 |                   
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   63.15 |       75 |      50 |   63.15 | 42-52,64-67       
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...ouseEvents.ts |   87.17 |    88.88 |   66.66 |   87.17 | 81-82,86-88       
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derCommand.ts |       0 |        0 |       0 |       0 | 1-27              
  ...derUpdates.ts |   86.49 |    77.96 |    90.9 |   86.49 | ...26,288-300,348 
  ...lScheduler.ts |    84.7 |    93.33 |     100 |    84.7 | ...71-276,372-382 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   96.96 |    83.33 |     100 |   96.96 | 101-102,131       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   96.98 |    95.78 |     100 |   96.98 | ...83-184,238-241 
  ...sionPicker.ts |   96.86 |    94.65 |     100 |   96.86 | ...95-397,430-431 
  ...earchInput.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...Completion.ts |    82.7 |    85.41 |   94.73 |    82.7 | ...69-671,679-715 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   96.18 |    90.64 |     100 |   96.18 | ...76-379,465-472 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...tification.ts |     100 |    85.71 |     100 |     100 | 47                
  ...alProgress.ts |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |      60 |    83.33 |      50 |      60 | 24-37,43-44       
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 44-45,87          
  vim.ts           |   83.77 |    80.31 |     100 |   83.77 | ...55,759-767,776 
 src/ui/layouts    |   89.72 |     87.5 |     100 |   89.72 |                   
  ...AppLayout.tsx |   89.88 |     87.5 |     100 |   89.88 | 51-53,93-98       
  ...AppLayout.tsx |   89.47 |     87.5 |     100 |   89.47 | 58-63             
 ...i/manageModels |   58.14 |    48.38 |     100 |   58.14 |                   
  manageModels.ts  |   58.14 |    48.38 |     100 |   58.14 | ...19,232,263-317 
 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 |   13.33 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |   13.33 |     100 |                   
 src/ui/state      |   94.91 |    81.81 |     100 |   94.91 |                   
  extensions.ts    |   94.91 |    81.81 |     100 |   94.91 | 68-69,88          
 src/ui/themes     |   98.53 |    70.58 |     100 |   98.53 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |     100 |      100 |     100 |     100 |                   
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  hopcode-dark.ts  |     100 |      100 |     100 |     100 |                   
  hopcode-light.ts |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   88.07 |    82.89 |     100 |   88.07 | ...52-361,366-367 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   84.15 |    82.85 |    92.5 |   84.15 |                   
  ...Colorizer.tsx |   79.53 |    83.78 |     100 |   79.53 | ...51-152,249-275 
  ...nRenderer.tsx |   68.83 |    70.14 |      50 |   68.83 | ...52-254,274-293 
  ...wnDisplay.tsx |   86.01 |    87.66 |     100 |   86.01 | ...87,704,729-754 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.08 |    80.45 |      95 |   92.08 | ...76-679,723-728 
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   59.61 |    58.82 |     100 |   59.61 | ...,86-88,107-149 
  commandUtils.ts  |    95.9 |    88.42 |     100 |    95.9 | ...66,168-169,293 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   88.37 |    72.22 |     100 |   88.37 | 23,25,29,31,33    
  formatters.ts    |   95.23 |    98.27 |     100 |   95.23 | 117-120           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    94.59 |     100 |     100 | 40,62             
  historyUtils.ts  |   94.11 |       94 |     100 |   94.11 | 94-97             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |    89.47 |     100 |     100 | 81,110            
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |   98.66 |    96.77 |     100 |   98.66 | 48-49             
  ...geRenderer.ts |   86.28 |    69.06 |   95.12 |   86.28 | ...1281,1321-1327 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 83                
  mouse.ts         |   90.71 |    73.33 |   88.88 |   90.71 | ...40-143,200-201 
  osc8.ts          |   94.73 |    87.75 |     100 |   94.73 | ...49,434,438-439 
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |   98.98 |    97.05 |     100 |   98.98 | 98                
  ...storyUtils.ts |   62.74 |    71.26 |      90 |   62.74 | ...84,432,437-459 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   95.04 |      100 |   88.88 |   95.04 | 115-120           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.61 |    94.84 |   92.85 |   97.61 | ...50-251,386-387 
  todoSnapshot.ts  |   89.33 |    93.47 |     100 |   89.33 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |   56.77 |     40.8 |   79.41 |   56.77 |                   
  collect.ts       |   55.92 |    50.58 |   86.36 |   55.92 | ...25-640,642-647 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   57.47 |    20.51 |      80 |   57.47 | ...09-310,324-359 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   71.71 |    89.78 |   85.76 |   71.71 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |    96.8 |    97.22 |     100 |    96.8 | 168-171           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   90.51 |    91.89 |     100 |   90.51 | 67-76,116         
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |    62.4 |    68.57 |     100 |    62.4 | ...51-499,503-532 
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   97.14 |    96.42 |     100 |   97.14 | 125-126           
  errors.ts        |   90.85 |    96.36 |    92.3 |   90.85 | 69-70,298-310     
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   93.68 |       84 |     100 |   93.68 | 79-80,121-124     
  githubApi.ts     |    1.93 |      100 |       0 |    1.93 | ...92-308,314-446 
  ...TokenStore.ts |   29.54 |       25 |      25 |   29.54 | ...46,50-57,61-68 
  ...AutoUpdate.ts |   90.76 |    93.33 |   88.88 |   90.76 | 103-114           
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |     100 |      100 |     100 |     100 |                   
  languageUtils.ts |   97.89 |    96.42 |     100 |   97.89 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.79 |    93.28 |     100 |   96.79 | ...76-477,575,588 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  promptUtils.ts   |    3.44 |      100 |       0 |    3.44 | 14-46             
  ...rDetection.ts |    6.25 |      100 |       0 |    6.25 | 43-118            
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   93.22 |    81.25 |     100 |   93.22 | 65-67,80          
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-1039            
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.51 |    91.72 |   89.74 |   82.51 | ...76-694,701-709 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |   98.46 |    94.52 |     100 |   98.46 | 136-137,311       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   95.12 |    89.06 |     100 |   95.12 | ...43-244,249-253 
  ...InfoFields.ts |    87.5 |       65 |     100 |    87.5 | ...24-125,146-147 
  ...iffPreview.ts |   94.11 |    83.33 |     100 |   94.11 | 13                
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |    62.1 |       75 |     100 |    62.1 | 93,107,118-157    
 ...s/housekeeping |   90.15 |     89.7 |   94.11 |   90.15 |                   
  cleanup.ts       |   94.33 |       95 |     100 |   94.33 | 60-62             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   89.71 |    88.23 |   85.71 |   89.71 | 51-55,66,116-120  
  throttledOnce.ts |   86.66 |    85.18 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |    74.8 |    83.34 |   82.01 |    74.8 |                   
 src               |   74.32 |    16.66 |   16.66 |   74.32 |                   
  auth.ts          |       0 |      100 |     100 |       0 | 10-22             
  bun.ts           |       0 |        0 |       0 |       0 | 1-5               
  env.ts           |       0 |        0 |       0 |       0 | 1-13              
  global.ts        |       0 |        0 |       0 |       0 | 1-12              
  index.ts         |     100 |      100 |     100 |     100 |                   
  installation.ts  |       0 |        0 |       0 |       0 | 1-15              
  plugin.ts        |       0 |        0 |       0 |       0 | 1-6               
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   87.03 |    79.81 |   88.29 |   87.03 |                   
  ...transcript.ts |   92.25 |    85.71 |     100 |   92.25 | ...87,306-307,438 
  ...ent-resume.ts |    82.8 |    71.63 |   77.41 |    82.8 | ...1059-1063,1066 
  ...ound-tasks.ts |   95.76 |    87.57 |     100 |   95.76 | ...26-827,898-899 
  github-agents.ts |   68.18 |      100 |      20 |   68.18 | ...60-164,170-171 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |   76.54 |    66.87 |   78.72 |   76.54 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.37 |    63.37 |   78.26 |   75.37 | ...1860,1866-1867 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   76.35 |    86.15 |   73.04 |   76.35 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.37 |    90.62 |   86.66 |   91.37 | ...95,250-270,329 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   81.71 |    77.64 |   72.41 |   81.71 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   76.81 |    72.89 |   63.63 |   76.81 | ...1614,1641-1688 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   84.48 |    78.04 |   63.63 |   84.48 | ...00-401,404-405 
  ...nteractive.ts |   80.07 |    80.76 |   74.07 |   80.07 | ...53,455,457,460 
  ...statistics.ts |   96.95 |    81.39 |   91.66 |   96.95 | ...40,164,205,238 
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/auth          |    6.88 |        0 |       0 |    6.88 |                   
  ...b-app-auth.ts |    3.67 |        0 |       0 |    3.67 | ...46-261,267-273 
  ...-flow-auth.ts |    9.46 |        0 |       0 |    9.46 | ...88-290,297-302 
 src/config        |   76.76 |    83.57 |   65.61 |   76.76 |                   
  ...ovalConfig.ts |     100 |      100 |     100 |     100 |                   
  chatConfig.ts    |       0 |        0 |       0 |       0 | 1-66              
  config.ts        |   76.11 |    82.08 |   58.29 |   76.11 | ...4175,4186-4198 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  ...ionsConfig.ts |     100 |    93.33 |     100 |     100 | 83,105            
  storage.ts       |   95.01 |     90.9 |   90.47 |   95.01 | ...71-372,375-376 
  ...etryConfig.ts |     100 |       80 |     100 |     100 | 77,85,89,109      
  uiConfig.ts      |       0 |        0 |       0 |       0 | 1-118             
 ...nfirmation-bus |   99.01 |    98.18 |     100 |   99.01 |                   
  ...ateHandler.ts |     100 |      100 |     100 |     100 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   86.04 |    83.86 |   90.94 |   86.04 |                   
  baseLlmClient.ts |   87.24 |    76.47 |    87.5 |   87.24 | ...82,484-494,503 
  ...ionPlanner.ts |   89.85 |     91.3 |     100 |   89.85 | 44-48,134-135     
  client.ts        |   87.43 |    80.57 |   86.36 |   87.43 | ...2069,2107-2110 
  ...tGenerator.ts |   72.25 |    61.11 |     100 |   72.25 | ...64,366,373-376 
  ...lScheduler.ts |   87.23 |    82.86 |   94.91 |   87.23 | ...3326,3387-3398 
  geminiChat.ts    |    91.6 |    87.93 |   97.33 |    91.6 | ...2881,2948-2949 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...ionHandler.ts |       0 |        0 |       0 |       0 | 1-133             
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | 34-42,45-49,52-87 
  logger.ts        |   87.33 |    87.12 |     100 |   87.33 | ...61-565,611-625 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   93.57 |     87.5 |     100 |   93.57 | 47-49,67,77,83,85 
  ...issionFlow.ts |   98.64 |    95.23 |     100 |   98.64 | 93                
  prompts.ts       |   84.05 |    86.58 |   66.66 |   84.05 | ...1182,1189-1204 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...ionHandler.ts |   48.23 |    56.25 |      75 |   48.23 | ...79-402,406-419 
  ...okTriggers.ts |   99.33 |    90.47 |     100 |   99.33 | 156,167           
  turn.ts          |   96.48 |    88.88 |     100 |   96.48 | ...33,446-447,495 
 ...ntentGenerator |   94.88 |    82.07 |      94 |   94.88 |                   
  ...tGenerator.ts |   96.29 |    83.18 |   92.85 |   96.29 | ...1,971,999-1001 
  converter.ts     |   94.51 |    80.72 |     100 |   94.51 | ...06-607,617,823 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.53 |    71.64 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.96 |   92.85 |      90 | ...80-286,304-305 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   93.86 |    82.98 |    90.9 |   93.86 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   93.72 |    81.27 |   90.32 |   93.72 | ...29,939-940,968 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   82.94 |    84.86 |   91.02 |   82.94 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   79.11 |    83.53 |   88.46 |   79.11 | ...1389,1603-1618 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   54.54 |    68.75 |      50 |   54.54 | ...79,87-91,95-99 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   93.82 |     84.4 |     100 |   93.82 | ...89-490,498,566 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   90.66 |    88.57 |     100 |   90.66 | ...15-319,349-350 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.67 |    88.99 |   96.07 |   96.67 |                   
  dashscope.ts     |   97.37 |    91.48 |   93.33 |   97.37 | ...91-292,369-370 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   95.79 |    89.65 |   88.88 |   95.79 | 122-123,193-195   
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
 src/errors        |   94.56 |    90.55 |   94.28 |   94.56 |                   
  boundaries.ts    |   98.82 |    95.12 |     100 |   98.82 | 249,318           
  handlers.ts      |   93.65 |    88.88 |     100 |   93.65 | ...70-171,267-268 
  index.ts         |       0 |        0 |       0 |       0 | 1-60              
  logger.ts        |   86.07 |     90.9 |   92.85 |   86.07 | ...-82,84,211-234 
  types.ts         |    98.4 |    89.79 |   94.28 |    98.4 | 98-99,312,359-360 
 src/extension     |   62.41 |    79.54 |   80.31 |   62.41 |                   
  ...-converter.ts |   66.53 |    52.45 |     100 |   66.53 | ...85-786,795-827 
  ...ionManager.ts |   47.05 |    82.06 |    65.9 |   47.05 | ...1400,1410-1429 
  ...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        |   46.41 |     87.3 |   63.63 |   46.41 | ...68-374,413-466 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.31 |    93.75 |     100 |   97.31 | ...65,185-186,275 
  npm.ts           |   59.01 |    71.69 |    87.5 |   59.01 | ...23-425,432-436 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-108,143-149    
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/flag          |       0 |      100 |     100 |       0 |                   
  flag.ts          |       0 |      100 |     100 |       0 | 5-28              
 src/followup      |   55.57 |    84.14 |   81.25 |   55.57 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   95.06 |       84 |     100 |   95.06 | 78,108,122,133    
  speculation.ts   |   13.02 |      100 |   16.66 |   13.02 | 89-464,524-575    
  ...onToolGate.ts |     100 |    96.42 |     100 |     100 | 94                
  ...nGenerator.ts |    71.6 |    72.13 |   83.33 |    71.6 | ...88-246,316-318 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   89.57 |    83.45 |   94.44 |   89.57 |                   
  ...eGoalStore.ts |    85.1 |    95.45 |   84.61 |    85.1 | ...63-166,174-182 
  goalHook.ts      |   97.26 |    91.48 |     100 |   97.26 | 100-105           
  goalJudge.ts     |   84.33 |    74.28 |     100 |   84.33 | ...57-358,366-368 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   83.79 |     85.4 |   86.47 |   83.79 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |    96.4 |    90.78 |     100 |    96.4 | ...91,293-294,367 
  ...entHandler.ts |    94.8 |    86.25 |   93.54 |    94.8 | ...75,832-833,843 
  hookPlanner.ts   |   86.74 |    85.24 |   83.33 |   86.74 | ...74-176,194-205 
  hookRegistry.ts  |   90.17 |    83.33 |     100 |   90.17 | ...33,352,356,360 
  hookRunner.ts    |   58.69 |    71.26 |   66.66 |   58.69 | ...50-751,760-761 
  hookSystem.ts    |   85.23 |      100 |   66.66 |   85.23 | ...44-645,651-652 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   96.37 |     90.9 |      90 |   96.37 | 342-350,424-425   
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   96.66 |    91.66 |     100 |   96.66 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |       0 |        0 |       0 |       0 | 1-124             
  types.ts         |   91.24 |    92.04 |   85.71 |   91.24 | ...42-443,503-507 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/hopcode       |   83.95 |    77.23 |   95.83 |   83.95 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  hopCodeOAuth2.ts |    80.9 |    70.27 |   90.32 |    80.9 | ...1169-1185,1215 
  ...kenManager.ts |   83.91 |    76.22 |     100 |   83.91 | ...67-772,793-798 
 src/ide           |   75.73 |    83.52 |   78.33 |   75.73 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   66.38 |    81.75 |   66.66 |   66.38 | ...4-965,994-1002 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   41.24 |    52.14 |   51.42 |   41.24 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |   42.69 |    79.16 |      50 |   42.69 | ...62-413,419-436 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   25.31 |    62.06 |   41.66 |   25.31 | ...85-704,710-740 
  ...eLspClient.ts |   32.77 |       80 |   17.64 |   32.77 | ...84-288,294-295 
  ...LspService.ts |   48.49 |    67.16 |   65.71 |   48.49 | ...1352,1369-1379 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |    63.2 |    75.11 |   73.21 |    63.2 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...mcp-client.ts |    1.98 |        0 |       0 |    1.98 | 134-665,671-672   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.62 |    97.72 |     100 |   98.62 | 87-88             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.52 |    86.66 |   86.36 |   79.52 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   82.87 |    82.35 |   92.85 |   82.87 | ...63-173,181-182 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   69.84 |    75.62 |   68.88 |   69.84 |                   
  const.ts         |     100 |      100 |     100 |     100 |                   
  dream.ts         |   65.65 |    73.33 |      50 |   65.65 | 50,107-148        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   63.77 |    79.16 |      50 |   63.77 | ...72-180,183-189 
  extract.ts       |    95.2 |    79.16 |     100 |    95.2 | 81-86,125         
  ...entPlanner.ts |   63.08 |    65.71 |   41.17 |   63.08 | ...17,222-223,332 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |    45.8 |    61.53 |   44.44 |    45.8 | ...04,211,214-346 
  governance.ts    |       0 |        0 |       0 |       0 |                   
  indexer.ts       |   83.87 |    45.45 |     100 |   83.87 | ...50,56-57,69-70 
  manager.ts       |   75.31 |    81.04 |    75.6 |   75.31 | ...1278,1291-1293 
  memoryAge.ts     |   90.47 |    77.77 |     100 |   90.47 | 50-51             
  paths.ts         |   55.47 |    89.47 |   85.71 |   55.47 | ...,89-90,106-114 
  prompt.ts        |   93.36 |    71.42 |     100 |   93.36 | ...58,161,228-229 
  proposalStore.ts |       0 |        0 |       0 |       0 | 1-97              
  recall.ts        |   77.54 |    69.38 |   88.88 |   77.54 | ...53-258,282-293 
  ...ceSelector.ts |   91.86 |    77.27 |     100 |   91.86 | ...15,117-118,126 
  scan.ts          |   87.91 |    68.42 |     100 |   87.91 | ...47-48,58,82-87 
  ...entPlanner.ts |   58.02 |    66.66 |   56.25 |   58.02 | ...47-268,344-389 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   94.44 |    83.33 |     100 |   94.44 | 56-57,92-93       
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   79.38 |    81.03 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.65 |    86.37 |      88 |   89.65 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.24 |    91.66 |     100 |   90.24 | 142,148,151-160   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |       44 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.66 |    93.15 |     100 |   98.66 | 163,325,331       
  modelRegistry.ts |     100 |    98.61 |     100 |     100 | 222               
  modelsConfig.ts  |    85.1 |    83.42 |    82.5 |    85.1 | ...1278,1307-1308 
  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   |   76.71 |    90.62 |      60 |   76.71 |                   
  autoMode.ts      |    92.9 |    92.15 |     100 |    92.9 | ...34-235,256-266 
  ...transcript.ts |      98 |    84.61 |     100 |      98 | 200-201           
  classifier.ts    |   92.89 |    91.42 |     100 |   92.89 | 151-158,342-346   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   78.41 |    86.06 |   82.14 |   78.41 | ...-929,1035-1039 
  rule-parser.ts   |   98.12 |    96.35 |     100 |   98.12 | ...-759,1024-1026 
  ...-semantics.ts |   58.35 |    86.06 |    30.2 |   58.35 | ...1604-1614,1643 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   98.18 |       90 |     100 |   98.18 |                   
  system-prompt.ts |   98.18 |       90 |     100 |   98.18 | 150               
 src/project       |       0 |        0 |       0 |       0 |                   
  instance.ts      |       0 |        0 |       0 |       0 | 1-9               
 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/provider      |       0 |       40 |      40 |       0 |                   
  auth.ts          |       0 |        0 |       0 |       0 | 1-173             
  error.ts         |       0 |      100 |     100 |       0 | 2-204             
  models.ts        |       0 |        0 |       0 |       0 | 1-139             
  provider.ts      |       0 |        0 |       0 |       0 | 1-1602            
  transform.ts     |       0 |      100 |     100 |       0 | 2-1097            
 ...er/sdk/copilot |       0 |    33.33 |   33.33 |       0 |                   
  ...t-provider.ts |       0 |      100 |     100 |       0 | 2-110             
  index.ts         |       0 |        0 |       0 |       0 | 1                 
  ...ible-error.ts |       0 |        0 |       0 |       0 | 1-30              
 ...k/copilot/chat |       0 |     37.5 |    37.5 |       0 |                   
  ...t-messages.ts |       0 |        0 |       0 |       0 | 1-172             
  ...e-metadata.ts |       0 |        0 |       0 |       0 | 1-15              
  ...ish-reason.ts |       0 |      100 |     100 |       0 | 3-19              
  ...-api-types.ts |       0 |        0 |       0 |       0 |                   
  ...uage-model.ts |       0 |        0 |       0 |       0 | 1-851             
  ...at-options.ts |       0 |        0 |       0 |       0 | 1-26              
  ...-extractor.ts |       0 |        0 |       0 |       0 |                   
  ...pare-tools.ts |       0 |        0 |       0 |       0 | 1-92              
 ...ilot/responses |       0 |       50 |      50 |       0 |                   
  ...nses-input.ts |       0 |        0 |       0 |       0 | 1-323             
  ...ish-reason.ts |       0 |      100 |     100 |       0 | 3-22              
  openai-config.ts |       0 |        0 |       0 |       0 |                   
  openai-error.ts  |       0 |        0 |       0 |       0 | 1-22              
  ...-api-types.ts |       0 |        0 |       0 |       0 |                   
  ...uage-model.ts |       0 |        0 |       0 |       0 | 1-1818            
  ...pare-tools.ts |       0 |        0 |       0 |       0 | 1-180             
  ...s-settings.ts |       0 |        0 |       0 |       0 |                   
 ...responses/tool |       0 |        0 |       0 |       0 |                   
  ...nterpreter.ts |       0 |        0 |       0 |       0 | 1-89              
  file-search.ts   |       0 |        0 |       0 |       0 | 1-132             
  ...generation.ts |       0 |        0 |       0 |       0 | 1-116             
  local-shell.ts   |       0 |        0 |       0 |       0 | 1-65              
  ...ch-preview.ts |       0 |        0 |       0 |       0 | 1-104             
  web-search.ts    |       0 |        0 |       0 |       0 | 1-103             
 src/providers     |   77.46 |    70.94 |   60.71 |   77.46 |                   
  all-providers.ts |      68 |      100 |       0 |      68 | 68-69,73-79,83-89 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   98.87 |    87.27 |     100 |   98.87 | 268-269           
  ...der-config.ts |   66.11 |    55.93 |   63.15 |   66.11 | ...08-409,416-425 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.26 |    86.36 |      50 |   97.26 |                   
  ...oding-plan.ts |   87.17 |      100 |       0 |   87.17 | 81-83,86-88,90-93 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.01 |    81.25 |      75 |   97.01 | 120-121           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/security      |     100 |      100 |     100 |     100 |                   
  ...l-security.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   85.52 |    84.24 |   92.33 |   85.52 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.37 |    85.34 |     100 |   97.37 | ...94,117,420-421 
  ...ionService.ts |   97.87 |    93.82 |     100 |   97.87 | 391,393-397,494   
  ...ingService.ts |   84.86 |    84.47 |   83.78 |   84.86 | ...1333,1350-1351 
  ...ttribution.ts |   91.83 |    87.71 |      90 |   91.83 | ...85-690,831-832 
  ...utSlimming.ts |     100 |    97.43 |     100 |     100 | 215,268           
  cronScheduler.ts |   97.56 |    92.98 |     100 |   97.56 | 62-63,77,155      
  evolveService.ts |       0 |        0 |       0 |       0 | 1-220             
  ...eryService.ts |   91.08 |     92.3 |      70 |   91.08 | ...50-151,157-158 
  ...oryService.ts |   86.18 |    76.76 |   91.17 |   86.18 | ...1154,1195-1198 
  fileReadCache.ts |     100 |    97.56 |     100 |     100 | 386               
  ...temService.ts |   91.27 |    82.69 |    90.9 |   91.27 | ...94,196,294-301 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  gitService.ts    |   68.75 |     92.3 |   55.55 |   68.75 | ...12-122,125-129 
  ...reeService.ts |   69.45 |    68.82 |   93.33 |   69.45 | ...2066,2094-2095 
  ...ionService.ts |   98.13 |     97.8 |   95.45 |   98.13 | ...32-333,380-381 
  ...ticsDumper.ts |   98.18 |    95.23 |     100 |   98.18 | 165-166           
  ...ureMonitor.ts |   95.27 |     91.6 |      96 |   95.27 | ...02,603,617-619 
  ...orRegistry.ts |   96.54 |    91.73 |     100 |   96.54 | ...70-471,622-623 
  ollamaService.ts |   90.54 |       84 |     100 |   90.54 | ...01-503,513-522 
  ...kerService.ts |     100 |    95.65 |     100 |     100 | 39                
  ...ttachments.ts |   96.81 |       90 |     100 |   96.81 | ...06,612,627-628 
  ...MapService.ts |   85.54 |    86.88 |     100 |   85.54 | ...82,312-315,328 
  sessionRecap.ts  |   12.65 |      100 |       0 |   12.65 | 44-150            
  ...ionService.ts |   90.47 |     79.2 |   96.87 |   90.47 | ...1324,1328-1329 
  sessionTitle.ts  |   93.87 |    69.81 |     100 |   93.87 | ...33-236,267-268 
  ...ionService.ts |   81.17 |    77.92 |   89.28 |   81.17 | ...1933,1939-1944 
  task-store.ts    |     100 |    98.33 |     100 |     100 | 64                
  ...Estimation.ts |     100 |      100 |     100 |     100 |                   
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...reeCleanup.ts |   14.56 |      100 |   33.33 |   14.56 | 58-185            
  ...ionService.ts |   84.74 |    79.41 |     100 |   84.74 | ...22-223,239-240 
 ...icrocompaction |   98.05 |     91.8 |     100 |   98.05 |                   
  microcompact.ts  |   98.05 |     91.8 |     100 |   98.05 | ...19,289,293,391 
 src/skills        |   88.51 |    85.75 |   94.54 |   88.51 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |      94 |    86.56 |     100 |      94 | ...08,228,240-242 
  skill-manager.ts |   84.26 |    80.87 |   90.32 |   84.26 | ...1155,1162-1166 
  skill-paths.ts   |   89.15 |    86.36 |     100 |   89.15 | ...00-101,106-107 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/subagents     |   83.72 |    79.37 |   95.34 |   83.72 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...-selection.ts |   87.87 |    91.66 |     100 |   87.87 | 59-62             
  ...nt-manager.ts |   77.18 |    71.36 |    93.1 |   77.18 | ...1180,1202-1203 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |    92.5 |    95.18 |     100 |    92.5 | 51-56,69-74,78-83 
 src/telemetry     |   77.56 |     89.3 |    79.8 |   77.56 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |   98.13 |       88 |     100 |   98.13 | 185-187           
  ...-exporters.ts |   46.37 |      100 |   44.44 |   46.37 | ...85,88-89,92-93 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.06 |    95.45 |      95 |   99.06 | 131,344-345       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   53.34 |    65.38 |      60 |   53.34 | ...1215,1232-1252 
  metrics.ts       |   74.05 |    82.95 |   73.21 |   74.05 | ...1027,1030-1041 
  modelPricing.ts  |   70.37 |      100 |       0 |   70.37 | ...16-126,133-138 
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   93.06 |     88.4 |   81.81 |   93.06 | ...72-573,593-597 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   92.79 |    88.39 |     100 |   92.79 | ...31-934,938-941 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.61 |    89.36 |     100 |   98.61 | 53,108            
  types.ts         |   80.37 |    95.49 |   84.93 |   80.37 | ...1151,1154-1183 
  uiTelemetry.ts   |   92.97 |    96.96 |   81.25 |   92.97 | ...93-194,200-207 
 ...hopcode-logger |   69.48 |     80.2 |   66.66 |   69.48 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  ...ode-logger.ts |   69.48 |       80 |   66.07 |   69.48 | ...1059,1097-1098 
 src/test-utils    |   93.16 |    95.91 |   76.47 |   93.16 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   91.19 |    97.14 |   72.41 |   91.19 | ...38,202-203,216 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   75.18 |    81.73 |   84.83 |   75.18 |                   
  ...erQuestion.ts |   88.93 |    76.74 |    90.9 |   88.93 | ...39-340,347-348 
  bg-stop.ts       |       0 |        0 |       0 |       0 | 1-97              
  browser.ts       |       0 |        0 |       0 |       0 | 1-359             
  cron-create.ts   |   88.11 |    88.88 |    62.5 |   88.11 | ...,43-44,165-172 
  cron-delete.ts   |   96.82 |      100 |   83.33 |   96.82 | 26-27             
  cron-list.ts     |   96.66 |      100 |   83.33 |   96.66 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   81.02 |    84.07 |      75 |   81.02 | ...15-716,826-876 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  exit-worktree.ts |   84.23 |    85.96 |   91.66 |   84.23 | ...92-293,298-312 
  exitPlanMode.ts  |   85.09 |    85.71 |     100 |   85.09 | ...60-163,177-189 
  glob.ts          |   90.63 |    88.33 |   84.61 |   90.63 | ...28,171,302,305 
  grep.ts          |   79.19 |    85.71 |   78.94 |   79.19 | ...20,560,569-576 
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.77 |    60.09 |   90.32 |   72.77 | ...1211,1213-1214 
  ...nt-manager.ts |   84.36 |    82.74 |   84.21 |   84.36 | ...2099-2103,2142 
  mcp-client.ts    |   39.91 |    83.82 |   69.44 |   39.91 | ...1618,1622-1625 
  mcp-tool.ts      |   90.98 |    88.88 |   96.42 |   90.98 | ...95-596,646-647 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-47              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   91.65 |    84.05 |   88.46 |   91.65 | ...87,600,796-801 
  notebook-edit.ts |   85.11 |    76.42 |   81.25 |   85.11 | ...54-870,916-917 
  ...nforcement.ts |     100 |    97.67 |     100 |     100 | 234               
  read-file.ts     |    95.4 |    90.32 |      90 |    95.4 | ...99,298-301,304 
  repoMap.ts       |       0 |        0 |       0 |       0 | 1-113             
  ripGrep.ts       |   94.59 |    85.71 |   93.33 |   94.59 | ...60,463,541-542 
  ...-transport.ts |    6.34 |        0 |       0 |    6.34 | 47-145            
  send-message.ts  |   84.68 |    91.66 |    62.5 |   84.68 | ...,82-90,167-170 
  shell.ts         |   73.45 |    79.96 |   91.42 |   73.45 | ...4234,4280-4286 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   88.51 |    91.66 |   88.23 |   88.51 | ...20,424,447-469 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |       0 |        0 |       0 |       0 | 1-116             
  task-get.ts      |       0 |        0 |       0 |       0 | 1-92              
  task-list.ts     |       0 |        0 |       0 |       0 | 1-120             
  task-output.ts   |       0 |        0 |       0 |       0 | 1-95              
  task-ready.ts    |       0 |        0 |       0 |       0 | 1-103             
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  task-update.ts   |   89.65 |    94.44 |   85.71 |   89.65 | 33-38,43-48       
  todoWrite.ts     |   89.17 |    82.05 |   92.85 |   89.17 | ...41-546,568-569 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   74.33 |    77.06 |   80.95 |   74.33 | ...53-854,862-863 
  tool-search.ts   |   95.19 |    86.48 |    92.3 |   95.19 | ...47-153,208-213 
  tools.ts         |   92.14 |    90.38 |   89.47 |   92.14 | ...78-479,495-501 
  web-fetch.ts     |   88.84 |       80 |   92.85 |   88.84 | ...12-313,315-316 
  write-file.ts    |   82.65 |    80.45 |   84.61 |   82.65 | ...65-668,696-731 
 src/tools/agent   |   74.98 |    80.49 |   73.61 |   74.98 |                   
  agent.ts         |   75.24 |    80.72 |   74.24 |   75.24 | ...2476,2485-2488 
  fork-subagent.ts |   69.62 |    71.42 |   66.66 |   69.62 | ...04-105,140-151 
 ...s/computer-use |   86.93 |    87.82 |   78.37 |   86.93 |                   
  bootstrap.ts     |   82.24 |    94.44 |      80 |   82.24 | 116-135,235-236   
  client.ts        |      38 |      100 |      50 |      38 | ...48-178,182-191 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    76.92 |     100 |   94.44 | 40-41             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 43                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    95.5 |    81.39 |    92.3 |    95.5 | 47-48,145-151     
 ...ols/web-search |   61.08 |     66.1 |   73.68 |   61.08 |                   
  base-provider.ts |    40.9 |    33.33 |     100 |    40.9 | 40-43,48-56       
  index.ts         |   62.69 |    70.58 |      80 |   62.69 | ...32-369,388-398 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      60 |       50 |      50 |      60 | 35-42             
 ...arch/providers |    20.7 |    55.17 |   56.52 |    20.7 |                   
  bing-provider.ts |    5.88 |       50 |      50 |    5.88 | 43-99             
  ...m-provider.ts |   16.58 |        0 |       0 |   16.58 | 48-56,75-255      
  ...e-provider.ts |       8 |        0 |       0 |       8 | 68-83,89-199      
  ...o-provider.ts |    3.84 |       50 |      50 |    3.84 | 36-124            
  exa-provider.ts  |       6 |       50 |      50 |       6 | 36-91             
  ...l-provider.ts |    5.55 |       50 |      50 |    5.55 | 39-100            
  ...e-provider.ts |      82 |    55.55 |     100 |      82 | 57-58,61-62,72-76 
  jina-provider.ts |       6 |       50 |      50 |       6 | 34-92             
  ...y-provider.ts |   89.79 |       75 |     100 |   89.79 | 62-66             
 src/util          |     7.5 |    42.85 |      25 |     7.5 |                   
  bun-shim.ts      |    87.5 |      100 |       0 |    87.5 | 6                 
  error.ts         |       0 |      100 |     100 |       0 | 8-49              
  filesystem.ts    |       0 |        0 |       0 |       0 | 1-22              
  fn.ts            |       0 |      100 |     100 |       0 | 3-14              
  iife.ts          |       0 |        0 |       0 |       0 | 1-3               
  lazy.ts          |       0 |        0 |       0 |       0 | 1-11              
  log.ts           |       0 |        0 |       0 |       0 | 1-25              
  zod-meta.ts      |      40 |      100 |       0 |      40 | 12-14             
 src/utils         |   89.01 |    87.63 |   93.71 |   89.01 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   80.74 |    78.84 |     100 |   80.74 | ...28,151,195-198 
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |    7.69 |      100 |       0 |    7.69 | 17-56             
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |      90 |    87.71 |     100 |      90 | ...54-155,158-159 
  cronDisplay.ts   |   42.85 |    23.07 |     100 |   42.85 | 26-31,33-45,47-54 
  cronParser.ts    |   89.74 |    85.71 |     100 |   89.74 | ...,63-64,183-186 
  debugLogger.ts   |   95.95 |    92.53 |   94.73 |   95.95 | 106-107,218-222   
  editHelper.ts    |   93.63 |    83.52 |     100 |   93.63 | ...28-429,463-464 
  editor.ts        |    97.6 |     95.4 |     100 |    97.6 | ...25-326,328-329 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |     100 |    95.45 |     100 |     100 | 83                
  errorParsing.ts  |   87.87 |    91.89 |     100 |   87.87 | 73-74,93-103      
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   72.04 |    77.41 |   55.55 |   72.04 | ...85-301,305-311 
  fetch.ts         |   70.18 |    71.42 |   71.42 |   70.18 | ...42,148,161,186 
  fileUtils.ts     |   91.51 |    86.13 |   95.23 |   91.51 | ...1192,1196-1202 
  forkedAgent.ts   |   80.68 |    78.12 |   83.33 |   80.68 | ...39-545,550-556 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  gitDiff.ts       |   92.36 |    79.53 |     100 |   92.36 | ...55-856,928-929 
  ...noreParser.ts |   92.36 |     87.5 |     100 |   92.36 | ...17-118,188-189 
  gitUtils.ts      |   73.64 |    90.32 |   83.33 |   73.64 | ...,78-79,103-154 
  ...noreParser.ts |   85.71 |    82.14 |     100 |   85.71 | ...61,67-68,74-75 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 26                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |    74.1 |    90.76 |   58.33 |    74.1 | ...23-326,336-342 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |   88.27 |    83.87 |     100 |   88.27 | ...76,279,407-410 
  ...tProcessor.ts |    93.2 |    89.18 |     100 |    93.2 | ...82-288,370-371 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  modelId.ts       |   98.95 |    98.21 |     100 |   98.95 | 148               
  ...kerChecker.ts |   90.78 |    91.66 |     100 |   90.78 | 73-79             
  notebook.ts      |   94.57 |    89.83 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   90.85 |    87.87 |     100 |   90.85 | ...97-199,222-227 
  partUtils.ts     |     100 |    98.61 |     100 |     100 | 206               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.24 |    91.86 |     100 |   93.24 | ...90-391,393-395 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.39 |    72.41 |     100 |   89.39 | ...37-142,193-196 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  rateLimit.ts     |   92.55 |    85.92 |     100 |   92.55 | ...70-272,309-310 
  readManyFiles.ts |   87.59 |       84 |     100 |   87.59 | ...09-211,227-238 
  retry.ts         |   89.95 |    88.05 |     100 |   89.95 | ...32,353,360-361 
  ripgrepUtils.ts  |   46.79 |    84.37 |   66.66 |   46.79 | ...45-246,258-335 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   81.51 |    85.04 |   95.23 |   81.51 | ...21,546,575-584 
  runtimeStatus.ts |   97.53 |    88.57 |     100 |   97.53 | 162-163           
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    88.23 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   94.57 |    80.26 |     100 |   94.57 | ...04,213-216,270 
  ...r-launcher.ts |   76.92 |     91.3 |   66.66 |   76.92 | ...34,136,157-195 
  ...orageUtils.ts |   96.89 |    85.84 |     100 |   96.89 | ...51,367,447,466 
  shell-utils.ts   |   82.64 |    89.73 |     100 |   82.64 | ...1631,1638-1642 
  ...lAstParser.ts |   95.58 |    85.79 |     100 |   95.58 | ...1067-1069,1079 
  ...ContextEnv.ts |     100 |      100 |     100 |     100 |                   
  ...nlyChecker.ts |    95.1 |    91.66 |     100 |    95.1 | ...16-317,325-326 
  sideQuery.ts     |   86.17 |    86.53 |     100 |   86.17 | ...55-161,163-169 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   81.48 |       75 |     100 |   81.48 | 54-59             
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  truncation.ts    |     100 |       92 |     100 |     100 | 52,71             
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   93.71 |    89.28 |   93.33 |   93.71 | ...24-225,249-251 
  xml.ts           |     100 |      100 |     100 |     100 |                   
  yaml-parser.ts   |     100 |    98.33 |     100 |     100 | 152               
 ...ils/filesearch |   86.22 |    81.44 |   96.42 |   86.22 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.84 |    77.49 |   94.82 |   82.84 | ...1451,1485-1486 
  fileSearch.ts    |   93.58 |    87.32 |     100 |   93.58 | ...46-247,249-250 
  ignore.ts        |     100 |       96 |     100 |     100 | 11                
  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.

TaimoorSiddiquiOfficial and others added 2 commits June 2, 2026 15:08
Upstream tests stub QWEN_HOME, but Storage.getGlobalHopCodeDir()
reads HOPCODE_HOME. Update both test fixtures to use the correct
env var so cleanup and scheduler tests can find the temp directory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…log tests

The useConfig mock previously created a new object on every call:
  useConfig: vi.fn(() => ({ ... }))

Since fetchHooksData = useCallback(..., [config]), a new config reference
on every render caused fetchHooksData to be recreated, re-running the
useEffect([fetchHooksData]) each render. This infinite loop prevented
keypress navigation from working in the three navigation tests.

Fix: create stableConfig once inside the vi.mock factory closure and
always return the same reference from useConfig(). This breaks the
render loop and lets all 8 tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ss tests

The afterEach was calling cleanup() from ink-testing-library, but the
tests use renderWithProviders() from test-utils/render.tsx which maintains
its own separate instances array. The ink-testing-library cleanup is a
no-op for these instances, so components were never unmounted after each
test.

This caused deferred React re-renders from tests 4 and 5 (which use
mockReturnValueOnce and trigger extra renders) to fire during test 6,
contaminating mockedUseKeypress.mock.calls with stale handlers. When
pressKey('return') used mock.calls.at(-1) it would invoke the wrong
handler from a previous test, preventing navigation.

Fix: import cleanup from render.tsx so instances are properly unmounted
between tests. Also retain NAV_TIMEOUT on waitFor calls to handle CI
runners under heavy integration-test load.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@TaimoorSiddiquiOfficial TaimoorSiddiquiOfficial merged commit 1a1e77f into main Jun 2, 2026
9 checks passed
@TaimoorSiddiquiOfficial TaimoorSiddiquiOfficial deleted the merge/upstream-qwen-sync branch June 2, 2026 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.