Skip to content

feat(core): atomic write rollout for credentials, memory, config, JSONL (closes #3681, #4095 Phase 2)#4333

Merged
doudouOUC merged 34 commits into
mainfrom
worktree-ethereal-bubbling-cook
Jun 2, 2026
Merged

feat(core): atomic write rollout for credentials, memory, config, JSONL (closes #3681, #4095 Phase 2)#4333
doudouOUC merged 34 commits into
mainfrom
worktree-ethereal-bubbling-cook

Conversation

@doudouOUC

@doudouOUC doudouOUC commented May 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Phase 2 of #4095 — replace the remaining bare fs.writeFile / fs.writeFileSync / fs.appendFile calls in security-sensitive and data-integrity paths with the atomic helpers introduced by Phase 1 (PR #4096). Also closes #3681 (JSONL session writer durability).

A process killed mid-write — kill -9, OOM, power loss, AV scan stalling rename, FS unmount mid-flush — could previously leave OAuth credentials, memory metadata, session transcripts, or trust-folder config half-written or with glued }{ JSONL records. After this PR all of those go through atomicWriteFile / atomicWriteFileSync (temp + fsync + rename + EXDEV fallback + EPERM retry).

Ref: #4095 Phase 2. Closes: #3681.

What changed

Ten commits, each independently green:

Core migration (6 commits):

  1. feat(core): add atomicWriteFileSync + forceMode option — new sync helper mirroring async API (flush:true, symlink chain, EXDEV fallback, EPERM retry via Atomics.wait blocking sleep). New forceMode option ignores existing-target permissions and applies options.mode regardless — needed for credentials so a historically over-permissive file (e.g. 0o644 restored from backup) gets healed to 0o600 on next write.
  2. refactor(core): migrate credential writes (Tier 1)oauth-token-storage, file-token-storage, sharedTokenManager. All write with {mode: 0o600, forceMode: true}. (cacheQwenCredentials in qwenOAuth2.ts was initially included but de-migrated during merge with upstream PR feat(serve): auth device-flow route (#4175 Wave 4 PR 21) #4255 — see "Deliberately not in scope" below.)
  3. refactor(core): migrate memory state writes (Tier 2)memory/manager, extract, indexer, dream, forget. Trailing-newline preserved.
  4. refactor: migrate config + logger + state writes (Tier 3a)trustedFolders (sync), logger (4 sites), plus state-file siblings the issue didn't list but match the same risk profile: tipHistory, installationManager, projectSummary, todoWrite, trustedHooks.
  5. fix(core): flush JSONL appends to disk (Tier 3b, closes #3681)jsonl-utils.ts writeLine/writeLineSync get flush: true; write() full-file replace goes through atomicWriteFileSync; debugLogger.ts appendFile gets flush: true.
  6. refactor(core): migrate extension config + LSP edit to atomic write — catch-up commit after auditing Claude Code's equivalents: extensionManager.ts enablement config + install metadata, NativeLspService.ts LSP-driven user-file edit.

Cosmetic cleanup (1 commit):
7. chore: cosmetic cleanups from PR reviewindex.ts export ordering; tipHistory.ts adds forceMode: true for consistency with other 0o600 sites.

Codex-review-driven fixes (3 commits): all three were latent bugs flagged across three Codex review rounds. None had user-visible symptoms yet — caught before merge.
8. fix(core): address Codex review findings on Phase 2 PR — three latent bugs from round 1:

  • forceMode without mode silently downgraded perms. if (!options?.forceMode) skipped the existing-mode stat whenever forceMode was true, regardless of whether mode was also supplied. Calling atomicWriteFile(p, data, { forceMode: true }) (no mode) on an existing 0o600 file produced 0o644 (umask default). Tightened guard to also require options.mode; mirrored in sync; added regression tests that assert mode preservation.
  • logger.test.ts: vi.resetAllMocks() blanked the atomicWriteFile shim. vi.fn(actual.atomicWriteFile) factory implementation gets reset to no-op by vi.resetAllMocks() in beforeEach, which would make logger.initialize() silently skip creating logs.json. Tests passed by coincidence (file pre-existence). Captured real implementation at module load and re-attached via mockImplementation.
  • NativeLspService.applyTextEdits swallowed all read errors. A read failure (EACCES on read-protected file, EISDIR, etc.) was treated as "new empty file" and the atomic rename could replace the original. Now only ENOENT is treated as new-file; other errors propagate.
  1. fix(lsp): refuse LSP edits to chmod 0444 files (round 2) — even after the previous fix, a file that's readable but chmod 0444 (read-only) would still be replaced by atomic rename (rename only needs parent-directory write access). Added explicit fs.accessSync(W_OK) check before the atomic write; ENOENT still allowed so LSP can create new files.
  2. fix(core): drop withTimeout around atomic credential write (round 3)saveCredentialsToFile wrapped atomicWriteFile in withTimeout(5000). If the call hit the budget (slow NFS, fsync stall), withTimeout would reject while the atomicWriteFile internal write+rename kept running unobserved → the refresh lock got released → another process could write newer credentials → the original atomicWriteFile finally completed its rename and silently overwrote the newer token. Atomic write is durable by design and fs.rename is not abortable — accept the I/O latency. mkdir and stat timeouts kept (idempotent and read-only respectively).

⚠️ Behavior changes (release-note candidates)

Site Before After Impact
mcp/oauth-token-storage.ts, mcp/token-storage/file-token-storage.ts, qwen/sharedTokenManager.ts preserves existing perms forceMode: true heals historically over-permissive token files to 0o600 One-time mode-tightening on next write
utils/jsonl-utils.ts writeLine/writeLineSync bare appendFile, no fsync flush: true per append +few ms latency per assistant turn / tool call; eliminates }{ glued records from kill -9
sharedTokenManager.saveCredentialsToFile 5s withTimeout around the write no timeout (durable atomic write) A pathological NFS hang now blocks token refresh instead of silently rolling back to a stale credential file
NativeLspService.applyTextEdits half-handled read failures, atomic rename could bypass file-level write perms only ENOENT treated as "new file"; explicit W_OK check before write LSP edits on chmod 0444 files now throw EACCES (matches pre-Phase-2 behavior); LSP edits on read-protected files no longer silently overwrite with an empty buffer

Deliberately not in scope

Audited the repo for other bare-write call sites; the following are intentionally left as-is. For each I checked Claude Code's equivalent path; verdicts in parentheses.

  • Lock files using flag: 'wx': sharedTokenManager:708, memory/manager:363, memory/store:49, chatRecordingService:633, sessionService:937 — exclusive-create semantics, must not become atomic. (Claude Code agrees.)
  • qwen/qwenOAuth2.ts cacheQwenCredentials — initially migrated as part of Tier 1, then de-migrated during merge with upstream PR feat(serve): auth device-flow route (#4175 Wave 4 PR 21) #4255 (the daemon device-flow registry work). Upstream added AbortSignal threading + SharedTokenManager.getInstance().clearCache() invalidation into the hand-rolled atomic write. atomicWriteFile doesn't accept a signal (and fs.rename is not abortable), so re-migrating would silently drop signal cancellation — the exact race I just fixed in round 3 for saveCredentialsToFile. Kept upstream's hand-rolled atomic, accept slightly weaker guarantees (no EPERM retry / EXDEV fallback) in exchange for correct cancellation semantics.
  • services/gitService.ts, services/gitWorktreeService.ts — both planned for deprecation (shadow-git checkpointing is being replaced by fileHistoryService per PR feat(rewind): add file restoration support to /rewind command #4064; worktree path is also slated to be retired). Not worth investing atomic-write effort in code on the way out. Defer permanently.
  • extension/extensionSettings.ts env writes, extension/claude-converter.ts, extension/gemini-converter.ts, extension/variables.ts — Claude Code has no equivalent (no per-extension env, no converters). Defer.
  • agents/agent-transcript.ts:127, agents/arena/ArenaManager.ts:1616 — Claude Code's sub-agent metadata sidecars use bare writeFile too (write-once, re-derivable). Defer.
  • core/prompts.ts:406 prompt dump, utils/openaiLogger.ts, tools/shell.ts, utils/truncation.ts, tools/modifiable-tool.ts, core/config/config.ts:2600 — transient / per-request / scratch files. Claude Code's equivalent debug-dump uses appendFile too. Defer.
  • cli/src/serve/httpAcpBridge.ts:1274 — already a hand-rolled atomic write with wx tmp + rename. Worth folding into the shared helper in a follow-up PR with BOM/encoding regression testing.
  • cli/src/config/settings.ts:875 recovery write-back — has its own backup machinery; touching it risks settings-migration regressions, defer.

Test plan

Automated

  • 630 tests pass across 38 test files covering every touched path
  • npx vitest run packages/core/src/utils/atomicFileWrite.test.ts — 36 tests (19 async, 13 sync, 5 forceMode including 2 round-1 regression cases for the "no mode" edge)
  • npx vitest run packages/core/src/utils/jsonl-utils.test.ts packages/core/src/utils/debugLogger.test.ts — 44 pass
  • Tier 1: oauth-token-storage 28, file-token-storage 16, qwenOAuth2 83, sharedTokenManager 31 — all pass with updated mocks
  • Memory tests use real fs and stay green (95 across 17 files)
  • logger.test.ts 52 pass — beforeEach re-binds the real atomicWriteFile after vi.resetAllMocks() (fix from Codex round 1)
  • trustedFolders.test.ts 21, todoWrite.test.ts 28, extensionManager.test.ts 42, LSP suite 62 pass
  • npx tsc --noEmit -p packages/core && npx tsc --noEmit -p packages/cli clean
  • eslint clean on all modified files

Manual smoke verification — completed

Verified on macOS arm64, Node v24.12.0, against this branch (worktree-ethereal-bubbling-cook). Combined library-level integration script (covers crash-safety claims that don't need a model) with a real npm run dev tmux run (proves the actual code paths users hit fire correctly under kill -9).

Part 1 — library-level integration script (17/17 pass)

Direct exercise of atomicWriteFile / atomicWriteFileSync / writeLine / writeLineSync against real disk, including a kill -9 subprocess for the JSONL claim. Confirms every Codex-round fix is regression-proof at the helper level.

verify-atomic-helpers.mjs — full script (click to expand)
// Save as /tmp/verify-atomic-helpers.mjs and run from the worktree root:
//   npx tsx /tmp/verify-atomic-helpers.mjs
// Adjust REPO to point at your worktree.

import * as fs from 'node:fs/promises';
import * as fsSync from 'node:fs';
import * as path from 'node:path';
import * as os from 'node:os';
import { execSync } from 'node:child_process';

const REPO = process.cwd();
const { atomicWriteFile, atomicWriteFileSync } = await import(
  `${REPO}/packages/core/src/utils/atomicFileWrite.js`
);
const { writeLineSync } = await import(
  `${REPO}/packages/core/src/utils/jsonl-utils.js`
);

let pass = 0, fail = 0;
const fails = [];
function check(name, cond, detail = '') {
  const sym = cond ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
  console.log(`${sym} ${name}${detail ? ` \x1b[2m(${detail})\x1b[0m` : ''}`);
  cond ? pass++ : (fail++, fails.push(name));
}

const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'pr-verify-'));
console.log(`Working in: ${tmpDir}\n`);

try {
  console.log('--- Group A: atomicWriteFile basics ---');
  {
    const f = path.join(tmpDir, 'a1.txt');
    await atomicWriteFile(f, 'hello');
    check('A1: write new file', (await fs.readFile(f, 'utf-8')) === 'hello');
    const files = await fs.readdir(tmpDir);
    check('A2: no tmp residue', files.length === 1 && files[0] === 'a1.txt');
  }

  console.log('\n--- Group B: permission preservation ---');
  {
    const f = path.join(tmpDir, 'b1.txt');
    await fs.writeFile(f, 'old');
    await fs.chmod(f, 0o600);
    await atomicWriteFile(f, 'new');
    const mode = (await fs.stat(f)).mode & 0o777;
    check('B1: existing 0o600 preserved on rewrite', mode === 0o600, `mode=${mode.toString(8)}`);
  }
  {
    const f = path.join(tmpDir, 'b2.txt');
    const origUmask = process.umask(0o077);
    try {
      await atomicWriteFile(f, 'new', { mode: 0o600 });
      const mode = (await fs.stat(f)).mode & 0o777;
      check('B2: umask 077 + mode 0o600 lands at 0o600', mode === 0o600, `mode=${mode.toString(8)}`);
    } finally { process.umask(origUmask); }
  }

  console.log('\n--- Group C: forceMode behavior ---');
  {
    const f = path.join(tmpDir, 'c1.txt');
    await fs.writeFile(f, 'old');
    await fs.chmod(f, 0o644); // simulate "restored from backup at 0o644"
    await atomicWriteFile(f, 'new', { mode: 0o600, forceMode: true });
    const mode = (await fs.stat(f)).mode & 0o777;
    check('C1: forceMode heals 0o644 → 0o600', mode === 0o600, `mode=${mode.toString(8)}`);
  }
  {
    // Regression: forceMode WITHOUT mode used to drop perms to umask.
    const f = path.join(tmpDir, 'c2.txt');
    await fs.writeFile(f, 'old');
    await fs.chmod(f, 0o600);
    await atomicWriteFile(f, 'new', { forceMode: true });
    const mode = (await fs.stat(f)).mode & 0o777;
    check('C2: forceMode without mode preserves 0o600 (round-1 fix)', mode === 0o600, `mode=${mode.toString(8)}`);
  }
  {
    const f = path.join(tmpDir, 'c3.txt');
    fsSync.writeFileSync(f, 'old');
    fsSync.chmodSync(f, 0o600);
    atomicWriteFileSync(f, 'new', { forceMode: true });
    const mode = fsSync.statSync(f).mode & 0o777;
    check('C3: atomicWriteFileSync forceMode-no-mode preserves 0o600 (sync round-1 fix)', mode === 0o600, `mode=${mode.toString(8)}`);
  }

  console.log('\n--- Group D: symlinks ---');
  {
    const real = path.join(tmpDir, 'd1-real.txt');
    const link = path.join(tmpDir, 'd1-link.txt');
    await fs.writeFile(real, 'original');
    await fs.symlink(real, link);
    await atomicWriteFile(link, 'via-symlink');
    check('D1: write through symlink updates real target', (await fs.readFile(real, 'utf-8')) === 'via-symlink');
    check('D1: symlink preserved', (await fs.readlink(link)) === real);
  }
  {
    const real = path.join(tmpDir, 'd2-not-yet.txt');
    const link = path.join(tmpDir, 'd2-broken.txt');
    await fs.symlink(real, link); // broken
    await atomicWriteFile(link, 'create-via-broken');
    check('D2: broken symlink — target created', (await fs.readFile(real, 'utf-8')) === 'create-via-broken');
    check('D2: broken symlink — link preserved', (await fs.readlink(link)) === real);
  }

  console.log('\n--- Group E: JSONL fsync survives kill -9 ---');
  {
    // Writer subprocess writes 5 JSONL lines via writeLine, signals readiness,
    // then waits to be killed. We kill -9 and verify the file is intact.
    const writerScript = path.join(tmpDir, 'jsonl-writer.mjs');
    const jsonlFile = path.join(tmpDir, 'session.jsonl');
    const readyFile = path.join(tmpDir, 'ready.flag');
    await fs.writeFile(writerScript, `
import { writeLine } from '${REPO}/packages/core/src/utils/jsonl-utils.js';
import * as fs from 'node:fs';
for (let i = 0; i < 5; i++) {
  await writeLine(${JSON.stringify(jsonlFile)}, { seq: i, payload: 'x'.repeat(100) });
}
fs.writeFileSync(${JSON.stringify(readyFile)}, 'done');
await new Promise(() => {});
`);
    const tsxPath = path.join(REPO, 'node_modules/.bin/tsx');
    const { spawn } = await import('node:child_process');
    const child = spawn(tsxPath, [writerScript], { stdio: 'inherit' });
    const deadline = Date.now() + 5000;
    while (Date.now() < deadline) {
      if (fsSync.existsSync(readyFile)) break;
      await new Promise(r => setTimeout(r, 50));
    }
    const ready = fsSync.existsSync(readyFile);
    child.kill('SIGKILL');
    await new Promise(r => setTimeout(r, 100));
    check('E1: writer reached ready before kill', ready);
    const content = await fs.readFile(jsonlFile, 'utf-8');
    const lines = content.split('\n').filter(Boolean);
    check('E1: all 5 lines on disk', lines.length === 5, `got ${lines.length}`);
    let allParse = true;
    for (const [i, line] of lines.entries()) {
      try {
        if (JSON.parse(line).seq !== i) allParse = false;
      } catch { allParse = false; }
    }
    check('E1: every line is well-formed (no `}{` glue)', allParse);
  }
  {
    const f = path.join(tmpDir, 'sync.jsonl');
    writeLineSync(f, { a: 1 });
    writeLineSync(f, { b: 2 });
    check('E2: writeLineSync appends with flush',
      fsSync.readFileSync(f, 'utf-8') === '{"a":1}\n{"b":2}\n');
  }

  console.log('\n--- Group F: LSP fix (chmod 0444 refusal) ---');
  {
    const f = path.join(tmpDir, 'readonly.txt');
    await fs.writeFile(f, 'original');
    await fs.chmod(f, 0o444);
    let threw = false;
    try { fsSync.accessSync(f, fsSync.constants.W_OK); }
    catch (err) { threw = err.code === 'EACCES' || err.code === 'EPERM'; }
    check('F1: accessSync(W_OK) throws on chmod 0444', threw);
    await fs.chmod(f, 0o644);
  }
  {
    const f = path.join(tmpDir, 'nonexistent.txt');
    let threw = false, isENOENT = false;
    try { fsSync.accessSync(f, fsSync.constants.W_OK); }
    catch (err) { threw = true; isENOENT = err.code === 'ENOENT'; }
    check('F2: accessSync ENOENT on missing file (LSP lets this fall through)', threw && isENOENT);
  }

  console.log(`\n${pass} passed, ${fail} failed`);
  if (fail > 0) {
    for (const f of fails) console.log(`  - ${f}`);
    process.exit(1);
  }
} finally {
  try { execSync(`chmod -R u+rwX ${JSON.stringify(tmpDir)}`); } catch {}
  await fs.rm(tmpDir, { recursive: true, force: true });
}

Actual output (run on this branch):

--- Group A: atomicWriteFile basics ---
✓ A1: write new file
✓ A2: no tmp residue

--- Group B: permission preservation ---
✓ B1: existing 0o600 preserved on rewrite (mode=600)
✓ B2: umask 077 + mode 0o600 lands at 0o600 (mode=600)

--- Group C: forceMode behavior ---
✓ C1: forceMode heals 0o644 → 0o600 (mode=600)
✓ C2: forceMode without mode preserves 0o600 (round-1 fix) (mode=600)
✓ C3: atomicWriteFileSync forceMode-no-mode preserves 0o600 (sync round-1 fix) (mode=600)

--- Group D: symlinks ---
✓ D1: write through symlink updates real target
✓ D1: symlink preserved
✓ D2: broken symlink — target created
✓ D2: broken symlink — link preserved

--- Group E: JSONL fsync survives kill -9 ---
✓ E1: writer reached ready before kill
✓ E1: all 5 lines on disk (got 5 lines)
✓ E1: every line is well-formed (no `}{` glue)
✓ E2: writeLineSync appends with flush

--- Group F: LSP fix (chmod 0444 refusal) ---
✓ F1: accessSync(W_OK) throws on chmod 0444
✓ F2: accessSync ENOENT on missing file (LSP lets this fall through)

17 passed, 0 failed

Part 2 — real CLI end-to-end (tmux + npm run dev)

Validates the helper changes work inside an actual qwen-code session — specifically that logger.ts (logs.json full-file rewrite) and jsonl-utils.writeLine (per-turn session transcript append) survive a hard process kill and /resume can still read the JSONL. This is the closest reproduction of the real #3681 failure mode.

Environment: API key auth (selectedType: "openai" → DASHSCOPE → glm-5). OAuth path is dormant for API-key users, so the high-value paths under load are logger.ts and jsonl-utils.ts — exactly what's verified here.

Commands (run from the worktree root):

# 1. Launch the worktree code in a tmux session
tmux new-session -d -s pr-smoke -x 200 -y 50
tmux send-keys -t pr-smoke 'npm run dev' Enter
sleep 8   # wait for TUI to render

# 2. Issue a long prompt; let the model stream the response
tmux send-keys -t pr-smoke \
  'Tell me a 600-word detailed story about a software engineer debugging a race condition.' Enter

# 3. Identify the leaf node process (the actual qwen-code TUI, under tsx)
ps -A -o pid,ppid,command | grep 'tsx.*packages/cli/index'
#   → grandchild of `npm run dev` — kill that one, not the npm wrapper

# 4. Kill -9 the leaf process mid-stream
kill -9 <PID>

# 5. Verify on-disk state
SESSION_LOGS=~/.qwen/tmp/<projectHash>/logs.json
SESSION_JSONL=~/.qwen/projects/<projectSlug>/chats/<sessionId>.jsonl

# logs.json must parse as a valid JSON array
node -e "JSON.parse(require('fs').readFileSync('$SESSION_LOGS','utf-8'))"

# Every JSONL line must parse and there must be no `}{` glue
node -e "
const lines = require('fs').readFileSync('$SESSION_JSONL','utf-8').split('\n').filter(Boolean);
let bad=0, glue=0;
for (const l of lines) { if (l.includes('}{')) glue++; try { JSON.parse(l); } catch { bad++; } }
console.log('lines:', lines.length, 'parse failures:', bad, 'glued:', glue);
"

# 6. Restart and verify /resume can load the killed session
tmux send-keys -t pr-smoke 'npm run dev' Enter
sleep 8
tmux send-keys -t pr-smoke '/resume' Enter
# inspect the picker — the killed session must appear and load cleanly

Observed results:

Step Expected Actual
Boot dev with worktree changes Clean welcome banner, glm-5 shown
Send prompts, model streams response Tokens appear, JSONL grows per turn
kill -9 <leaf PID> mid-response Process dies instantly, no graceful drain
JSON.parse(logs.json) Returns array with submitted user entries ✅ 2 entries, both well-formed
Every JSONL line parses, no }{ 0 parse failures, 0 glue ✅ 10/10 lines clean
Restart dev Fresh boot, no crash from prior state
/resume picker Killed session listed with original prompt text 请用大约200字详细描述...hello visible
Select session Full conversation loaded (context > 0%) ✅ Context 11.2%

Coverage matrix — PR claim → verification

Claim Covered by
atomicWriteFile is crash-atomic (write tmp + fsync + rename) Part 1: A, B (B2 catches umask × mode), E1 (5 lines + kill -9), Part 2 (full CLI + kill -9)
atomicWriteFileSync mirrors async semantics Part 1: C3, E2
Symlink chain resolution (writes through link, preserves it) Part 1: D1, D2
forceMode: true heals legacy 0o644 → 0o600 Part 1: C1
forceMode without mode preserves existing perms (Codex round-1 fix) Part 1: C2, C3
JSONL writeLine flush: true survives kill -9 — no glued }{ (closes #3681) Part 1: E1, Part 2 (10/10 JSONL lines clean)
LSP refuses to overwrite chmod 0444 (Codex round-2 fix) Part 1: F1, F2
withTimeout removal eliminates token-overwrite race (Codex round-3 fix) Code-level — race is gone by construction (no timeout that can fire while atomic rename is in flight); validated by sharedTokenManager.test.ts (31 pass)
/rewind-style session resume still works after a kill Part 2 step 6 (/resume picker + select)
End-to-end smoke under real auth (API-key path, glm-5) Part 2 — entire flow

Not covered (out of scope for local verification)

  • OAuth refresh + kill -9 round-trip — requires fresh Qwen OAuth credentials and a backend that recognizes them. The existing ~/.qwen/oauth_creds.json in the test environment held test fixtures, and the user's CLI uses API-key auth instead. The code path is identical to the verified atomicWriteFile(creds, {mode:0o600, forceMode:true}) shape, just driven by the OAuth refresh callback rather than the logger.
  • Windows AV stress — no Windows host available; renameWithRetry/renameWithRetrySync EPERM retry path is exercised by the existing unit tests but not under live AV pressure.

Out-of-scope follow-ups

  • Phase 4 — tool result disk overflow (separate issue scope)
  • Fold cli/src/serve/httpAcpBridge.ts:1274 hand-rolled atomic write into the shared helper
  • Backup-rotation pattern (à la Claude Code's 5-file config backups) for ~/.qwen/settings.json — defense in depth, low priority

🤖 Generated with Qwen Code


📝 描述准确性更新(2026-05-31,作者自查)

更正:debugLogger.ts 实际保留 bare appendFile(有意不 fsync),与 commit-5 的 flush:true 描述相反;且 closes #3681 仅覆盖 Item 2(writer 持久性),未含 Item 1。

doudouOUC added 10 commits May 19, 2026 20:18
Sync mirror of atomicWriteFile for code paths that can't await
(settings persistence on exit, sync config writers). Same semantics:
symlink chain resolution, permission preservation, fsync via flush:true,
EPERM/EACCES rename retry, EXDEV fallback to direct write.

Add forceMode option on AtomicWriteFileOptions — when true, ignore the
existing target's permission bits and apply options.mode regardless.
Needed for credential files that must heal historically over-permissive
files (e.g. a 0o644 token restored from backup must be forced to 0o600).
Honored by both async and sync paths. Default false preserves existing
behavior.

Reuses Atomics.wait for true blocking sleep in renameWithRetrySync —
no busy-wait, no extra dep.

Refs: #4095 Phase 2
…ier 1)

Route all OAuth credential persistence through atomicWriteFile with
forceMode: true, so a process crash mid-write cannot leave the user
with a half-written token file, and historically over-permissive files
(e.g. 0o644 from a manual restore) are healed to 0o600 on the next
write.

- oauth-token-storage.ts: setCredentials, deleteCredentials
- file-token-storage.ts: saveTokens (encrypted MCP token storage)
- qwenOAuth2.ts: cacheQwenCredentials (also fixes missing mode — was
  inheriting 0o644 from umask, now forced to 0o600)
- sharedTokenManager.ts: saveCredentialsToFile — drops ~15 lines of
  hand-rolled tmp + rename in favor of the shared helper

Lock-file writes using flag: 'wx' (sharedTokenManager.ts:720) are
intentionally left untouched — they rely on exclusive-create semantics
that atomic write does not preserve.

Tests updated to mock atomicWriteFile instead of fs.writeFile.

Refs: #4095 Phase 2
…Tier 2)

Route all auto-memory state persistence through atomicWriteFile so a
process crash during a dream/extract/forget cycle cannot corrupt the
metadata sidecar, extraction cursor, or topic body files.

Touched: manager (writeDreamMetadata), extract (writeExtractCursor +
bumpMetadata), indexer (rebuild), dream (bumpDreamMetadata), forget
(bumpMetadata + topic body rewrite).

manager.ts:362 acquireDreamLock uses flag: 'wx' for exclusive create —
left untouched, atomic write does not preserve that semantic.

Uses atomicWriteFile (not atomicWriteJSON) to preserve the trailing
newline these files have always had.

Refs: #4095 Phase 2
…4095 Tier 3a)

Route the remaining state-file write paths through atomic helpers so a
crash mid-write cannot corrupt config, log, or session-scoped state:

- trustedFolders.ts (sync): atomicWriteFileSync — sole path that flips
  workspace trust, must not half-write
- logger.ts (4 sites): atomicWriteFile — full-file JSON rewrites for
  logs.json and per-checkpoint files
- tipHistory, installationManager, projectSummary, todoWrite,
  trustedHooks: bonus sites with the same shape (state JSON written
  multiple times per session)

todoWrite is on the hot path — writes every time the todo list mutates
— so the added rename + fsync cost is measurable (a few ms per write
on SSD). Trade-off accepted to avoid a half-written todos file
silently breaking the next session's resume.

Export atomicWriteFile / atomicWriteFileSync from the core public
index so CLI-side callers (trustedFolders, tipHistory) can reach them.

Tests updated:
- logger.test.ts uses vi.importActual to re-export the real helper and
  override per-test via vi.mocked(atomicWriteFile).mockRejectedValueOnce
- trustedFolders.test.ts and todoWrite.test.ts mock the helper directly

Refs: #4095 Phase 2
#3656 fixed the read side of glued '}{' JSONL records — when a process
was killed mid-appendFile, the trailing '\n' was lost and the next
record was concatenated. The write side was left for a follow-up
(#3681).

This adds flush:true (fsync) to every per-line append:
- jsonl-utils.ts writeLine / writeLineSync (session transcripts,
  auto-titles, prompt history)
- debugLogger.ts appendFile (per-session debug log)

jsonl-utils.ts write() (full-file replace) now goes through
atomicWriteFileSync so a crash during overwrite cannot corrupt the
session transcript either.

Trade-off: fsync on every append adds disk-sync latency (single-digit
ms on SSD, more on spinning disk / network FS). Acceptable for a few
writes per turn; the alternative is silently losing the last record
of every interrupted session, which #3681 explicitly flagged.

Refs: #4095 Phase 2 Tier 3b
Closes: #3681
Catch up two sites where Claude Code's equivalent path is atomic but
qwen-code's isn't (verified against
/Users/jinye.djy/Projects/claude-code on 2026-05-19):

- extension/extensionManager.ts:533, :1073 — enablement config and
  install metadata writes. Claude Code's plugin install-counts and zip
  cache use atomic temp+rename via writeFileSyncAndFlush_DEPRECATED.
- lsp/NativeLspService.ts:1351 — applying an LSP edit to a user file.
  Claude Code's FileWriteTool/FileEditTool both route through atomic
  writeTextContent → writeFileSyncAndFlush_DEPRECATED. A bare
  writeFileSync here could half-write the user's source file if the
  process is killed during an LSP-driven rename or quick-fix.

Also clean up stale fs.rename mock setups in sharedTokenManager.test.ts
that became no-ops after Tier 1 migration (rename is no longer called
by saveCredentialsToFile). The fs.writeFile mocks stay because the
wx-flag lock path still uses them.

Refs: #4095 Phase 2
- packages/core/src/index.ts: move atomicFileWrite export to its
  alphabetical position (before browser.js)
- tipHistory.ts: add forceMode: true to atomicWriteFileSync for
  consistency with other 0o600 sites — heals legacy 0o644 files even
  though tips are non-critical

Refs: #4095 Phase 2
Three issues caught by post-merge Codex review of the #4095 Phase 2
branch — none had user-visible symptoms yet but all were latent bugs.

1. atomicFileWrite: forceMode without mode silently downgraded perms
   `if (!options?.forceMode)` skipped the existing-mode stat whenever
   forceMode was true, regardless of whether `mode` was also supplied.
   Calling `atomicWriteFile(p, data, { forceMode: true })` (no mode) on
   an existing 0o600 file produced 0o644 (umask default) instead of
   preserving 0o600. Tightened the guard to also require `options.mode`
   to be defined; mirrored fix in atomicWriteFileSync. Added two
   regression tests (async + sync) that assert mode preservation.

2. logger.test.ts: vi.resetAllMocks() blanked the atomicWriteFile shim
   The vi.fn(actual.atomicWriteFile) factory implementation gets reset
   to a no-op by `vi.resetAllMocks()` in beforeEach, which would make
   `logger.initialize()` silently skip creating logs.json on disk.
   Tests passed by coincidence (file pre-existence from prior runs).
   Captured the real implementation at module load and re-attach it via
   `mockImplementation` after each reset.

3. NativeLspService.applyTextEdits: atomic write bypassed file unwritability
   The read catch swallowed every error and treated it as "new empty
   file". With atomic write (tmp + rename), an unreadable target on a
   writable parent could be replaced with edits applied to an empty
   buffer — the old fs.writeFileSync would have errored on the target
   permission. Now only ENOENT is treated as new-file; other read
   errors (EACCES, EISDIR, etc.) propagate.

Refs: #4095 Phase 2
The previous fix only handled "read failed → propagate the error".
Codex round 2 caught the remaining gap: a file that's readable but
chmod 0444 (read-only) would still be replaced by the atomic rename,
because rename only needs parent-directory write access.

Add an explicit fs.accessSync(W_OK) check before the atomic write.
ENOENT is allowed through so LSP can still create new files via edits.

Refs: #4095 Phase 2
…nd 3)

`saveCredentialsToFile` wrapped `atomicWriteFile` in `withTimeout(5000)`.
If the call hits the 5s budget (e.g. slow NFS home, network-backed
storage, fsync added by Phase 2), withTimeout rejects but the
atomicWriteFile internal write+rename keeps running unobserved:

  1. withTimeout rejects → saveCredentialsToFile throws
  2. performTokenRefresh `finally` releases the refresh lock
  3. Another process acquires the lock and writes newer credentials
  4. The original atomicWriteFile finally completes its rename and
     overwrites the newer credentials — silent token rollback

Pre-migration the code awaited the tmp write and the rename in two
separate withTimeout calls; a timed-out tmp write never reached the
rename so there was no race against the target file. The migration
collapsed both into one inseparable atomicWriteFile, which made the
timeout actively unsafe (the work cannot be cancelled after the
timeout fires — fs.rename is not abortable).

Atomic write is durable by design — accept the I/O latency. The
mkdir and stat timeouts are kept (idempotent and read-only
respectively, no corruption risk on late completion).

Refs: #4095 Phase 2
Copilot AI review requested due to automatic review settings May 19, 2026 16:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR expands the atomic file-write rollout across core persistence paths, focusing on credential safety, JSONL/session durability, memory metadata, config/state files, and LSP-driven edits.

Changes:

  • Adds synchronous atomic write support and forceMode permission tightening.
  • Migrates high-value bare writes/appends to atomic writes or flushed appends.
  • Updates affected unit tests and mocks to validate the new write paths.

Reviewed changes

Copilot reviewed 31 out of 31 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/core/src/utils/atomicFileWrite.ts Adds forceMode, sync atomic write helper, and sync rename retry support.
packages/core/src/utils/atomicFileWrite.test.ts Adds sync helper and forceMode regression coverage.
packages/core/src/utils/jsonl-utils.ts Flushes JSONL appends and atomically rewrites full JSONL files.
packages/core/src/utils/debugLogger.ts Flushes debug log appends.
packages/core/src/utils/debugLogger.test.ts Updates append expectations for flushed writes.
packages/core/src/utils/projectSummary.ts Uses atomic write for welcome-back state.
packages/core/src/utils/installationManager.ts Uses sync atomic write for installation ID persistence.
packages/core/src/core/logger.ts Uses atomic writes for log and checkpoint JSON files.
packages/core/src/core/logger.test.ts Mocks atomic writes while preserving real disk behavior by default.
packages/core/src/qwen/qwenOAuth2.ts Writes cached Qwen credentials atomically with restricted mode.
packages/core/src/qwen/qwenOAuth2.test.ts Adds atomic write mock.
packages/core/src/qwen/sharedTokenManager.ts Replaces manual temp/rename credential write with atomic helper.
packages/core/src/qwen/sharedTokenManager.test.ts Updates credential save mocks.
packages/core/src/mcp/oauth-token-storage.ts Stores MCP OAuth token files with atomic restricted writes.
packages/core/src/mcp/oauth-token-storage.test.ts Updates tests for atomic token writes.
packages/core/src/mcp/token-storage/file-token-storage.ts Stores encrypted token file with atomic restricted write.
packages/core/src/mcp/token-storage/file-token-storage.test.ts Updates encrypted token write expectations.
packages/core/src/memory/manager.ts Writes auto-memory metadata atomically.
packages/core/src/memory/indexer.ts Writes memory index atomically.
packages/core/src/memory/forget.ts Writes memory metadata and topic files atomically.
packages/core/src/memory/extract.ts Writes extraction cursor and metadata atomically.
packages/core/src/memory/dream.ts Writes dream metadata atomically.
packages/core/src/tools/todoWrite.ts Writes todo state atomically.
packages/core/src/tools/todoWrite.test.ts Updates todo write tests for atomic helper.
packages/core/src/lsp/NativeLspService.ts Applies LSP edits via sync atomic write with read/write error handling.
packages/core/src/hooks/trustedHooks.ts Writes trusted hooks config atomically.
packages/core/src/extension/extensionManager.ts Writes extension enablement and install metadata atomically.
packages/core/src/index.ts Re-exports atomic file write utilities.
packages/cli/src/services/tips/tipHistory.ts Writes tip history atomically with restricted mode.
packages/cli/src/config/trustedFolders.ts Writes trusted folders config atomically with restricted mode.
packages/cli/src/config/trustedFolders.test.ts Updates trusted folder save expectations.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

wenshao
wenshao previously approved these changes May 19, 2026
Comment thread packages/core/src/utils/atomicFileWrite.ts
Comment thread packages/core/src/utils/atomicFileWrite.ts
@doudouOUC doudouOUC self-assigned this May 19, 2026
Comment thread packages/core/src/utils/jsonl-utils.ts
…bling-cook

# Conflicts:
#	packages/core/src/qwen/qwenOAuth2.ts
Address PR review suggestions from wenshao (via qwen-latest /review):
neither renameWithRetry/Sync nor the EXDEV cross-device fallback had
direct test coverage. Both paths are critical (Windows AV contention,
Docker tmpfs /tmp) and a regression would degrade silently.

Vitest can't spy on ESM exports of `node:fs` (`Cannot redefine property:
renameSync`), so add narrow internal test seams instead:
- renameWithRetry / renameWithRetrySync take an optional `_renameImpl`
  parameter, defaulting to fs.rename / fs.renameSync.
- atomicWriteFile / atomicWriteFileSync take an optional `_testFs`
  parameter with `rename` and `writeFile` overrides, forwarded to the
  retry helper and used in the EXDEV fallback branch.

The seams are underscore-prefixed and JSDoc-tagged as "Internal test
seam — production callers never pass this", which keeps the public API
clean while making the behavior testable.

New coverage (+9 tests, 36 → 45):
- renameWithRetry: retry-EPERM-then-succeed, give-up after retries,
  no-retry on non-retryable (ENOSPC)
- renameWithRetrySync: same 3 patterns (EACCES, EPERM exhausted, EINVAL)
- EXDEV fallback: async direct write + tmp cleanup, sync ditto,
  non-EXDEV failure propagates without fallback (rejects EIO + tmp cleanup)

Refs: #4333, #4095 Phase 2
@github-actions

github-actions Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 77.83% 77.83% 80.76% 80.17%
Core 80.99% 80.99% 82.96% 83.34%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   77.83 |    80.17 |   80.76 |   77.83 |                   
 src               |   72.61 |    67.22 |   76.19 |   72.61 |                   
  gemini.tsx       |   62.68 |    63.33 |   71.42 |   62.68 | ...1163-1166,1178 
  ...ractiveCli.ts |   78.61 |    66.66 |      75 |   78.61 | ...1299-1300,1336 
  ...liCommands.ts |    74.9 |     75.6 |     100 |    74.9 | ...41-265,290,391 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   65.32 |    65.74 |   85.24 |   65.32 |                   
  acpAgent.ts      |   65.05 |    65.95 |   85.96 |   65.05 | ...2076,2090-2098 
  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 |   75.82 |     72.1 |   86.41 |   75.82 |                   
  ...ryReplayer.ts |   67.34 |     75.6 |   81.81 |   67.34 | ...54-269,282-283 
  Session.ts       |   74.87 |    70.87 |   88.67 |   74.87 | ...2694,2700-2703 
  ...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/commands      |   45.67 |    85.71 |   43.47 |   45.67 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   94.73 |      100 |      50 |   94.73 | 28                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
  serve.ts         |    8.02 |      100 |       0 |    8.02 | ...56-152,154-266 
 ...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 | ...39-142,145-153 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |      100 |     100 |     100 |                   
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  uninstall.ts     |    37.5 |      100 |   33.33 |    37.5 | 23-45,57-64,67-70 
  update.ts        |   96.32 |      100 |     100 |   96.32 | 101-105           
  utils.ts         |   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              
 src/commands/mcp  |   92.29 |    86.08 |   88.88 |   92.29 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 293               
  list.ts          |   91.22 |    80.76 |      80 |   91.22 | ...19-121,146-147 
  reconnect.ts     |   76.72 |    71.42 |   85.71 |   76.72 | 35-48,153-175     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   11.57 |      100 |       0 |   11.57 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   11.32 |      100 |       0 |   11.32 | ...41-153,155-156 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 src/config        |   92.65 |    84.54 |   89.47 |   92.65 |                   
  auth.ts          |   86.98 |    80.32 |     100 |   86.98 | ...26-227,243-244 
  config.ts        |   86.59 |     83.1 |   81.48 |   86.59 | ...1962,1964-1972 
  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 | ...95-197,212-213 
 ...nfig/migration |   94.89 |    78.94 |   83.33 |   94.89 |                   
  index.ts         |   94.87 |    88.88 |     100 |   94.87 | 91-92             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.74 |       96 |     100 |   94.74 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.19 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   63.09 |    64.51 |   55.55 |   63.09 |                   
  ...tputBridge.ts |   62.94 |    65.51 |   56.25 |   62.94 | ...22-323,331-334 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   81.47 |    75.94 |   65.71 |   81.47 |                   
  index.ts         |   63.68 |    69.56 |   53.84 |   63.68 | ...70-271,281-286 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,184   
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |   72.57 |    71.12 |   74.07 |   72.57 |                   
  session.ts       |   76.64 |     69.4 |   85.71 |   76.64 | ...23-824,833-843 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...90-591,594-595 
 ...active/control |   76.79 |    88.23 |      80 |   76.79 |                   
  ...rolContext.ts |    6.89 |        0 |       0 |    6.89 | 50-86             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...54-372,388,391 
  ...rolService.ts |       8 |        0 |       0 |       8 | 46-179            
 ...ol/controllers |   27.25 |    35.71 |   36.66 |   27.25 |                   
  ...Controller.ts |   36.97 |       80 |      80 |   36.97 | ...15-117,127-210 
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    33.7 |    34.48 |   44.44 |    33.7 | ...57-466,481-486 
  ...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.44 |    78.92 |   92.93 |   79.44 |                   
  auth.ts          |   88.49 |    88.63 |     100 |   88.49 | ...49-150,153-155 
  capabilities.ts  |     100 |     90.9 |     100 |     100 | 264               
  ...usProvider.ts |   67.01 |    51.42 |     100 |   67.01 | ...40-245,278-286 
  debugMode.ts     |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  envSnapshot.ts   |    92.3 |       84 |     100 |    92.3 | 108-111,170-177   
  eventBus.ts      |     100 |      100 |     100 |     100 |                   
  httpAcpBridge.ts |   79.99 |    79.16 |   96.47 |   79.99 | ...4270,4301-4342 
  ...oryChannel.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-106             
  loopbackBinds.ts |     100 |      100 |     100 |     100 |                   
  runQwenServe.ts  |   73.98 |    87.83 |   55.55 |   73.98 | ...94-710,735-737 
  server.ts        |   86.18 |    82.94 |   90.62 |   86.18 | ...2478,2543-2552 
  status.ts        |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...paceAgents.ts |   64.87 |    70.45 |    90.9 |   64.87 | ...1306,1316-1326 
  ...paceMemory.ts |   87.13 |    78.46 |     100 |   87.13 | ...54-361,421-428 
 src/serve/auth    |   86.54 |    78.75 |   93.75 |   86.54 |                   
  deviceFlow.ts    |   96.33 |    79.51 |    97.5 |   96.33 | ...1526,1630,1700 
  ...owProvider.ts |   45.23 |    74.07 |      75 |   45.23 | ...90-359,375,379 
 src/serve/fs      |   84.85 |    79.75 |     100 |   84.85 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 201               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.82 |    77.08 |     100 |   77.82 | ...64,493-497,510 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...FileSystem.ts |   83.55 |    76.22 |     100 |   83.55 | ...1859,1886-1887 
 src/serve/routes  |   89.41 |       70 |     100 |   89.41 |                   
  ...ceFileRead.ts |   94.41 |    76.92 |     100 |   94.41 | ...28-329,390-392 
  ...eFileWrite.ts |    82.1 |    60.52 |     100 |    82.1 | ...42-244,247-249 
 src/services      |   91.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 | ...10-211,277-278 
  ...mandLoader.ts |     100 |      100 |     100 |     100 |                   
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.21 |    96.66 |     100 |   98.21 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |    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.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.35 |    84.84 |     100 |   97.35 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   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    |   93.75 |    83.33 |      80 |   93.75 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   64.71 |    73.17 |   59.67 |   64.71 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   63.54 |    64.74 |      50 |   63.54 | ...3191,3195-3199 
  ...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.97 |    51.21 |   42.42 |   52.97 |                   
  AuthDialog.tsx   |   62.87 |     42.1 |   18.18 |   62.87 | ...03,310-332,336 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |    39.4 |       32 |   38.46 |    39.4 | ...68,471,477,480 
  useAuth.ts       |   94.55 |    73.52 |     100 |   94.55 | ...19-220,239-245 
  ...rSetupFlow.ts |   43.45 |    33.33 |      50 |   43.45 | ...68-389,406-449 
 src/ui/commands   |   77.26 |    81.31 |   84.67 |   77.26 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.04 |    81.25 |     100 |   89.04 | 91-92,94-99       
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...91-596,681-689 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |    96.1 |    74.07 |     100 |    96.1 | 149-154           
  bugCommand.ts    |   81.13 |    71.42 |     100 |   81.13 | 60-69             
  clearCommand.ts  |      92 |    76.47 |     100 |      92 | 43-44,72-73,91-92 
  ...essCommand.ts |    64.7 |       50 |      75 |    64.7 | ...48-149,163-166 
  ...extCommand.ts |   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             
  goalCommand.ts   |   91.41 |    84.44 |      90 |   91.41 | ...86-189,201-204 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.13 |    65.71 |   85.71 |   81.13 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  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        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   75.09 |    78.18 |      75 |   75.09 | ...20-225,262-267 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...berCommand.ts |   32.43 |      100 |      50 |   32.43 | 23-57             
  renameCommand.ts |   85.71 |    86.04 |     100 |   85.71 | ...02-209,216-221 
  ...oreCommand.ts |    92.3 |    87.87 |     100 |    92.3 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |      80 |      100 |      50 |      80 | 19-21             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |   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 |   63.22 |    76.38 |   64.42 |   63.22 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |   89.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 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.98 |      100 |       0 |   11.98 | 65-508            
  DiffDialog.tsx   |    2.47 |      100 |       0 |    2.47 | 68-732            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   77.48 |    54.76 |     100 |   77.48 | ...41,165,186-191 
  ...ngSpinner.tsx |   68.42 |       80 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   76.19 |    81.81 |     100 |   76.19 | 24-30,46-50       
  Header.tsx       |   98.62 |    94.28 |     100 |   98.62 | 162,164           
  Help.tsx         |   98.32 |       90 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |    61.7 |       36 |     100 |    61.7 | ...42,345,348-354 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   80.44 |    79.62 |   83.33 |   80.44 | ...1461,1593,1643 
  ...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  |   84.54 |    81.15 |   66.66 |   84.54 | ...87-290,347-351 
  MemoryDialog.tsx |   61.87 |    76.05 |    62.5 |   61.87 | ...72,391,428-430 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   80.12 |    63.55 |     100 |   80.12 | ...39-555,612-616 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   41.26 |    61.53 |   71.42 |   41.26 | ...74-472,476-520 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   92.42 |    84.37 |     100 |   92.42 | ...,70-71,143-145 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...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 |     100 |      100 |     100 |     100 |                   
  ...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 | 20-131            
  ...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.37 |   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.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   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 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   79.06 |      100 |      70 |   79.06 | ...51-264,268-280 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...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.2 |    79.98 |   95.45 |    86.2 |                   
  ...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    |   77.77 |    48.78 |      80 |   77.77 | ...14-218,230-236 
  ...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.7 |    80.78 |   97.91 |    85.7 | ...2604,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 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |   21.51 |    59.52 |   27.27 |   21.51 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   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.53 |   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.84 |     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 | ...56-259,263-266 
  ...gsContext.tsx |   83.33 |       50 |     100 |   83.33 | 17-18             
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...nsContext.tsx |   88.23 |       50 |     100 |   88.23 | 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/hooks      |   82.59 |    82.51 |   87.22 |   82.59 |                   
  ...dProcessor.ts |   83.12 |    82.56 |     100 |   83.12 | ...88-389,408-435 
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...dProcessor.ts |    94.8 |    70.58 |     100 |    94.8 | ...76-277,282-283 
  ...dProcessor.ts |   78.59 |     64.7 |   71.42 |   78.59 | ...06,930,951-955 
  ...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 |   94.04 |    94.11 |     100 |   94.04 | 47,119-122        
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   63.15 |       75 |      50 |   63.15 | 42-52,64-67       
  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       
  ...derUpdates.ts |   86.49 |    77.96 |    90.9 |   86.49 | ...26,288-300,348 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |    84.7 |    93.33 |     100 |    84.7 | ...71-276,372-382 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   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.74 |     100 |   96.98 | ...83-184,238-241 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...Completion.ts |    82.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 |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       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             
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |   14.28 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |   14.28 |     100 |                   
 src/ui/state      |   94.91 |    81.81 |     100 |   94.91 |                   
  extensions.ts    |   94.91 |    81.81 |     100 |   94.91 | 68-69,88          
 src/ui/themes     |   98.53 |    70.58 |     100 |   98.53 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |     100 |      100 |     100 |     100 |                   
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   87.98 |    82.89 |     100 |   87.98 | ...48-357,362-363 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   84.12 |    82.82 |    92.5 |   84.12 |                   
  ...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.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  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 |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.61 |    94.84 |   92.85 |   97.61 | ...50-251,386-387 
  todoSnapshot.ts  |   89.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         |   77.35 |    90.36 |   94.09 |   77.35 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.72 |    97.14 |     100 |   96.72 | 165-168           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   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  |   70.98 |       75 |     100 |   70.98 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.17 |     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      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...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 |                   
  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-1047            
  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 | 130-131,305       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   95.12 |    89.06 |     100 |   95.12 | ...43-244,249-253 
  ...InfoFields.ts |    87.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          |   80.99 |    83.34 |   82.96 |   80.99 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   88.06 |    79.77 |   92.13 |   88.06 |                   
  ...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 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |   76.54 |    66.87 |   78.72 |   76.54 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.37 |    63.37 |   78.26 |   75.37 | ...1860,1866-1867 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   76.29 |    86.15 |   73.04 |   76.29 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.25 |    90.62 |   86.66 |   91.25 | ...94,249-269,328 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   81.78 |    77.83 |   73.04 |   81.78 |                   
  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 |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   78.47 |    82.96 |   64.64 |   78.47 |                   
  config.ts        |   76.44 |    81.93 |   60.08 |   76.44 | ...4064,4075-4087 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   95.01 |     90.9 |   90.47 |   95.01 | ...71-372,375-376 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   88.61 |    83.63 |   92.16 |   88.61 |                   
  baseLlmClient.ts |   87.24 |    76.47 |    87.5 |   87.24 | ...82,484-494,503 
  client.ts        |   87.39 |    80.57 |   86.36 |   87.39 | ...2071,2110-2113 
  ...tGenerator.ts |    72.1 |    61.11 |     100 |    72.1 | ...63,365,372-375 
  ...lScheduler.ts |   87.52 |    82.15 |   94.82 |   87.52 | ...3254,3315-3326 
  geminiChat.ts    |   91.41 |    87.44 |   97.29 |   91.41 | ...2812,2879-2880 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | 34-42,45-49,52-87 
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   86.48 |    72.22 |     100 |   86.48 | ...97-198,212-221 
  ...issionFlow.ts |   98.59 |       95 |     100 |   98.59 | 93                
  prompts.ts       |    89.2 |    86.41 |   76.92 |    89.2 | ...-960,1163-1164 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...okTriggers.ts |   99.33 |    90.47 |     100 |   99.33 | 156,167           
  turn.ts          |   96.46 |    88.88 |     100 |   96.46 | ...32,445-446,494 
 ...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 |   83.02 |    85.22 |   91.02 |   83.02 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   79.28 |    84.29 |   88.46 |   79.28 | ...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.66 |    88.94 |   96.07 |   96.66 |                   
  dashscope.ts     |   97.35 |    91.39 |   93.33 |   97.35 | ...90-291,367-368 
  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/extension     |   62.35 |    79.54 |   80.31 |   62.35 |                   
  ...-converter.ts |   66.21 |    52.45 |     100 |   66.21 | ...85-786,795-827 
  ...ionManager.ts |    47.1 |    82.06 |    65.9 |    47.1 | ...1404,1414-1433 
  ...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/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         |   85.61 |    84.87 |   87.14 |   85.61 |                   
  ...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.56 |    71.26 |   66.66 |   58.56 | ...48-749,758-759 
  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  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   91.24 |    92.13 |   85.71 |   91.24 | ...42-443,503-507 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   75.55 |    83.52 |   78.33 |   75.55 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   66.14 |    81.75 |   66.66 |   66.14 | ...7-968,997-1005 
  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           |   42.41 |    52.21 |   52.14 |   42.41 |                   
  ...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 |   51.85 |    65.98 |   68.57 |   51.85 | ...1339,1399-1409 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   78.75 |    75.45 |   75.92 |   78.75 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.64 |    97.72 |     100 |   98.64 | 88-89             
  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.72 |    87.05 |   86.36 |   79.72 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   83.44 |    84.21 |   92.85 |   83.44 | ...68-178,186-187 
  ...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        |   71.03 |    75.44 |    69.1 |   71.03 |                   
  const.ts         |     100 |      100 |     100 |     100 |                   
  dream.ts         |      66 |    73.33 |      50 |      66 | 51,108-149        
  ...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.23 |    79.16 |     100 |   95.23 | 82-87,126         
  ...entPlanner.ts |   63.08 |    65.71 |   41.17 |   63.08 | ...17,222-223,332 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |      46 |    61.53 |   44.44 |      46 | ...05,212,215-347 
  indexer.ts       |   84.61 |    45.45 |     100 |   84.61 | ...51,57-58,70-71 
  manager.ts       |   75.34 |    81.04 |    75.6 |   75.34 | ...1279,1292-1294 
  memoryAge.ts     |   90.47 |    77.77 |     100 |   90.47 | 50-51             
  paths.ts         |   55.47 |    89.47 |   85.71 |   55.47 | ...,89-90,106-114 
  prompt.ts        |   93.36 |    71.42 |     100 |   93.36 | ...58,161,228-229 
  recall.ts        |   77.54 |    69.38 |   88.88 |   77.54 | ...53-258,282-293 
  ...ceSelector.ts |   91.86 |    77.27 |     100 |   91.86 | ...15,117-118,126 
  scan.ts          |   87.91 |    68.42 |     100 |   87.91 | ...47-48,58,82-87 
  ...entPlanner.ts |   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 |    78.33 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.63 |    86.61 |   87.83 |   89.63 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.24 |    91.42 |     100 |   90.24 | 142,148,151-160   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.66 |    92.85 |     100 |   98.66 | 162,324,330       
  modelRegistry.ts |     100 |    98.59 |     100 |     100 | 222               
  modelsConfig.ts  |   85.37 |    83.42 |    82.5 |   85.37 | ...1272,1301-1302 
  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.33 |    89.42 |   59.32 |   76.33 |                   
  autoMode.ts      |    92.1 |    89.58 |     100 |    92.1 | ...09,225,227-237 
  ...transcript.ts |      98 |    84.61 |     100 |      98 | 200-201           
  classifier.ts    |   92.89 |    91.42 |     100 |   92.89 | 146-153,333-337   
  ...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   |   97.37 |    93.82 |     100 |   97.37 | ...-875,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/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/providers     |   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/qwen          |   84.48 |     77.6 |   95.83 |   84.48 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   80.85 |    70.74 |   90.32 |   80.85 | ...1169-1185,1215 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/services      |   85.76 |    83.67 |   91.72 |   85.76 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.35 |    85.34 |     100 |   97.35 | ...94,117,417-418 
  ...ionService.ts |   97.87 |    93.82 |     100 |   97.87 | 383,385-389,486   
  ...ingService.ts |   83.88 |    83.22 |   83.33 |   83.88 | ...1268,1285-1286 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |     100 |    97.43 |     100 |     100 | 215,268           
  cronScheduler.ts |   97.56 |    92.98 |     100 |   97.56 | 62-63,77,155      
  ...eryService.ts |   80.43 |    95.45 |      75 |   80.43 | ...19-134,140-141 
  ...oryService.ts |   86.18 |    76.76 |   91.17 |   86.18 | ...1150,1191-1194 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   91.27 |    82.69 |    90.9 |   91.27 | ...94,196,294-301 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  gitService.ts    |   68.75 |     92.3 |   55.55 |   68.75 | ...12-122,125-129 
  ...reeService.ts |    69.4 |    68.82 |   93.33 |    69.4 | ...2064,2092-2093 
  ...ionService.ts |   98.13 |     97.8 |   95.45 |   98.13 | ...32-333,380-381 
  ...ureMonitor.ts |    95.2 |    91.36 |      96 |    95.2 | ...88,589,603-605 
  ...orRegistry.ts |   96.54 |    91.73 |     100 |   96.54 | ...70-471,622-623 
  ...ttachments.ts |   96.81 |       90 |     100 |   96.81 | ...06,612,627-628 
  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 |    71.15 |     100 |   93.87 | ...33-236,267-268 
  ...ionService.ts |   81.24 |    78.31 |   89.28 |   81.24 | ...1923,1929-1934 
  ...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.21 |    79.41 |     100 |   84.21 | ...18-219,235-236 
 ...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     |   82.61 |    78.89 |   95.23 |   82.61 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   77.15 |    71.36 |    93.1 |   77.15 | ...1178,1200-1201 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 51-56,69-74,78-83 
 src/telemetry     |   77.76 |    89.04 |   80.85 |   77.76 |                   
  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 |    64.93 |      60 |   53.34 | ...1215,1232-1252 
  metrics.ts       |   75.03 |    82.95 |   74.54 |   75.03 | ...8-988,991-1002 
  ...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 |    94.59 |   84.93 |   80.37 | ...1151,1154-1183 
  uiTelemetry.ts   |   92.97 |    96.96 |   81.25 |   92.97 | ...93-194,200-207 
 ...ry/qwen-logger |   69.37 |     80.2 |   66.66 |   69.37 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   69.37 |       80 |   66.07 |   69.37 | ...1056,1094-1095 
 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         |   79.34 |    81.79 |   86.01 |   79.34 |                   
  ...erQuestion.ts |   88.93 |    76.74 |    90.9 |   88.93 | ...39-340,347-348 
  cron-create.ts   |   88.11 |    88.88 |    62.5 |   88.11 | ...,43-44,165-172 
  cron-delete.ts   |   96.82 |      100 |   83.33 |   96.82 | 26-27             
  cron-list.ts     |   96.66 |      100 |   83.33 |   96.66 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   81.02 |    84.07 |      75 |   81.02 | ...15-716,826-876 
  ...r-worktree.ts |   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.62 |    84.05 |   88.46 |   91.62 | ...85,598,794-799 
  notebook-edit.ts |   85.11 |    76.42 |   81.25 |   85.11 | ...54-870,916-917 
  ...nforcement.ts |   82.57 |       90 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |    95.4 |    90.32 |      90 |    95.4 | ...99,298-301,304 
  ripGrep.ts       |   94.59 |    85.71 |   93.33 |   94.59 | ...60,463,541-542 
  ...-transport.ts |    6.34 |      100 |       0 |    6.34 | 47-145            
  send-message.ts  |   84.68 |    91.66 |    62.5 |   84.68 | ...,82-90,167-170 
  shell.ts         |   73.49 |    80.03 |   91.42 |   73.49 | ...4243,4292-4298 
  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-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  todoWrite.ts     |   89.27 |    82.05 |   92.85 |   89.27 | ...44-549,571-572 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   74.85 |    76.85 |   80.95 |   74.85 | ...30-831,839-840 
  tool-search.ts   |   95.19 |    86.48 |    92.3 |   95.19 | ...47-153,208-213 
  tools.ts         |   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     
 src/utils         |   89.65 |     87.9 |   94.37 |   89.65 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.76 |    93.06 |     100 |   94.76 | ...30-531,634-638 
  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.9 |    93.93 |   94.73 |    95.9 | 106-107,222-226   
  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  |    97.7 |    97.05 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.54 |    79.59 |      50 |   70.54 | ...15-231,235-241 
  fetch.ts         |   70.18 |    71.42 |   71.42 |   70.18 | ...42,148,161,186 
  fileUtils.ts     |    91.5 |    86.13 |   95.23 |    91.5 | ...1191,1195-1201 
  forkedAgent.ts   |   80.68 |    78.12 |   83.33 |   80.68 | ...39-545,550-556 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  gitDiff.ts       |   92.36 |    79.53 |     100 |   92.36 | ...55-856,928-929 
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   73.64 |    90.32 |   83.33 |   73.64 | ...,78-79,103-154 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   88.98 |    90.66 |   91.66 |   88.98 | ...46-349,359-365 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |    96.4 |     90.9 |     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.21 |    91.86 |     100 |   93.21 | ...89-390,392-394 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   92.55 |    85.92 |     100 |   92.55 | ...70-272,309-310 
  readManyFiles.ts |   87.59 |       84 |     100 |   87.59 | ...09-211,227-238 
  retry.ts         |   89.81 |    88.05 |     100 |   89.81 | ...29,350,357-358 
  ripgrepUtils.ts  |   46.79 |    84.37 |   66.66 |   46.79 | ...45-246,258-335 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   81.72 |    85.04 |   95.23 |   81.72 | ...18,543,572-581 
  runtimeStatus.ts |    97.5 |    88.57 |     100 |    97.5 | 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   |   84.22 |    89.91 |     100 |   84.22 | ...1583,1590-1594 
  ...lAstParser.ts |   95.58 |    85.79 |     100 |   95.58 | ...1067-1069,1079 
  ...nlyChecker.ts |    95.1 |    91.57 |     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   |      92 |     84.9 |     100 |      92 | 49-53,65-69       
 ...ils/filesearch |   86.21 |    81.61 |   96.42 |   86.21 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.84 |    77.49 |   94.82 |   82.84 | ...1451,1485-1486 
  fileSearch.ts    |   93.58 |    87.32 |     100 |   93.58 | ...46-247,249-250 
  ignore.ts        |     100 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |     92.3 |     100 |     100 | 46                
 ...uest-tokenizer |   56.63 |    74.52 |   74.19 |   56.63 |                   
  ...eTokenizer.ts |   41.86 |    76.47 |   69.23 |   41.86 | ...70-443,453-507 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |      76 |      100 |   33.33 |      76 | 45-48,55-56       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

…sh:true

CI failure on all 3 OSes (macos / ubuntu / windows): sdk.test.ts asserted
`fs.appendFile` was called with `'utf8'` as the 3rd positional argument,
but commit b7badc7 (#4095 Tier 3b — JSONL fsync) changed the
`debugLogger.ts` appendFile call from string-form to options-form
`{ encoding: 'utf8', flush: true }` to enable per-line fsync. Update the
3 assertions in the telemetry diagnostics test to match the new shape.

No behavior change — debugLogger still flushes per append; only the
assertion in this previously-unrelated suite needed updating.

Refs: #4333, #4095 Phase 2 Tier 3b
@doudouOUC doudouOUC requested a review from wenshao May 19, 2026 23:46

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] qwenOAuth2.ts cacheQwenCredentials was de-migrated from atomicWriteFile back to a hand-rolled temp+chmod+rename pattern during merge conflict resolution (commit 7b1a7ae38). The PR description still lists qwenOAuth2 under Tier 1 migration and the behavior-changes table references qwen/qwenOAuth2.ts:982, but the file is no longer in the diff and line 982 now points to pollDeviceToken (the function starts at ~1060 after the merge).

The hand-rolled version uses a predictable temp path component (process.pid) versus atomicWriteFile's crypto.randomBytes(6), and lacks EPERM rename retry and EXDEV fallback. Consider either re-migrating to atomicWriteFile (consolidating onto the shared, tested helper) or moving qwenOAuth2 to the "Deliberately not in scope" section with a rationale and fixing the stale line reference.

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

Comment thread packages/core/src/lsp/NativeLspService.ts
Comment thread packages/core/src/utils/atomicFileWrite.ts Outdated
Comment thread packages/core/src/utils/jsonl-utils.ts Outdated
…4333 review)

Address three review suggestions from wenshao (via qwen-latest /review),
each pointing at a real coverage gap introduced by this PR:

1. NativeLspService.applyTextEdits error branches (round-2 LSP fix):
   the ENOENT-only read guard and the fs.accessSync(W_OK) refusal had
   no automated coverage. Added 3 tests accessing applyTextEdits via a
   typed cast (the method is private; making it public for one
   verification inflates API surface). Tests use chmod 0000 / chmod 0444
   reproducers and assert (a) read failure propagates EACCES without
   silently overwriting with empty content, (b) W_OK rejects with
   EACCES/EPERM before the atomic rename touches the target,
   (c) nonexistent files are still accepted so LSP can create via edits.

2. atomicWriteFileSync non-EXDEV rename failure cleanup: the async
   counterpart had an explicit EIO-rename test asserting tmp cleanup;
   the sync variant did not. Added the mirror — injects a sync rename
   throwing EIO via the existing _testFs seam and asserts
   `readdirSync(tmpDir).length === 0`.

3. jsonl-utils writeLine / writeLineSync / write smoke tests: the three
   write paths are the core fix for #3681 (the PR's headline goal) but
   downstream callers (chatRecordingService, sessionService) mock them
   entirely. Without direct unit tests, a regression that dropped
   `flush: true` or reverted `write()` to bare writeFileSync would go
   undetected. Added 3 real-fs roundtrip tests.

Test count delta:
- NativeLspService.test.ts: 15 → 18
- atomicFileWrite.test.ts: 45 → 46
- jsonl-utils.test.ts: 22 → 25

Refs: #4333, #4095 Phase 2
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Re #4333 (review) (cacheQwenCredentials review summary):

Updated the PR body to remove the stale qwenOAuth2.ts:982 reference from the behavior-changes table and moved cacheQwenCredentials into "Deliberately not in scope" with the rationale. Picked defer-with-doc-fix over re-migrate.

Why not re-migrate: upstream PR #4255 added AbortSignal threading + SharedTokenManager.getInstance().clearCache() invalidation into the hand-rolled atomic write. atomicWriteFile does not accept a signal (and fs.rename is not abortable), so re-migrating would silently drop signal cancellation — the exact same race I fixed in this PR's round 3 for sharedTokenManager.saveCredentialsToFile (caller observes timeout / cancel, but the atomic write keeps running and overwrites a newer credential file).

The trade-off is real: upstream's hand-roll loses EPERM retry + EXDEV fallback + symlink chain resolution vs the shared helper. That gap is worth a follow-up that extends atomicWriteFile to honor an AbortSignal so the next migration round can consolidate without regressing cancellation. Filing that as a Phase 2.5 item.

Comment thread packages/core/src/utils/atomicFileWrite.ts
Comment thread packages/core/src/qwen/sharedTokenManager.test.ts
Comment thread packages/core/src/lsp/NativeLspService.test.ts Outdated

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No issues found. LGTM! ✅ — gpt-5.5 via Qwen Code /review

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] saveCredentialsToFile at packages/core/src/qwen/sharedTokenManager.ts calls atomicWriteFile successfully (credentials persisted), then calls fs.stat (wrapped in withTimeout(5000)) to update memoryCache.fileModTime. If fs.stat fails (slow NFS, transient mount issue), the catch block throws TokenManagerError(FILE_ACCESS_ERROR, "Failed to write credentials file: ..."). The error message is misleading: the credentials were successfully written. The failure is only in the cache-update step. In a retry loop, this could trigger an unnecessary token refresh storm. Consider wrapping the fs.stat in its own try/catch that logs but does not propagate the error — memoryCache.fileModTime staleness is self-healing on next read.

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

Comment thread packages/core/src/utils/atomicFileWrite.ts
Comment thread packages/core/src/utils/atomicFileWrite.ts Outdated
Comment thread packages/core/src/hooks/trustedHooks.ts
…dHooks tests

Three PR #4333 round-14 review items:

1. **Path-level tryChmod / tryChmodSync catch narrowing had zero direct
   coverage**. Round-13 narrowed the bare `catch {}` to ENOSYS/ENOTSUP
   only (matching the round-8 fd-level fchmod narrowing), but every
   existing EXDEV test passed `options: undefined`, so `desiredMode ===
   undefined` short-circuited before any chmod was attempted. A
   regression that inverted the catch condition (missing `!` prefix)
   would silently swallow EPERM on every sync credential write
   (trustedHooks, tipHistory, trustedFolders, etc.) with zero
   diagnostic signal. Added 6 tests via the existing `_testFs.chmod`
   seam: parameterized ENOSYS/ENOTSUP swallow + EPERM propagation, for
   both async (`atomicWriteFile`) and sync (`atomicWriteFileSync`).

2. **Orphan-cleanup unlink on the noFollow EXDEV failure path was
   using raw `fs.unlink` / `fsSync.unlinkSync` instead of the
   injected `unlinkImpl` seam**. The pre-open unlink correctly used
   the seam, but the round-9 orphan cleanup added later bypassed it,
   making it the only fs operation in `atomicWriteFile` not flowing
   through the test seam. Routed both async and sync orphan cleanup
   through `unlinkImpl`, and added 2 tests that inject a spy and
   assert orphan cleanup is invoked against targetPath after a
   simulated fchmod EPERM.

3. **`trustedHooks.ts` had no test coverage**. Round-11 migrated it to
   `atomicWriteFileSync` with `{ mode: 0o600, forceMode: true }` —
   strictly the most security-sensitive write in the PR since the
   file stores user-approved executable hook commands — but unlike
   the sibling files (trustedFolders, tipHistory) it had no test
   file. A regression that dropped `forceMode: true` or weakened
   the mode would have passed all existing tests. Created
   `trustedHooks.test.ts` covering: write goes through
   atomicWriteFileSync with `{ mode: 0o600, forceMode: true }`,
   write targets the global qwen dir path, the persisted content
   matches the hook key derived from the hook config, and round-trip
   trust/untrust behavior.

Test results: 73/73 atomicFileWrite tests (was 65) + 5/5
trustedHooks (new). Typecheck clean.

Refs: #4333, #4095 Phase 2
Comment thread packages/core/src/hooks/trustedHooks.ts Outdated
Comment thread packages/core/src/utils/atomicFileWrite.ts
Comment thread packages/core/src/utils/atomicFileWrite.ts Outdated
…eanup through seam

Two PR #4333 round-15 review items:

1. **`trustedHooks.ts` and `trustedFolders.ts` were missing `noFollow:
   true`**. The credential write sites
   (`sharedTokenManager`/`oauth-token-storage`/`file-token-storage`)
   all pass `{ mode: 0o600, forceMode: true, noFollow: true }` to
   prevent pre-placed symlink attacks. The trustedHooks comment
   already called it "strictly more sensitive than trustedFolders /
   tipHistory" — yet credential paths got symlink protection it
   didn't. A pre-placed symlink at `~/.qwen/trusted_hooks.json` (or
   `trustedFolders.json`) could redirect the atomic write to an
   attacker-controlled path, either leaking the executable-trust
   list / trusted-folder list, or leaving the user's real config
   silently stale. Added `noFollow: true` to both write sites and
   updated the assertions in `trustedHooks.test.ts` and
   `trustedFolders.test.ts`.

2. **Tmp-file cleanup at L240 (async) and L568 (sync) used raw
   `fs.unlink` / `fsSync.unlinkSync` instead of the injected
   `unlinkImpl` seam**. Pre-open unlink and orphan cleanup correctly
   routed through `unlinkImpl`, making the tmp-cleanup branch the
   only outlier — `_testFs.unlink`-injecting tests couldn't intercept
   this path, weakening the seam abstraction. Behavioral impact is
   nil (cleanup is best-effort, errors swallowed), but consistency
   matters for future test authors. Routed both async and sync
   variants through `unlinkImpl`.

Test results: 99/99 affected suites pass (atomicFileWrite 73,
trustedHooks 5, trustedFolders 21). Typecheck clean on core.

Refs: #4333, #4095 Phase 2
@wenshao

wenshao commented May 25, 2026

Copy link
Copy Markdown
Collaborator

本地真实测试报告(merge 参考)

在本地完成了 PR body 中描述的两阶段验证(Part 1 库级脚本 + Part 2 tmux + npm run dev + kill -9)。所有关键路径均已通过,可作为合并参考。

测试环境

测试 commit 150469203 (fix(core): add noFollow to trustedHooks/trustedFolders + route tmp cleanup through seam)
平台 macOS arm64 (Darwin 25.4.0)
Node v22.17.0
Worktree /Users/wenshao/Work/git/qwen-code/.qwen/tmp/review-pr-4333(基于 pull/4333/head
模型 API Key auth → qwen3.7-maxselectedType: "openai"

1. 构建与类型检查

npm run build          → 成功(10.7s 主链路 + vscode-ide-companion)
npx tsc --noEmit -p packages/core   → CORE_EXIT=0
npx tsc --noEmit -p packages/cli    → CLI_EXIT=0

⚠️ 提示给 reviewer:在工作树带有过期 packages/core/dist/ 的情况下,packages/cli 的类型检查会因为 AtomicWriteFileOptions 缺少 noFollow 字段而报错。先跑一次 npm run build 即可消除——这是本地 worktree 的副作用,不是 PR 本身的问题(CI 上从干净 checkout 出发不会触发)。

2. 单元测试(针对本 PR 触及的所有路径)

10 个 test 文件、373 个用例全部通过:

Test file Tests 覆盖点
packages/core/src/utils/atomicFileWrite.test.ts 73 atomicWriteFile/SyncforceModenoFollow、EPERM 重试、EXDEV fallback、symlink 链
packages/core/src/utils/jsonl-utils.test.ts 26 writeLine/writeLineSyncflush:true、整文件替换
packages/core/src/utils/debugLogger.test.ts 22 appendFile + flush:true
packages/core/src/mcp/oauth-token-storage.test.ts 28 OAuth token 写入 0o600 + forceMode
packages/core/src/mcp/token-storage/file-token-storage.test.ts 18 通用 file token 存储
packages/core/src/qwen/sharedTokenManager.test.ts 32 凭据写入 + withTimeout 移除后的 token 一致性
packages/core/src/qwen/qwenOAuth2.test.ts 83 设备码流程 + cacheQwenCredentials 保留旧 atomic 实现的取消语义
packages/core/src/core/logger.test.ts 52 logs.json 全文件原子重写 + vi.resetAllMocks 修复
packages/core/src/lsp/NativeLspService.test.ts 18 仅 ENOENT 视为新文件 + accessSync(W_OK) 守卫
packages/cli/src/config/trustedFolders.test.ts 21 trustedFolders.json 同步原子写 + noFollow:true

3. Part 1 — 库级 verify-atomic-helpers 脚本

直接调用源码 atomicWriteFile / atomicWriteFileSync / writeLine / writeLineSync,含 kill -9 子进程:

17 passed, 0 failed

逐项:

  • A1, A2 ✅ 基本写入 + 无 .tmp 残留
  • B1, B2 ✅ 现有 0o600 保留;umask 077 × mode 0o600 落到 0o600
  • C1, C2, C3forceMode 把 0o644 修正回 0o600;forceMode 不带 mode 时保留原权限(Codex round-1 修复,async + sync 都验过)
  • D1, D2 ✅ 通过 symlink 写入更新真实目标且 link 保留;broken symlink 也能创建目标
  • E1 ✅ JSONL writer 子进程写完 5 行 → fsync → kill -9 → 文件 5/5 行全部解析正确,无 }{ 粘连
  • E2writeLineSync 含 flush 的连续 append
  • F1, F2chmod 0444accessSync(W_OK) 抛 EACCES;不存在文件抛 ENOENT(LSP 仅放行后者)

4. Part 2 — 真实 CLI(tmux + npm run dev + kill -9

这是 #3681 最贴近真实失败模式的复现,验证 logger.tslogs.json 全文件改写 与 jsonl-utils.writeLine 的逐 turn append 在硬杀进程下不会损坏。

步骤:

  1. tmux new-session -d -s pr4333 -x 220 -y 50,发送 npm run dev 启动 TUI(API Key | qwen3.7-max)
  2. 发送一段长 prompt,让模型流式输出
  3. ps -A 找到孙进程:root tsx wrapper (46259) → loader.mjs node (46260) → leaf TUI (46583)
  4. 流式途中("19s · ↓ 327 tokens")执行 kill -9 46583
  5. 校验磁盘文件 → 重启 → /resume

结果:

检查 期望 实际
kill -9 46583 后所有 review-pr-4333 进程消失
JSON.parse(logs.json) 解析为数组 ✅ length=29,最后一条 type=user
JSONL 行级解析 + }{ 粘连扫描 全部解析 / 0 粘连 ✅ 7 行,0 parse_failures,0 glued_records
JSONL 末尾 }\n 收尾 endsWithNewline=true, lastBeforeNL=}
杀进程前 vs 杀进程后 JSONL/logs.json 字节数 不被截断 ✅ JSONL 13413→13413,logs 6230→6230
重启后 /resume picker 列出被杀会话 ✅ 「请用大约600字详细描述一个软件工程师调试一个race condition的故事...」「1 minute ago · pr-4333-fresh」 排在最上
选中后会话内容完整加载 ✅ 已完成的 race-condition 故事完整可见,context 2.2%

未在 JSONL 中出现 partial 流式片段——符合预期(per-turn 在 turn 完成时整体写入,未完成的 turn 不会留下半截记录)。

5. 未覆盖范围

诚实声明几项无法在本机验证的项:

  • OAuth refresh + kill -9 端到端:本机使用 API Key 认证,OAuth 路径处于休眠状态。代码层面是同形 atomicWriteFile(creds, {mode:0o600, forceMode:true, noFollow:true}),由 sharedTokenManager.test.ts(32) 与 qwenOAuth2.test.ts(83) 间接覆盖
  • Windows AV 压力下的 renameWithRetry EPERM 重试:无 Windows 主机;现有单测覆盖逻辑分支但非真实 AV
  • atomicWriteFileSyncprocess.exit hook 中的 SharedArrayBuffer blockingSleep:未跑 stress test,相关单测有覆盖

6. 结论

  • ✅ Build / 类型检查 / 单测全绿(373 tests, 10 files, 全 PR 触及路径覆盖)
  • ✅ Part 1 库级 17/17 通过——三轮 Codex review 修复(forceMode-no-mode、LSP accessSync(W_OK)withTimeout 移除)均回归验证
  • ✅ Part 2 真实 CLI kill -9 没有产生任何损坏:logs.json 仍是合法 JSON 数组,JSONL 7/7 行解析无粘连,/resume 完整恢复
  • 行为变化(凭据 0o600 healing、JSONL fsync 引入 +几 ms 延迟、saveCredentialsToFile 移除 5s timeout)已在 PR body 显式列出,与 PR 描述一致

从本地真实测试角度,该 PR 可以合并。 #3681}{ 粘连闭环验证通过,#4095 Phase 2 的所有迁移点行为正确。

@doudouOUC doudouOUC requested a review from wenshao May 27, 2026 12:04

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Round 13 review with qwen3.7-max (second opinion after R12 with qwen-latest-series-invite-beta-v34). tsc + eslint clean. 15,507 tests pass (5 pre-existing failures unrelated to this PR). 2 new Suggestions found (test coverage gaps); 7 additional findings flagged for human review. — qwen3.7-max via Qwen Code /review

Comment thread packages/core/src/utils/atomicFileWrite.ts
Comment thread packages/core/src/utils/atomicFileWrite.test.ts Outdated
Comment thread packages/core/src/hooks/trustedHooks.test.ts Outdated
Comment thread packages/core/src/lsp/NativeLspService.ts
PR #4333 round-15 review item (Critical, from claude-opus-4-8 /qreview):

trustedHooks.test.ts:68 hardcoded a POSIX path
('/mock/home/.qwen/trusted_hooks.json'), but production builds the path
with path.join(Storage.getGlobalQwenDir(), 'trusted_hooks.json')
(trustedHooks.ts:29-31). On Windows path.join emits '\' separators, so
the mocked atomicWriteFileSync receives
'\mock\home\.qwen\trusted_hooks.json' and the toBe assertion fails — the
cause of the red Test (windows-latest, Node 22.x) check. macOS/Linux
runs are green because forward slashes match.

Build the expected path with path.join so it matches the platform
separator, and add the node:path import.

Refs: #4333, #4095 Phase 2
Comment thread packages/cli/src/services/tips/tipHistory.ts
Comment thread packages/cli/src/services/tips/tipHistory.ts
…st coverage + LSP concurrency note

Four PR #4333 follow-up review items from wenshao:

1. tipHistory.ts was missing noFollow: true while the sibling
   0o600+forceMode config sites (trustedFolders.ts:192,
   trustedHooks.ts:63) both set it. The cleanup commit added forceMode
   "for consistency with other 0o600 sites" but stopped short of
   noFollow. All three store user-trusted paths and should share the
   same pre-placed-symlink protection. Added noFollow: true.

2. annotateWriteError idempotency guard had no direct coverage. The
   guard switched from includes(targetPath) to startsWith(fnName+"(")
   because real syscall errors embed the *tmp* path (which contains the
   target as a substring), so the old guard silently skipped annotation
   on every real failure. Added a test where the rename error message
   embeds a tmp-style path containing the target; the correct startsWith
   guard still annotates it, and reverting to includes would fail it.

3. non-EXDEV rename failure tests only asserted /EIO/, not the
   atomicWriteFile(...): / atomicWriteFileSync(...): annotation prefix
   that the production re-throw applies on that path. Tightened both
   async and sync assertions to match the prefix.

4. applyTextEdits concurrency constraint was undocumented. The async
   read-modify-write has await points between read and write;
   atomicWriteFile prevents torn files but does not serialize writers,
   so concurrent same-path edits can lose updates. Latent today (no
   production caller / no workspace/applyEdit handler), so documented
   the per-file-serialization requirement instead of adding a lock.

Not taking: extending the _testFs seam with open/openSync to fault-inject
O_EXCL EEXIST — the noFollow/O_EXCL security behavior is already covered
by the real-fs behavioral tests (noFollow EXDEV fallback refuses to
follow symlinks); a seam-injected EEXIST would only exercise error
propagation, not the guarantee.

Test results: atomicFileWrite 74/74 pass, eslint clean.

Refs: #4333, #4095 Phase 2
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Round-16 review follow-up (31d4a17)

Thread Action
tipHistory.ts noFollow missing Fixed — added noFollow: true to match trustedFolders/trustedHooks
atomicFileWrite.ts:371 annotateWriteError idempotency untested Fixed — added a public-API test guarding the startsWith-vs-includes(targetPath) regression (no private export needed)
atomicFileWrite.test.ts:714 non-EXDEV assertion too loose Fixed — both async/sync assertions now match the annotation prefix
NativeLspService.ts:1372 applyTextEdits concurrency Partial — documented the per-file-serialization requirement; latent today (no production caller), so no lock added yet
atomicFileWrite.ts:269 _testFs.open seam for O_EXCL Not taking — noFollow/O_EXCL is already covered behaviorally by the real-fs tests; a seam-injected EEXIST would only exercise error propagation, not the guarantee. Left this thread unresolved for your call.

Tests: atomicFileWrite 74/74 pass, eslint clean.

wenshao
wenshao previously approved these changes May 31, 2026

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No new issues found. LGTM! ✅

Reviewed the full diff (atomic-write migration of credential / memory / config / logger / JSONL paths + the forceMode/noFollow options and sync helper). All migration sites preserve prior encoding/mode/newline semantics, the async and sync helper variants are semantically equivalent on every path, CI is green, and the targeted suites pass. The exhaustive prior review rounds resolved every substantive concern.

— claude-opus-4-8 via Claude Code /qreview

wenshao
wenshao previously approved these changes Jun 1, 2026

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review

@tanzhenxin

Copy link
Copy Markdown
Collaborator

@doudouOUC heads-up — this branch went stale and now conflicts with main. It was clean when it was approved (2026-06-01), but #4431 ("preserve uid in atomicWriteFile", 7448724d8) landed on main later that day and rewrote the same file.

The conflict is one file: packages/core/src/utils/atomicFileWrite.ts. The other touched files auto-merge cleanly.

One thing to watch while resolving: #4431 added the ownershipWouldChange() in-place fallback (preserves the original uid on shared-write files instead of letting rename strip it). Resolving the conflict toward this branch would drop it, so it'll need to be re-integrated into the rewritten control flow. The auto-merged test file keeps #4431's ownership tests, which should flag it if it's missed.

Could you merge origin/main and resolve? You have full context here, having authored both PRs.

doudouOUC added 2 commits June 2, 2026 14:44
…bling-cook

# Conflicts:
#	packages/core/src/utils/atomicFileWrite.ts

@tanzhenxin tanzhenxin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-checked after the merge of main: the #4431 ownership preservation is correctly re-integrated — ownershipWouldChange() + the in-place uid fallback are back in atomicWriteFile, and all 5 ownership regression tests are present, so the stale-base concern is resolved. CI is green on the current head (Test matrix passes on macOS / Ubuntu / Windows). LGTM 👍

@doudouOUC doudouOUC requested a review from wenshao June 2, 2026 08:50
@doudouOUC doudouOUC merged commit 27a7e8a into main Jun 2, 2026
17 of 22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

chore(core): jsonl reader/writer follow-ups from #3656

5 participants