Skip to content

feat(core,cli): surface and cancel auto-memory dream tasks#3836

Merged
tanzhenxin merged 17 commits into
mainfrom
feat/dream-bg-task
May 6, 2026
Merged

feat(core,cli): surface and cancel auto-memory dream tasks#3836
tanzhenxin merged 17 commits into
mainfrom
feat/dream-bg-task

Conversation

@wenshao

@wenshao wenshao commented May 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Brings managed auto-memory dream consolidation tasks into the unified Background tasks UI and makes them cancellable. Today, dream tasks fire silently in the background (scheduled per UserQuery via MemoryManager.scheduleDream) — the user only sees a memory_saved toast on completion, with no signal about what's running, what it's reviewing, or what failed, and no way to stop a runaway consolidation that's burning model tokens.

This PR adds:

  • Footer pill counts dreams alongside other kinds (e.g. 1 shell, 1 dream)
  • Combined dialog list shows [dream] memory consolidation reviewing N sessions
  • Per-kind detail body shows sessions reviewing, progress text, topics touched, errors
  • x stop keystroke from the dialog cancels via MemoryManager.cancelTask
  • task_stop tool gets a 4th dispatch route so the model can also cancel
  • MemoryTaskStatus gains 'cancelled'; cancellation aborts the dream fork-agent and lets the existing runDream finally block release the consolidation lock as the agent unwinds

Behavior change for existing users

Heads-up for users on the auto-memory build: pre-PR, dreams were invisible — only a memory_saved toast announced completion. Post-PR, every fired dream surfaces in the footer pill (e.g. 1 dream) and stays in the Background tasks dialog list for a brief retention window after completion. This is an additive change (no flag flip needed) but users who previously relied on the toast-only signal will now see the pill counter tick. No way to opt out in this PR — if that turns out to be noisy in practice, we can add a setting later.

Scope

  • In: dream visibility (running + recent terminal results) in pill + dialog list + dialog detail body; cancellation via dialog x keystroke and task_stop tool
  • Out (planned follow-up — I'll file it): live in-flight progress (phase flip / files-touched accumulation as the dream agent runs). Requires extending runForkedAgent's AgentPathParams with an onAssistantMessage callback, which would ripple through 4 call sites (extract / dream / 2 followup planners). Independent enough to ship separately; wanted to keep the API change in its own PR for blast-radius isolation.
  • Intentionally not included: extract tasks. They fire on every UserQuery, would flood the pill, the memory_saved toast in useGeminiStream already covers their completion signal, and they run on the request loop where cancelling would interfere with the user's own turn. task_stop rejects extract task ids with TASK_STOP_NOT_CANCELLABLE (distinct from NOT_FOUND) and MemoryManager.cancelTask returns false for non-dream taskType (defense in depth).

Risks / blast radius

  • MemoryTaskStatus widened with 'cancelled': grepped all consumers, only manager.ts itself + the cli view-model switch on this enum. No exhaustive-switch downstream that would silently fall through.
  • runForkedAgent API is unchanged: the cancellation work only uses the already-existing optional abortSignal parameter on AgentPathParams. No call-site migration risk for the other 3 fork-agent consumers.
  • Lock release path is unchanged: cancellation aborts the fork signal and lets runDream's existing finally { await releaseDreamLock(...) } release the lock as the natural error propagation unwinds. No new cleanup code path means no new chance to leak the lock on edge cases.
  • Cancellation status race: cancelTask flips status to 'cancelled' BEFORE aborting the signal so the runDream catch path can detect user-intent and skip the 'failed' overwrite. Tested directly in cancelTask() integration test.
  • No production-config changes: the auto-memory subsystem is gated by getManagedAutoMemoryEnabled() already; users not on that path see zero behavior change.

Design notes

  • Cancellation flow: cancelTask flips the record to 'cancelled' BEFORE aborting the signal. The runDream catch path then detects signal.aborted && record.status === 'cancelled' and skips overwriting with a generic 'failed'. Lock release stays in the existing finally block — no separate cleanup path needed.
  • Eviction cap (MAX_RETAINED_TERMINAL_DREAMS = 3): MemoryManager.tasks is a plain Map with no eviction path. Without a cap on the view-model side, completed dreams accumulate over the project's lifetime. The cap mirrors MonitorRegistry's terminal-cap pattern; running dreams are uncapped.
  • pending / skipped filter: every UserQuery creates a task record. Most get gated and end up 'skipped'. Surfacing those would render dozens of useless rows per session.

Rendering samples

Captured via ink-testing-library at 80x30 (see new dialog tests).

List mode — dream alongside other kinds:

> [dream] memory consolidation reviewing 7 sessions
↑/↓ select · Enter view · x stop · ←/Esc close

Detail · running (with cancel hint shown):

Dream
12s · 7 sessions

Sessions reviewing
7

Progress
Scheduled managed auto-memory dream.

← go back · Esc/Enter/Space close · x stop

Detail · completed:

Dream
✔ Completed · 47s · 5 sessions · 3 topics

Sessions reviewing
5

Progress
Managed auto-memory dream (agent): consolidated 3 topics, deduped 2 entries.

Topics touched (3)
  · user
  · project
  · feedback

← go back · Esc/Enter/Space close

Test plan

Automated:

  • npm run typecheck --workspaces --if-present — clean (cli + core + sdk + webui)
  • npx vitest run --no-coverage src/memory/manager src/tools/task-stop — 31 core tests pass (6 new for cancelTask + dream-aware task_stop)
  • npx vitest run --no-coverage src/ui/components/background-view src/ui/hooks/useBackgroundTaskView — 49 cli tests pass (14 new for dream)
  • Full core suite: 6664 tests pass
  • Full cli suite: 4869 tests pass, 0 regressions

Manual smoke (concrete recipe — bypass the 24h / 5-session gate by setting both thresholds low and force a recent-session count):

await config.getMemoryManager().scheduleDream({
  projectRoot,
  sessionId,
  config,
  minHoursBetweenDreams: 0,
  minSessionsBetweenDreams: 1,
});
  • Pill shows 1 dream while it runs; survives terminal-cap pressure (running uncapped, terminal capped at 3 most-recent)
  • Press x on a running dream → status flips to Stopped, fork-agent unwinds, lock released for next dream cycle
  • Model calls task_stop with a running dream id → cancellation succeeds; model calls it again with a completed id → returns TASK_STOP_NOT_RUNNING
  • Model calls task_stop with an extract task id → returns TASK_STOP_NOT_CANCELLABLE (extract is intentionally not cancellable)
  • Failed dream renders error block in detail body

Refs #3634

中文版

概述

把 managed auto-memory 的 dream(整理)任务接入统一的 Background tasks UI 让它可以被取消。当前 dream 任务每个 UserQuery 由 MemoryManager.scheduleDream 静默调度 — 用户只能看到完成时一条 memory_saved toast,对正在跑什么、在 review 什么、是否失败完全没感知;如果 dream 跑飞烧 token 也没法停。

本 PR 加入:

  • Footer pill 跟其他 kind 一起计 dream 计数(如 1 shell, 1 dream
  • 组合 dialog 列表显示 [dream] memory consolidation reviewing N sessions
  • per-kind detail body 显示 sessions / 进度文本 / 已动 topic / 错误
  • dialog 的 x stop 键通过 MemoryManager.cancelTask 取消
  • task_stop 工具加第 4 路 dispatch,模型也能取消
  • MemoryTaskStatus'cancelled';取消会 abort dream fork-agent,原有 runDream finally 块在 agent unwind 时释放整理锁

用户层面行为变化

给开了 auto-memory 构建的用户提个醒:本 PR 之前 dream 完全静默,只有完成时一条 memory_saved toast。本 PR 之后每次 fire 的 dream 都会出现在 footer pill(如 1 dream),并且在完成后短暂保留窗口期内停留在 Background tasks dialog 列表里。这是纯增量改动(不需要 flag 切换),但之前依赖 toast-only 信号的用户会看到 pill 计数器变。本 PR 没提供 opt-out — 如果实际用下来嫌吵再加 setting。

范围

  • In: dream 可见性(running + 最近 terminal)pill + dialog 列表 + dialog detail;通过 dialog x 键和 task_stop 工具取消
  • 后续 PR: 实时 in-flight 进度(dream agent 跑过程中的 phase flip / files-touched 累积)。需要扩 runForkedAgentAgentPathParamsonAssistantMessage callback,会波及 4 个调用方(extract / dream / 2 个 followup planner)。独立性足够单开
  • 故意不包含: extract 任务。每个 UserQuery 都跑,频率太高放进 pill 会刷屏;完成信号 useGeminiStream 里的 memory_saved toast 已经 cover;并且在 request loop 上跑,取消会干扰用户当前 turn。task_stopTASK_STOP_NOT_CANCELLABLE 显式拒绝 extract 任务 id(区别于 NOT_FOUND),MemoryManager.cancelTask 对非 dream taskTypefalse(双层防御)

风险 / 影响面

  • MemoryTaskStatus'cancelled': grep 全 consumer,只有 manager.ts 自己 + cli view-model switch 这个 enum。下游没有 exhaustive switch 会被静默 fall through
  • runForkedAgent API 没动: 取消逻辑只用了 AgentPathParams 已有的可选 abortSignal 参数。其他 3 个 fork-agent 调用方没有迁移风险
  • 锁释放路径不变: 取消 abort fork signal,让 runDream 已有的 finally { await releaseDreamLock(...) } 在自然错误传播 unwind 时释放锁。没新清理代码意味着没新的边缘 case 漏锁可能
  • 取消状态竞争: cancelTask 在 abort 信号之前把 status 翻到 'cancelled',runDream catch 路径检测到 signal.aborted && status === 'cancelled' 就跳过 'failed' 覆盖。cancelTask() 集成测试直接 pin
  • 生产配置零变化: auto-memory 子系统已经被 getManagedAutoMemoryEnabled() gate;不在那条路径上的用户行为零变化

设计要点

  • 取消流程: cancelTask 先把 record flip 到 'cancelled' abort signal。runDream catch 路径检测 signal.aborted && record.status === 'cancelled' 跳过 generic 'failed' 覆盖。锁释放走原有 finally block — 不需要新清理路径
  • eviction cap (MAX_RETAINED_TERMINAL_DREAMS = 3): MemoryManager.tasks 是普通 Map,无 eviction。view-model 这边不上 cap 的话,completed dream 会随项目生命周期无限累积。Cap 镜像 MonitorRegistry 的 terminal-cap 模式;running dream 不限
  • pending / skipped filter: 每个 UserQuery 创建一条 record,大部分被 gate 拦掉变 'skipped'。surface 这些会 dialog 里堆几十行无用项

渲染示例

通过 ink-testing-library 在 80x30 抓帧(详见新 dialog test)。

列表模式 — dream 跟其他 kind 并列:

> [dream] memory consolidation reviewing 7 sessions
↑/↓ select · Enter view · x stop · ←/Esc close

Detail · running(带取消 hint):

Dream
12s · 7 sessions

Sessions reviewing
7

Progress
Scheduled managed auto-memory dream.

← go back · Esc/Enter/Space close · x stop

Detail · completed

Dream
✔ Completed · 47s · 5 sessions · 3 topics

Sessions reviewing
5

Progress
Managed auto-memory dream (agent): consolidated 3 topics, deduped 2 entries.

Topics touched (3)
  · user
  · project
  · feedback

← go back · Esc/Enter/Space close

测试 plan

自动化:

  • npm run typecheck --workspaces --if-present — 干净(cli + core + sdk + webui)
  • npx vitest run --no-coverage src/memory/manager src/tools/task-stop — 31+ core 测试通过(cancelTask + dream-aware task_stop 共加 6+ 个新测试)
  • npx vitest run --no-coverage src/ui/components/background-view src/ui/hooks/useBackgroundTaskView — 49 cli 测试通过(dream 共 14 个新测试)
  • core 全套件:6669 测试通过
  • cli 全套件:4872 测试通过,零回归

手动 smoke(具体配方 — 把两个阈值降到最低绕开 24h / 5-session gate):

await config.getMemoryManager().scheduleDream({
  projectRoot,
  sessionId,
  config,
  minHoursBetweenDreams: 0,
  minSessionsBetweenDreams: 1,
});
  • pill 在跑时显示 1 dream;扛住 terminal-cap 压力(running 不限,terminal 只留最近 3 个)
  • running dream 上按 x → 状态翻 Stopped,fork-agent unwind,锁释放给下一轮 dream
  • 模型用 running dream id 调 task_stop → 取消成功;再用 completed id 调 → 返 TASK_STOP_NOT_RUNNING
  • 模型用 extract id 调 task_stop → 返 TASK_STOP_NOT_CANCELLABLE(extract 故意不可取消)
  • failed dream 在 detail body 渲染 error 段

wenshao added 3 commits May 5, 2026 01:12
Adds `dream` as a fourth kind in the Background tasks pill + dialog,
alongside agent / shell / monitor. Subscribes to MemoryManager via
its existing subscribe() / listTasksByType() API and adapts
MemoryTaskRecord into a DreamDialogEntry view-model. Zero changes
to the core package.

Filters out `pending` (sub-second transition) and `skipped` (every
UserQuery that misses the gate creates one) records. Caps retained
terminal entries at 3 since `MemoryManager.tasks` has no eviction
path; without the cap, completed dreams would accumulate over the
project's lifetime (mirrors MonitorRegistry's terminal cap pattern).

Extract tasks are intentionally NOT surfaced — they fire on every
UserQuery, would flood the pill, and the `memory_saved` toast in
useGeminiStream already covers their completion signal.

Read-only for now: cancellation requires MemoryManager.cancelTask
+ task_stop integration which lands in a follow-up PR. The dialog
suppresses the "x stop" hint for dream entries until then to avoid
silent no-op keystrokes.

Refs #3634
The earlier comment compared the design to a non-qwen-code product;
restate the rationale in terms of the local extract / dream split
(extract fires every UserQuery and surfaces via memory_saved toast,
dream fires after gates and warrants pill / dialog visibility).
…stop

Wires cancellation for the auto-memory dream task kind:

- `MemoryManager.cancelTask(taskId)` — aborts the dream's fork-agent
  via a new per-task AbortController, marks the record `cancelled`
  before aborting so the runDream catch path can detect user-intent
  and avoid overwriting with a generic `failed`. The existing
  finally block releases the consolidation lock as the agent unwinds.
- `MemoryManager.getTask(id)` — point lookup helper so cross-cutting
  consumers like `task_stop` can route by id without a project root.
- AbortSignal threaded through `scheduleDream` → `runDream` →
  `runManagedAutoMemoryDream` → `planManagedAutoMemoryDreamByAgent`
  → `runForkedAgent.abortSignal` (already supported).
- `task_stop` tool gets a 4th dispatch branch: dream task ids look
  up via MemoryManager and route through `cancelTask`. Extract is
  intentionally NOT cancellable — it runs synchronously on the
  request loop, cancelling would interfere with the user's own turn.
- `BackgroundTasksDialog` x-stop hint suppression for dream is removed
  (was a PR-1 placeholder); `cancelSelected` dream branch now calls
  `memoryManager.cancelTask`.
- `MemoryTaskStatus` gains `'cancelled'`. Dream view-model widens
  status union and filter to surface cancelled entries (terminal
  cap continues to apply).

Refs #3634
@github-actions

github-actions Bot commented May 4, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 55.24% 55.24% 70.8% 79.3%
Core 76.31% 76.31% 78.74% 82.05%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   55.24 |     79.3 |    70.8 |   55.24 |                   
 src               |   67.99 |    62.34 |   74.19 |   67.99 |                   
  gemini.tsx       |   59.52 |    58.88 |   66.66 |   59.52 | ...62,770-773,781 
  ...ractiveCli.ts |   69.53 |    57.42 |   72.72 |   69.53 | ...21-768,776-783 
  ...liCommands.ts |   73.92 |     72.5 |     100 |   73.92 | ...40-264,289,389 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |    46.3 |    63.01 |   55.88 |    46.3 |                   
  acpAgent.ts      |   48.12 |    63.38 |   62.06 |   48.12 | ...91-793,807-815 
  authMethods.ts   |   12.19 |      100 |       0 |   12.19 | 11-31,34-38,41-50 
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   68.65 |    83.33 |   66.66 |   68.65 |                   
  filesystem.ts    |   68.65 |    83.33 |   66.66 |   68.65 | ...32,77-94,97-98 
 ...ration/session |   74.77 |    68.36 |    82.6 |   74.77 |                   
  ...ryReplayer.ts |   64.83 |    72.97 |   81.81 |   64.83 | ...68-269,277-278 
  Session.ts       |   73.52 |    66.12 |   82.92 |   73.52 | ...2322,2328-2331 
  ...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 |    95.9 |    90.43 |    92.3 |    95.9 |                   
  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 |   97.96 |     91.8 |     100 |   97.96 | 226-227,316,324   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |   89.69 |    85.89 |   94.11 |   89.69 |                   
  LlmRewriter.ts   |   80.53 |    79.31 |     100 |   80.53 | ...17-119,170-174 
  ...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      |   62.18 |      100 |    9.52 |   62.18 |                   
  auth.ts          |   46.91 |      100 |       0 |   46.91 | ...,91-98,101-102 
  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          
 src/commands/auth |   66.16 |    79.82 |   78.94 |   66.16 |                   
  handler.ts       |   47.07 |    74.68 |   35.29 |   47.07 | ...-968,1058-1068 
  ...veSelector.ts |     100 |    96.66 |     100 |     100 | 58                
  ...outerOAuth.ts |   89.02 |    78.99 |   96.87 |   89.02 | ...18-622,716-718 
 ...mmands/channel |    39.2 |    79.45 |      50 |    39.2 |                   
  ...l-registry.ts |    8.57 |      100 |       0 |    8.57 | 6-21,24-42        
  config-utils.ts  |   91.89 |      100 |   66.66 |   91.89 | 20-25             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   31.15 |       52 |   69.23 |   31.15 | ...73-476,485-487 
  status.ts        |   17.54 |      100 |       0 |   17.54 | 15-26,32-77       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   84.53 |    88.95 |   81.81 |   84.53 |                   
  consent.ts       |   71.65 |    89.28 |   42.85 |   71.65 | ...85-141,156-162 
  disable.ts       |     100 |      100 |     100 |     100 |                   
  enable.ts        |     100 |      100 |     100 |     100 |                   
  install.ts       |    75.6 |    66.66 |   66.66 |    75.6 | ...39-142,145-153 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |      100 |     100 |     100 |                   
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  uninstall.ts     |    37.5 |      100 |   33.33 |    37.5 | 23-45,57-64,67-70 
  update.ts        |   96.32 |      100 |     100 |   96.32 | 101-105           
  utils.ts         |   60.24 |    28.57 |     100 |   60.24 | ...81,83-87,89-93 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 src/commands/mcp  |   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.51 |      100 |       0 |   11.51 |                   
  cleanup.ts       |    17.5 |      100 |       0 |    17.5 | ...03-108,110-111 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...13-729,731-732 
  fetch-pr.ts      |   10.94 |      100 |       0 |   10.94 | ...89-210,212-213 
  load-rules.ts    |   11.65 |      100 |       0 |   11.65 | ...39-150,152-153 
  pr-context.ts    |    6.19 |      100 |       0 |    6.19 | ...98-313,315-316 
  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.04 |    82.54 |   84.72 |   92.04 |                   
  auth.ts          |   87.87 |    81.35 |     100 |   87.87 | ...20-221,237-238 
  config.ts        |   86.36 |    82.53 |   72.72 |   86.36 | ...1339,1361-1362 
  keyBindings.ts   |   95.95 |       50 |     100 |   95.95 | 160-163           
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  sandboxConfig.ts |    58.9 |    61.53 |   66.66 |    58.9 | ...54-68,73,77-89 
  settings.ts      |   83.13 |    82.55 |   85.71 |   83.13 | ...35-936,941-944 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.29 |       94 |     100 |   96.29 | ...88-190,205-206 
 ...nfig/migration |   94.56 |    78.94 |   83.33 |   94.56 |                   
  index.ts         |   93.93 |    88.88 |     100 |   93.93 | 85-86             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   93.63 |     94.5 |     100 |   93.63 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.19 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
 src/constants     |   11.97 |     87.5 |   16.66 |   11.97 |                   
  ...dardApiKey.ts |     100 |      100 |     100 |     100 |                   
  codingPlan.ts    |    8.75 |     87.5 |   16.66 |    8.75 | ...22-327,335-347 
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/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          |   48.26 |    76.19 |   38.88 |   48.26 |                   
  index.ts         |   26.92 |    76.92 |   26.66 |   26.92 | ...38-239,249-260 
  languages.ts     |    98.7 |       75 |     100 |    98.7 | 110               
 src/i18n/locales  |       0 |        0 |       0 |       0 |                   
  ca.js            |       0 |        0 |       0 |       0 | 1-2144            
  de.js            |       0 |        0 |       0 |       0 | 1-2067            
  en.js            |       0 |        0 |       0 |       0 | 1-2117            
  fr.js            |       0 |        0 |       0 |       0 | 1-2100            
  ja.js            |       0 |        0 |       0 |       0 | 1-1558            
  pt.js            |       0 |        0 |       0 |       0 | 1-2058            
  ru.js            |       0 |        0 |       0 |       0 | 1-2063            
  zh-TW.js         |       0 |        0 |       0 |       0 | 1-1679            
  zh.js            |       0 |        0 |       0 |       0 | 1-1918            
 ...nonInteractive |   72.67 |    72.14 |   74.07 |   72.67 |                   
  session.ts       |   76.86 |    70.45 |   85.71 |   76.86 | ...78-779,787-797 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...80-581,584-585 
 ...active/control |   77.55 |    88.23 |      80 |   77.55 |                   
  ...rolContext.ts |    7.69 |        0 |       0 |    7.69 | 47-79             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...54-372,388,391 
  ...rolService.ts |       8 |        0 |       0 |       8 | 46-179            
 ...ol/controllers |    7.04 |       80 |   13.33 |    7.04 |                   
  ...Controller.ts |   19.32 |      100 |      60 |   19.32 | 81-118,127-210    
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    3.96 |      100 |   11.11 |    3.96 | ...61-379,389-494 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |    5.21 |      100 |       0 |    5.21 | ...21-433,442-471 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   97.59 |    93.06 |   95.18 |   97.59 |                   
  ...putAdapter.ts |   97.33 |    91.89 |   98.07 |   97.33 | ...1343,1368-1369 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.28 |      100 |      90 |   98.28 | 81-82,122-123     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/services      |   90.37 |    89.75 |   94.28 |   90.37 |                   
  ...mandLoader.ts |     100 |     92.3 |     100 |     100 | 89                
  ...killLoader.ts |     100 |    96.29 |     100 |     100 | 44                
  ...andService.ts |    93.5 |      100 |      80 |    93.5 | 107,150-153       
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.32 |    80.64 |   83.33 |   75.32 | ...05-206,272-273 
  ...mandLoader.ts |     100 |      100 |     100 |     100 |                   
  ...nd-factory.ts |      91 |     90.9 |     100 |      91 | 123,132-139       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  commandUtils.ts  |      96 |       90 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   85.95 |    86.42 |   90.47 |   85.95 |                   
  DataProcessor.ts |   85.68 |    86.46 |   92.85 |   85.68 | ...1110,1114-1121 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...teRenderer.ts |   45.45 |      100 |       0 |   45.45 | 13-51             
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   92.38 |    84.12 |     100 |   92.38 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |    78.3 |    71.42 |     100 |    78.3 | ...33-148,151,160 
  tipRegistry.ts   |     100 |    95.23 |     100 |     100 | 33                
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/test-utils    |   93.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            |   63.21 |    68.42 |   51.28 |   63.21 |                   
  App.tsx          |     100 |      100 |     100 |     100 |                   
  AppContainer.tsx |   65.87 |    62.67 |   66.66 |   65.87 | ...2279,2283-2287 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |   52.72 |      100 |   23.52 |   52.72 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   91.83 |       90 |     100 |   91.83 | 25-26,54-55       
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   53.26 |    65.51 |      68 |   53.26 |                   
  AuthDialog.tsx   |   67.75 |    64.95 |    65.9 |   67.75 | ...1271,1273,1275 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  useAuth.ts       |    34.3 |    70.37 |     100 |    34.3 | ...14-920,922-937 
 src/ui/commands   |   60.31 |    78.12 |   61.08 |   60.31 |                   
  aboutCommand.ts  |     100 |    85.71 |     100 |     100 | 36                
  agentsCommand.ts |   72.97 |      100 |      20 |   72.97 | ...32,37-38,42-44 
  ...odeCommand.ts |     100 |      100 |     100 |     100 |                   
  arenaCommand.ts  |   33.13 |    67.64 |    37.5 |   33.13 | ...60-565,644-649 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   95.59 |    71.42 |     100 |   95.59 | 72,154-159        
  bugCommand.ts    |   77.35 |    66.66 |      50 |   77.35 | 21-22,60-69       
  clearCommand.ts  |   90.58 |    73.68 |      50 |   90.58 | ...46,74-75,93-94 
  ...essCommand.ts |   63.39 |       48 |      50 |   63.39 | ...48-149,163-166 
  ...extCommand.ts |    6.17 |      100 |      10 |    6.17 | ...21-522,527-528 
  copyCommand.ts   |     100 |      100 |     100 |     100 |                   
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  ...ryCommand.tsx |   66.11 |    76.74 |   55.55 |   66.11 | ...05-306,315-323 
  docsCommand.ts   |   96.07 |     87.5 |      50 |   96.07 | 20-21             
  doctorCommand.ts |     100 |    93.33 |     100 |     100 | 21                
  dreamCommand.ts  |      75 |    66.66 |   66.66 |      75 | 22-27,44-47       
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   56.93 |    91.66 |   33.33 |   56.93 | ...52-353,361-362 
  ...onsCommand.ts |   45.08 |    85.71 |   27.27 |   45.08 | ...37-238,247-248 
  forgetCommand.ts |   26.82 |      100 |      50 |   26.82 | 18-51             
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   19.04 |       25 |      20 |   19.04 | ...86-187,204-205 
  ideCommand.ts    |   57.33 |    57.69 |   35.29 |   57.33 | ...05-306,310-324 
  initCommand.ts   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |    72.8 |    66.66 |   83.33 |    72.8 | ...31-245,250-273 
  ...ageCommand.ts |   89.39 |    82.35 |   76.92 |   89.39 | ...22-325,348-349 
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  mcpCommand.ts    |   86.66 |      100 |      50 |   86.66 | 14-15             
  memoryCommand.ts |   86.66 |      100 |      50 |   86.66 | 14-15             
  modelCommand.ts  |      56 |    70.58 |   66.66 |      56 | ...,67-93,118-136 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |   93.93 |      100 |      50 |   93.93 | 15-16             
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...berCommand.ts |   32.43 |      100 |      50 |   32.43 | 23-57             
  renameCommand.ts |   85.61 |    78.18 |     100 |   85.61 | ...15-322,329-334 
  ...oreCommand.ts |    92.3 |     87.5 |     100 |    92.3 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |      80 |      100 |      50 |      80 | 19-21             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |   15.04 |      100 |      25 |   15.04 | ...90-106,109-136 
  statsCommand.ts  |   83.91 |    81.25 |      50 |   83.91 | ...31-132,142-145 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.51 |      100 |      50 |    6.51 | 28-323            
  tasksCommand.ts  |   77.45 |    73.43 |     100 |   77.45 | ...55-159,181-186 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |   95.23 |      100 |      50 |   95.23 | 18-19             
  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 |   59.16 |    72.89 |   61.29 |   59.16 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |   18.91 |      100 |       0 |   18.91 | 30-95             
  AppHeader.tsx    |   86.79 |    42.85 |     100 |   86.79 | 32-38,40          
  ...odeDialog.tsx |     9.7 |      100 |       0 |     9.7 | 35-47,50-182      
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   14.63 |      100 |       0 |   14.63 | 18-56             
  ...TextInput.tsx |   66.08 |    69.76 |      50 |   66.08 | ...30-232,250,259 
  Composer.tsx     |   79.31 |    57.14 |     100 |   79.31 | ...-77,95,133,146 
  ...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 |    12.4 |      100 |       0 |    12.4 | 61-457            
  ...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       |   79.67 |    58.06 |     100 |   79.67 | ...98-102,104-108 
  ...ngSpinner.tsx |   54.28 |       50 |      50 |   54.28 | 31-48,61          
  Header.tsx       |   98.14 |    85.71 |     100 |   98.14 | 97,99             
  Help.tsx         |   98.74 |    68.75 |     100 |   98.74 | 74,129            
  ...emDisplay.tsx |   62.55 |     37.5 |     100 |   62.55 | ...17-326,329,332 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   81.02 |    75.33 |      80 |   81.02 | ...1264,1329,1379 
  ...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  |   57.66 |    54.54 |     100 |   57.66 | ...89-200,209-223 
  ...elsDialog.tsx |   16.07 |    89.18 |      50 |   16.07 | ...58-159,162-648 
  MemoryDialog.tsx |   53.35 |    51.21 |   57.14 |   53.35 | ...55,367,380-382 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   76.59 |    54.54 |     100 |   76.59 | ...60-476,533-537 
  ...tsDisplay.tsx |     100 |    96.96 |     100 |     100 | 234               
  ...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 |   88.14 |    83.87 |     100 |   88.14 | ...01-105,133-138 
  PrepareLabel.tsx |   91.66 |    76.19 |     100 |   91.66 | 73-75,77-79,110   
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |    4.45 |      100 |       0 |    4.45 | 28-92,100-328     
  ...ionPicker.tsx |   94.76 |    87.17 |     100 |   94.76 | 99,132,253-261    
  ...onPreview.tsx |   91.73 |    78.26 |     100 |   91.73 | ...,70-71,126-128 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...ngsDialog.tsx |   66.88 |    73.52 |     100 |   66.88 | ...11-819,825-826 
  ...ionDialog.tsx |    87.8 |      100 |   33.33 |    87.8 | 36-39,44-51       
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |      28 |      100 |       0 |      28 | 18-40             
  ...ionPicker.tsx |   17.59 |      100 |       0 |   17.59 | 55-172            
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...yTodoList.tsx |   94.17 |       80 |     100 |   94.17 | 56-57,131-134     
  ...nsDisplay.tsx |   84.09 |    57.14 |     100 |   84.09 | ...16-118,125-127 
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   21.87 |      100 |       0 |   21.87 | 22-40,43-53       
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
 ...nts/agent-view |    25.2 |       90 |      10 |    25.2 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |    9.95 |      100 |       0 |    9.95 | 57-308            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    8.13 |      100 |       0 |    8.13 | 39-59,64-187      
  ...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 |    70.1 |     77.6 |   77.77 |    70.1 |                   
  ...sksDialog.tsx |   70.03 |    76.33 |   71.42 |   70.03 | ...1003,1067-1069 
  ...TasksPill.tsx |   70.83 |    86.95 |     100 |   70.83 | 44,77-89,97-105   
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.77 |    94.23 |   66.66 |   54.77 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 17-128            
  ...nListStep.tsx |   88.35 |    94.73 |      80 |   88.35 | 51-52,58-71,105   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   72.24 |    70.52 |      80 |   72.24 |                   
  ...etailStep.tsx |   96.52 |       75 |     100 |   96.52 | 33,37,50,59       
  ...etailStep.tsx |   93.27 |    73.68 |     100 |   93.27 | 41-42,99-104,110  
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   36.09 |    47.05 |      50 |   36.09 | ...49,453-466,470 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |    20.2 |    84.61 |   81.81 |    20.2 |                   
  ...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         |   96.42 |    87.09 |     100 |   96.42 | 21,96-97          
 ...ents/mcp/steps |    6.65 |      100 |       0 |    6.65 |                   
  ...icateStep.tsx |     5.1 |      100 |       0 |     5.1 | 34-95,98-334      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.26 |      100 |       0 |    5.26 | 31-247            
  ...rListStep.tsx |    5.88 |      100 |       0 |    5.88 | 20-176            
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |    7.14 |      100 |       0 |    7.14 | 16-146            
 ...nents/messages |   79.51 |    79.39 |   69.84 |   79.51 |                   
  ...ionDialog.tsx |   77.35 |    74.54 |    62.5 |   77.35 | ...90,508,526-528 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.33 |     100 |   97.67 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   77.35 |      100 |      70 |   77.35 | ...31-244,248-260 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...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 |   12.82 |      100 |       0 |   12.82 | 22-59             
  ...onMessage.tsx |   73.55 |    55.81 |   33.33 |   73.55 | ...41-443,450-452 
  ...upMessage.tsx |   76.76 |    82.08 |     100 |   76.76 | ...15-242,264-279 
  ToolMessage.tsx  |   90.16 |     83.8 |   91.66 |   90.16 | ...62-567,594-596 
 ...ponents/shared |   82.08 |    77.22 |   92.64 |   82.08 |                   
  ...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  |    6.29 |      100 |       0 |    6.29 | 35-42,45-176      
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  TextInput.tsx    |   74.84 |    57.14 |      75 |   74.84 | ...90-194,206-212 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  text-buffer.ts   |   82.82 |    75.48 |   97.61 |   82.82 | ...2272,2300,2368 
  ...er-actions.ts |   86.71 |    67.79 |     100 |   86.71 | ...07-608,809-811 
 ...ents/subagents |   32.77 |    33.33 |    12.5 |   32.77 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   13.69 |    33.33 |   16.66 |   13.69 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |    8.39 |      100 |       0 |    8.39 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |    2.29 |      100 |       0 |    2.29 | 28-449            
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...agents/runtime |   81.76 |    58.24 |   92.85 |   81.76 |                   
  ...onDisplay.tsx |   81.76 |    58.24 |   92.85 |   81.76 | ...14-716,719-722 
 ...mponents/views |   42.16 |    69.23 |   21.42 |   42.16 |                   
  ContextUsage.tsx |     4.7 |      100 |       0 |     4.7 | ...52-167,170-456 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   76.84 |    78.03 |   84.31 |   76.84 |                   
  ...ewContext.tsx |   65.77 |      100 |      75 |   65.77 | ...22-225,231-241 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.37 |    68.57 |      50 |   93.37 | ...94-195,222-226 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   81.88 |    82.26 |     100 |   81.88 | ...1153,1159-1161 
  ...owContext.tsx |   89.28 |       80 |   66.66 |   89.28 | 34,47-48,60-62    
  ...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             
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 145-146           
  ...teContext.tsx |   85.71 |       50 |     100 |   85.71 | 175-176           
  ...deContext.tsx |   76.08 |    72.72 |     100 |   76.08 | 47-48,52-59,77-78 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |   80.35 |    80.64 |   85.34 |   80.35 |                   
  ...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 |   72.73 |    56.77 |   61.53 |   72.73 | ...78,802,821-825 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-158            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...ationFrame.ts |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   19.81 |    66.66 |      25 |   19.81 | 57-175            
  ...Completion.ts |   92.77 |    89.09 |     100 |   92.77 | ...86-187,220-223 
  ...ifications.ts |   92.07 |    96.29 |     100 |   92.07 | 116-124           
  ...tIndicator.ts |     100 |    93.75 |     100 |     100 | 63                
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   94.11 |    76.92 |     100 |   94.11 | 119-123,216,222   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...lanUpdates.ts |     100 |       92 |     100 |     100 | 59,158            
  ...ompletion.tsx |   91.28 |    79.59 |     100 |   91.28 | ...20-221,259-269 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   76.92 |       50 |     100 |   76.92 | 55,68,71-75,88-96 
  ...eteCommand.ts |   33.33 |       50 |     100 |   33.33 | 30,34,41-90       
  ...ialogClose.ts |   18.18 |      100 |     100 |   18.18 | 75-130            
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...ionUpdates.ts |   93.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |   54.88 |       50 |   33.33 |   54.88 | ...71-173,195-196 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   67.46 |       90 |      50 |   67.46 | ...09-130,149-150 
  ...miniStream.ts |   75.84 |    72.89 |   91.66 |   75.84 | ...2293,2306-2314 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   93.15 |    93.75 |     100 |   93.15 | 44,107-110        
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   70.58 |       75 |      50 |   70.58 | 42-47,59-62       
  ...elsCommand.ts |     100 |      100 |     100 |     100 |                   
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   84.52 |    93.33 |     100 |   84.52 | ...27-232,328-338 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   97.24 |    76.92 |     100 |   97.24 | 104-105,145       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   96.96 |    95.69 |     100 |   96.96 | ...82-183,237-240 
  ...sionPicker.ts |   90.23 |    71.69 |     100 |   90.23 | ...78-279,283-284 
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...Completion.ts |   78.99 |    81.48 |   94.11 |   78.99 | ...77-579,587-624 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |     100 |    98.79 |     100 |     100 | 257               
  ...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 |                   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  vim.ts           |   83.77 |    80.31 |     100 |   83.77 | ...55,759-767,776 
 src/ui/layouts    |   89.51 |    86.95 |     100 |   89.51 |                   
  ...AppLayout.tsx |   89.53 |    86.66 |     100 |   89.53 | 50-52,92-97       
  ...AppLayout.tsx |   89.47 |     87.5 |     100 |   89.47 | 58-63             
 ...i/manageModels |   93.61 |       48 |     100 |   93.61 |                   
  manageModels.ts  |   93.61 |       48 |     100 |   93.61 | ...63-166,179,209 
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |    7.14 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    7.14 |     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.31 |     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.45 |     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      |   76.98 |    86.27 |   85.51 |   76.98 |                   
  ...Colorizer.tsx |   82.78 |    88.23 |     100 |   82.78 | ...10-111,197-223 
  ...nRenderer.tsx |   52.41 |    36.36 |      50 |   52.41 | ...49-151,171-180 
  ...wnDisplay.tsx |   86.79 |    88.88 |     100 |   86.79 | ...06-315,348-373 
  ...eRenderer.tsx |   94.45 |    81.25 |   94.11 |   94.45 | ...65,477,480-483 
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   59.61 |    58.82 |     100 |   59.61 | ...,86-88,107-149 
  commandUtils.ts  |   83.95 |    88.88 |    87.5 |   83.95 | ...50-151,247-266 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  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     |   98.63 |       95 |     100 |   98.63 | 93                
  ...oryMapping.ts |     100 |    94.28 |     100 |     100 | 33,55             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |    98.3 |    95.65 |     100 |    98.3 | 48-49             
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   57.81 |    67.14 |      90 |   57.81 | ...64,412,417-439 
  ...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     |   96.47 |    93.18 |   91.66 |   96.47 | ...46-247,382-383 
  todoSnapshot.ts  |   89.11 |    93.18 |     100 |   89.11 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |    2.36 |        0 |       0 |    2.36 |                   
  collect.ts       |    0.87 |        0 |       0 |    0.87 | 40-394,401-697    
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |     1.2 |      100 |       0 |     1.2 | 17-346            
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   73.68 |    89.56 |   94.52 |   73.68 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.52 |    97.05 |     100 |   96.52 | 166-169           
  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   |   85.29 |    89.47 |     100 |   85.29 | 48-57             
  ...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  |   68.59 |    64.28 |     100 |   68.59 | ...63-269,293-309 
  ...putCapture.ts |   90.65 |    86.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   94.28 |    88.46 |     100 |   94.28 | 28-29,125-126     
  errors.ts        |   98.63 |    96.15 |     100 |   98.63 | 67-68             
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |   90.76 |    93.33 |   88.88 |   90.76 | 103-114           
  ...lationInfo.ts |     100 |      100 |     100 |     100 |                   
  languageUtils.ts |   97.89 |    96.42 |     100 |   97.89 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.79 |    93.28 |     100 |   96.79 | ...76-477,575,588 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   98.07 |    76.92 |     100 |   98.07 | 70                
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-980             
  settingsUtils.ts |   86.32 |    90.59 |   94.44 |   86.32 | ...38,569,632-644 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |     100 |    95.83 |     100 |     100 | 110               
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   92.52 |     90.9 |   83.33 |   92.52 | 63-69,184         
  ...InfoFields.ts |   86.91 |    65.78 |     100 |   86.91 | ...16-117,138-139 
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |    62.1 |    77.77 |     100 |    62.1 | 93,107,118-157    
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   76.31 |    82.05 |   78.74 |   76.31 |                   
 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        |    83.5 |    75.49 |   88.15 |    83.5 |                   
  ...transcript.ts |   88.76 |    75.43 |     100 |   88.76 | ...82,306-307,434 
  ...ent-resume.ts |   78.75 |       70 |      75 |   78.75 | ...78-982,985-987 
  ...ound-tasks.ts |   91.83 |    85.18 |      96 |   91.83 | ...51-552,569-570 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |    76.9 |    66.66 |   78.94 |    76.9 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.84 |     62.9 |   78.57 |   75.84 | ...1889,1895-1896 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    73.46 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |    76.3 |    86.23 |   72.41 |    76.3 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.06 |     90.9 |   82.35 |   91.06 | ...51-271,330,430 
  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 |   80.15 |    75.35 |      66 |   80.15 |                   
  agent-core.ts    |   74.55 |    69.28 |   48.48 |   74.55 | ...1281,1308-1354 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   79.09 |    69.76 |   52.38 |   79.09 | ...78-379,382-383 
  ...nteractive.ts |   79.71 |    79.62 |      75 |   79.71 | ...54,456,458,461 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   74.26 |     75.8 |   60.77 |   74.26 |                   
  config.ts        |   71.86 |    72.91 |    55.1 |   71.86 | ...2888,2892-2904 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   95.72 |     93.1 |   91.66 |   95.72 | ...06-207,241-242 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/constants     |    4.95 |      100 |       0 |    4.95 |                   
  codingPlan.ts    |    4.95 |      100 |       0 |    4.95 | ...79-291,299-309 
 src/core          |   81.69 |    81.62 |   87.86 |   81.69 |                   
  baseLlmClient.ts |   96.77 |    96.42 |      80 |   96.77 | 123-126           
  client.ts        |   73.05 |    74.58 |      84 |   73.05 | ...1159,1163-1179 
  ...tGenerator.ts |    72.1 |    61.11 |     100 |    72.1 | ...63,365,372-375 
  ...lScheduler.ts |   76.59 |    80.63 |    92.3 |   76.59 | ...2178,2230-2234 
  geminiChat.ts    |   87.81 |    83.42 |   84.84 |   87.81 | ...-962,1029-1030 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | 34-42,45-49,52-87 
  logger.ts        |   82.25 |    81.81 |     100 |   82.25 | ...57-361,407-421 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   85.71 |    70.58 |     100 |   85.71 | ...90-191,205-214 
  ...issionFlow.ts |   98.59 |    94.73 |     100 |   98.59 | 93                
  prompts.ts       |    88.8 |    88.05 |      75 |    88.8 | ...-898,1101-1102 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...okTriggers.ts |   99.31 |     90.9 |     100 |   99.31 | 124,135           
  turn.ts          |   96.29 |    88.46 |     100 |   96.29 | ...87,400-401,449 
 ...ntentGenerator |    94.6 |    79.35 |   92.68 |    94.6 |                   
  ...tGenerator.ts |   96.49 |    79.35 |      90 |   96.49 | ...24,481,637,693 
  converter.ts     |   94.38 |    79.78 |     100 |   94.38 | ...40-541,551,734 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
 ...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 |   91.08 |    76.14 |   85.71 |   91.08 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   91.04 |    76.14 |   85.71 |   91.04 | ...23,533-534,562 
 ...ntentGenerator |   79.48 |    83.73 |   89.47 |   79.48 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   74.92 |    80.85 |   86.95 |   74.92 | ...1410,1431-1437 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   43.85 |    14.28 |      50 |   43.85 | ...,87-91,102-103 
  ...tGenerator.ts |   48.78 |    91.66 |   77.77 |   48.78 | ...10-163,166-167 
  pipeline.ts      |   93.62 |    84.76 |     100 |   93.62 | ...78-479,487,547 
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   90.66 |     88.4 |     100 |   90.66 | ...15-319,349-350 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.67 |    89.74 |   94.87 |   96.67 |                   
  dashscope.ts     |   97.22 |    87.69 |   93.33 |   97.22 | ...10-211,287-288 
  deepseek.ts      |   95.55 |    90.56 |     100 |   95.55 | ...31-132,145-146 
  default.ts       |   94.62 |    86.36 |   85.71 |   94.62 | 85-86,156-158     
  index.ts         |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
 src/extension     |   60.62 |    79.43 |   79.03 |   60.62 |                   
  ...-converter.ts |   62.35 |    47.82 |      90 |   62.35 | ...90-791,800-832 
  ...ionManager.ts |   46.92 |    82.19 |   67.44 |   46.92 | ...1386,1396-1415 
  ...onSettings.ts |   93.46 |    93.05 |     100 |   93.46 | ...17-221,228-232 
  ...-converter.ts |   54.88 |    94.44 |      60 |   54.88 | ...35-146,158-192 
  github.ts        |   44.94 |    88.52 |      60 |   44.94 | ...53-359,398-451 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.29 |    93.75 |     100 |   97.29 | ...64,184-185,274 
  npm.ts           |   48.66 |    76.08 |      75 |   48.66 | ...18-420,427-431 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-108,143-149    
  storage.ts       |   94.73 |       90 |     100 |   94.73 | 41-42             
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   46.35 |     92.3 |   71.87 |   46.35 |                   
  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.22 |      100 |   16.66 |   13.22 | 88-458,518-568    
  ...onToolGate.ts |     100 |    96.29 |     100 |     100 | 93                
  ...nGenerator.ts |   36.67 |    95.12 |   33.33 |   36.67 | ...24-326,361-391 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/hooks         |    80.6 |    84.37 |   84.16 |    80.6 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.37 |    90.54 |     100 |   96.37 | ...89,291-292,365 
  ...entHandler.ts |   95.58 |    84.37 |   92.59 |   95.58 | ...29,682-683,693 
  hookPlanner.ts   |   84.13 |    76.59 |      90 |   84.13 | ...38,144,162-173 
  hookRegistry.ts  |   88.83 |    86.36 |     100 |   88.83 | ...21,326,330,334 
  hookRunner.ts    |   53.63 |    72.22 |   61.11 |   53.63 | ...23-724,733-734 
  hookSystem.ts    |   75.47 |      100 |   56.41 |   75.47 | ...75-576,582-583 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |    96.5 |     91.8 |     100 |    96.5 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  trustedHooks.ts  |       0 |        0 |       0 |       0 | 1-124             
  types.ts         |   90.15 |    91.02 |   85.18 |   90.15 | ...91-392,452-456 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   74.28 |    83.39 |   78.33 |   74.28 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |    64.2 |    81.48 |   66.66 |    64.2 | ...9-970,999-1007 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   33.92 |    45.16 |   45.76 |   33.92 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |    4.29 |      100 |       0 |    4.29 | ...20-371,377-394 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   13.52 |    81.25 |   29.16 |   13.52 | ...75-694,700-730 
  ...eLspClient.ts |   17.89 |      100 |       0 |   17.89 | ...37-244,254-258 
  ...LspService.ts |   45.87 |    62.13 |   66.66 |   45.87 | ...1282,1299-1309 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   78.69 |    75.34 |   75.92 |   78.69 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.62 |    97.72 |     100 |   98.62 | 87-88             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |    95.83 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.48 |    86.66 |   86.36 |   79.48 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   82.75 |    82.35 |   92.85 |   82.75 | ...62-172,180-181 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   61.58 |    75.87 |   65.77 |   61.58 |                   
  const.ts         |     100 |      100 |     100 |     100 |                   
  dream.ts         |   65.65 |    73.33 |      50 |   65.65 | 50,107-148        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   59.84 |       70 |      50 |   59.84 | ...72-180,183-189 
  extract.ts       |    95.2 |    79.16 |     100 |    95.2 | 81-86,125         
  ...entPlanner.ts |   63.08 |    65.71 |   41.17 |   63.08 | ...17,222-223,332 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |    8.04 |      100 |       0 |    8.04 | 67-342            
  governance.ts    |       0 |        0 |       0 |       0 | 1-352             
  indexer.ts       |   83.87 |    45.45 |     100 |   83.87 | ...50,56-57,69-70 
  manager.ts       |   73.32 |    78.94 |   74.35 |   73.32 | ...1163,1176-1178 
  memoryAge.ts     |   80.95 |     87.5 |      75 |   80.95 | 48-51             
  paths.ts         |   55.47 |    89.47 |   85.71 |   55.47 | ...,88-89,105-113 
  prompt.ts        |   93.36 |    71.42 |     100 |   93.36 | ...58,161,228-229 
  recall.ts        |   82.24 |    78.04 |   88.88 |   82.24 | ...71-188,246-257 
  ...ceSelector.ts |   91.56 |    73.68 |     100 |   91.56 | ...01,103-104,112 
  scan.ts          |   87.91 |    68.42 |     100 |   87.91 | ...47-48,58,82-87 
  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 |                   
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.49 |    85.58 |   87.14 |   89.49 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   88.67 |     90.9 |     100 |   88.67 | 112,118,121-130   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |       44 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.63 |    92.53 |     100 |   98.63 | 161,323,329       
  modelRegistry.ts |     100 |    98.21 |     100 |     100 | 182               
  modelsConfig.ts  |   85.37 |    83.54 |   81.57 |   85.37 | ...1210,1239-1240 
  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   |   71.18 |    88.73 |   48.57 |   71.18 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   81.42 |    86.66 |      80 |   81.42 | ...19-820,827-836 
  rule-parser.ts   |   95.99 |    93.18 |     100 |   95.99 | ...-864,1013-1015 
  ...-semantics.ts |   58.28 |    85.27 |    30.2 |   58.28 | ...1604-1614,1643 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/qwen          |   86.03 |    79.48 |   97.18 |   86.03 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   85.01 |    74.81 |   93.33 |   85.01 | ...,986-1002,1032 
  ...kenManager.ts |   83.79 |    76.22 |     100 |   83.79 | ...63-768,789-794 
 src/services      |   84.33 |    83.85 |   87.76 |   84.33 |                   
  ...llRegistry.ts |   97.82 |    94.73 |     100 |   97.82 | 172-173           
  ...ionService.ts |   97.95 |    94.04 |     100 |   97.95 | 255,257-261       
  ...ingService.ts |   72.04 |    78.88 |   73.07 |   72.04 | ...35-936,953-954 
  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 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   89.76 |     85.1 |   88.88 |   89.76 | ...89,191,266-273 
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  gitService.ts    |   68.75 |     92.3 |   55.55 |   68.75 | ...12-122,125-129 
  ...reeService.ts |   71.83 |    68.47 |    91.3 |   71.83 | ...89-790,806,822 
  ...ionService.ts |   98.13 |     97.8 |   95.45 |   98.13 | ...32-333,380-381 
  ...orRegistry.ts |   96.76 |    92.15 |     100 |   96.76 | ...96-397,450-451 
  sessionRecap.ts  |   10.71 |      100 |       0 |   10.71 | 48-161            
  ...ionService.ts |   83.91 |    71.72 |      92 |   83.91 | ...-989,1021-1022 
  sessionTitle.ts  |   93.95 |    70.37 |     100 |   93.95 | ...36-239,270-271 
  ...ionService.ts |   83.96 |    80.97 |   83.78 |   83.96 | ...1029,1035-1040 
  ...UseSummary.ts |    94.7 |    88.67 |     100 |    94.7 | ...69-171,221-222 
 ...icrocompaction |   98.62 |    86.44 |     100 |   98.62 |                   
  microcompact.ts  |   98.62 |    86.44 |     100 |   98.62 | 138,142           
 src/skills        |   86.65 |    83.88 |   93.61 |   86.65 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |   89.72 |    80.76 |     100 |   89.72 | ...28,248,260-262 
  skill-manager.ts |   82.59 |    79.32 |   90.32 |   82.59 | ...1131,1138-1142 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/subagents     |   82.65 |    79.74 |   91.11 |   82.65 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   76.48 |    71.42 |   87.09 |   76.48 | ...1129,1151-1152 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 51-56,69-74,78-83 
 src/telemetry     |   70.05 |       83 |   75.11 |   70.05 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...-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 |   91.28 |    83.67 |   92.85 |   91.28 | ...66-171,186-187 
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |    51.9 |       64 |   57.77 |    51.9 | ...1214,1231-1251 
  metrics.ts       |    74.9 |    82.95 |   74.54 |    74.9 | ...58-978,981-992 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   88.97 |    77.77 |     100 |   88.97 | ...80-281,300-304 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |   79.09 |    85.59 |   83.33 |   79.09 | ...1134,1137-1166 
  uiTelemetry.ts   |   92.97 |    96.96 |   81.25 |   92.97 | ...93-194,200-207 
 ...ry/qwen-logger |   68.01 |    80.21 |   64.91 |   68.01 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.01 |       80 |   64.28 |   68.01 | ...1042,1080-1081 
 src/test-utils    |   93.07 |    95.55 |   73.52 |   93.07 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   91.02 |    96.77 |   68.96 |   91.02 | ...32,196-197,210 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   75.91 |    80.62 |   80.84 |   75.91 |                   
  ...erQuestion.ts |    88.8 |    76.74 |    90.9 |    88.8 | ...36-337,344-345 
  cron-create.ts   |   97.61 |    88.88 |   83.33 |   97.61 | 30-31             
  cron-delete.ts   |   96.55 |      100 |   83.33 |   96.55 | 26-27             
  cron-list.ts     |   96.36 |      100 |   83.33 |   96.36 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   80.83 |    84.09 |   73.33 |   80.83 | ...28-529,616-666 
  exitPlanMode.ts  |   84.61 |    85.71 |     100 |   84.61 | ...60-163,177-189 
  glob.ts          |    90.6 |    88.33 |   84.61 |    90.6 | ...28,171,301,304 
  grep.ts          |    71.3 |    87.34 |   72.22 |    71.3 | ...93,533,541-548 
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.69 |    60.09 |   90.32 |   72.69 | ...1208,1210-1211 
  ...nt-manager.ts |   52.09 |     65.9 |   47.36 |   52.09 | ...02-520,523-560 
  mcp-client.ts    |   29.65 |    71.05 |   46.87 |   29.65 | ...1434,1438-1441 
  mcp-tool.ts      |   90.92 |    88.88 |   96.42 |   90.92 | ...89-590,640-641 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-48              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   92.16 |    83.45 |      92 |   92.16 | ...15,544-547,560 
  read-file.ts     |   93.28 |    89.33 |      90 |   93.28 | ...99,240,262-271 
  ripGrep.ts       |   94.44 |    89.33 |   91.66 |   94.44 | ...34,337,415-416 
  ...-transport.ts |    6.34 |        0 |       0 |    6.34 | 47-145            
  send-message.ts  |   88.77 |    91.66 |   83.33 |   88.77 | 44-45,68-76       
  shell.ts         |   81.42 |    80.74 |    90.9 |   81.42 | ...1243,1292-1298 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   88.11 |    91.17 |   84.61 |   88.11 | ...95,399,422-444 
  task-stop.ts     |   92.94 |    96.15 |   85.71 |   92.94 | 39-40,54-64       
  todoWrite.ts     |   85.42 |    84.09 |   84.61 |   85.42 | ...05-410,432-433 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   67.49 |    68.91 |   65.71 |   67.49 | ...59-660,668-669 
  tools.ts         |    87.6 |    89.79 |   88.23 |    87.6 | ...25-426,442-448 
  web-fetch.ts     |   88.44 |    76.92 |    92.3 |   88.44 | ...05-306,308-309 
  write-file.ts    |   83.04 |    76.27 |   83.33 |   83.04 | ...28-431,443-478 
 src/tools/agent   |   82.17 |    82.96 |      80 |   82.17 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent.ts         |   82.23 |    83.04 |   78.78 |   82.23 | ...1306,1355-1359 
  fork-subagent.ts |   78.26 |    71.42 |      80 |   78.26 | 54-72,104-105     
 src/utils         |   87.27 |    87.27 |    91.7 |   87.27 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   76.08 |    44.44 |     100 |   76.08 | 61-70,72          
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |    7.69 |      100 |       0 |    7.69 | 17-56             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |   42.85 |    23.07 |     100 |   42.85 | 26-31,33-45,47-54 
  cronParser.ts    |   89.74 |    85.41 |     100 |   89.74 | ...,63-64,183-186 
  debugLogger.ts   |   96.12 |    93.75 |   93.75 |   96.12 | 164-168           
  editHelper.ts    |   92.67 |    82.14 |     100 |   92.67 | ...52-454,463-464 
  editor.ts        |   97.61 |    95.71 |     100 |   97.61 | ...70-271,273-274 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |     100 |    95.45 |     100 |     100 | 83                
  errorParsing.ts  |    97.7 |    96.87 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.92 |    80.39 |   53.33 |   70.92 | ...03-219,223-229 
  fetch.ts         |   70.18 |    71.42 |   71.42 |   70.18 | ...42,148,161,186 
  fileUtils.ts     |   89.08 |    85.06 |   94.73 |   89.08 | ...68-875,879-885 
  forkedAgent.ts   |   62.98 |    54.54 |      75 |   62.98 | ...23-432,434-447 
  formatters.ts    |   54.54 |       50 |     100 |   54.54 | 12-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   38.88 |    84.61 |      50 |   38.88 | ...2,51-74,97-148 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 26                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   59.57 |    89.74 |   45.45 |   59.57 | ...53-286,292-298 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...yDiscovery.ts |   83.85 |    79.36 |     100 |   83.85 | ...15,318,410-413 
  ...tProcessor.ts |   93.63 |       90 |     100 |   93.63 | ...96-302,384-385 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  ...kerChecker.ts |   82.55 |    78.57 |     100 |   82.55 | 68-69,79-84,92-98 
  notebook.ts      |   94.35 |    84.78 |     100 |   94.35 | ...10,122,174-176 
  openaiLogger.ts  |   86.27 |    82.14 |     100 |   86.27 | ...05-107,130-135 
  partUtils.ts     |     100 |      100 |     100 |     100 |                   
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   92.82 |    91.02 |     100 |   92.82 | ...71-372,374-376 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  ...ectSummary.ts |   89.39 |    72.41 |     100 |   89.39 | ...37-142,193-196 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   91.48 |    94.11 |     100 |   91.48 | 80,93-95          
  readManyFiles.ts |   87.96 |    86.95 |     100 |   87.96 | ...05-207,223-234 
  retry.ts         |   89.81 |    88.05 |     100 |   89.81 | ...29,350,357-358 
  ripgrepUtils.ts  |   46.53 |    83.33 |   66.66 |   46.53 | ...32-233,245-322 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...tchOptions.ts |   63.85 |    64.28 |   83.33 |   63.85 | ...29-130,187-188 
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    87.87 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   93.43 |    77.04 |     100 |   93.43 | ...46,155-158,212 
  ...r-launcher.ts |   76.92 |     91.3 |   66.66 |   76.92 | ...34,136,157-195 
  ...orageUtils.ts |   92.41 |    82.82 |     100 |   92.41 | ...39,423-430,441 
  shell-utils.ts   |   82.93 |     89.5 |     100 |   82.93 | ...1522,1529-1533 
  ...lAstParser.ts |   95.58 |    85.79 |     100 |   95.58 | ...1059-1061,1071 
  ...nlyChecker.ts |   95.75 |    92.47 |     100 |   95.75 | ...00-301,313-314 
  sideQuery.ts     |     100 |    92.85 |     100 |     100 | 43                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  truncation.ts    |     100 |       92 |     100 |     100 | 52,71             
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   93.71 |    88.88 |   93.33 |   93.71 | ...24-225,249-251 
  xml.ts           |     100 |      100 |     100 |     100 |                   
  yaml-parser.ts   |      92 |    84.31 |     100 |      92 | 49-53,65-69       
 ...ils/filesearch |   96.34 |    91.66 |     100 |   96.34 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   96.87 |    94.44 |     100 |   96.87 | 83-84             
  fileSearch.ts    |   93.29 |    86.76 |     100 |   93.29 | ...40-241,243-244 
  ignore.ts        |     100 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |     92.3 |     100 |     100 | 46                
 ...uest-tokenizer |   56.63 |    74.52 |   74.19 |   56.63 |                   
  ...eTokenizer.ts |   41.86 |    76.47 |   69.23 |   41.86 | ...70-443,453-507 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |      76 |      100 |   33.33 |      76 | 45-48,55-56       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

@wenshao wenshao changed the title feat(cli): surface auto-memory dream tasks in Background tasks dialog feat(core,cli): surface and cancel auto-memory dream tasks May 4, 2026

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 extends the CLI Background tasks UX to include managed auto-memory dream (consolidation) tasks alongside existing agent/shell/monitor entries, wiring MemoryManager tasks into the pill + dialog list/detail views and adding cancellation plumbing.

Changes:

  • Added a new background-task kind (dream) to the footer pill and Background tasks dialog (list rows + detailed rendering).
  • Adapted MemoryManager dream task records into the unified dialog view-model, including filtering/capping terminal entries and subscribing for updates.
  • Introduced dream cancellation support across the stack (MemoryManager abort controllers, UI cancel routing, and task_stop tool dispatch).

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/core/src/tools/task-stop.ts Adds task_stop support for cancelling MemoryManager dream tasks and extends not-running handling to dream.
packages/core/src/tools/task-stop.test.ts Adds unit tests for dream cancellation routing and terminal/not-found behavior.
packages/core/src/memory/manager.ts Adds cancelled status, per-dream AbortController tracking, plus getTask()/cancelTask() APIs and abort propagation into dream execution.
packages/core/src/memory/manager.test.ts Adds tests validating cancelTask() behavior and that cancellation doesn’t degrade to failed.
packages/core/src/memory/dreamAgentPlanner.ts Threads abortSignal into runForkedAgent for dream runs.
packages/core/src/memory/dream.ts Threads abortSignal through dream execution helpers into the planner.
packages/cli/src/ui/hooks/useBackgroundTaskView.ts Subscribes to MemoryManager and merges dream tasks into the unified dialog/pill entry list, including terminal-entry retention cap.
packages/cli/src/ui/hooks/useBackgroundTaskView.test.ts Adds coverage for dream filtering/capping and subscription-driven refresh.
packages/cli/src/ui/contexts/BackgroundTaskViewContext.tsx Routes cancel action for dream entries to MemoryManager.cancelTask().
packages/cli/src/ui/components/background-view/BackgroundTasksPill.tsx Adds dream counting/labeling in the pill (shell → agent → monitor → dream ordering).
packages/cli/src/ui/components/background-view/BackgroundTasksPill.test.tsx Adds pill label tests for dream singular/plural, ordering, and terminal-mix behavior.
packages/cli/src/ui/components/background-view/BackgroundTasksDialog.tsx Adds [dream] row labeling and DreamDetailBody rendering; hint/footer and key handling will now show x stop for running dreams.
packages/cli/src/ui/components/background-view/BackgroundTasksDialog.test.tsx Adds dialog rendering tests for dream list/detail states and cancellation routing.
Comments suppressed due to low confidence (1)

packages/core/src/memory/dreamAgentPlanner.ts:258

  • planManagedAutoMemoryDreamByAgent only throws when result.status === 'failed'. When a dream is aborted via the new abortSignal, runForkedAgent can return { status: 'cancelled' } without throwing; this path will currently be treated as success by runManagedAutoMemoryDream/MemoryManager.runDream and can overwrite a user-cancelled dream as completed (and even bump metadata/rebuild index based on partial writes). Handle cancellation explicitly (e.g., throw unless result.status === 'completed', mirroring extractionAgentPlanner, or propagate a cancelled result upward so callers can preserve cancelled).
  if (result.status === 'failed') {
    throw new Error(result.terminateReason || 'Dream agent failed');
  }

  return result;

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

Comment thread packages/cli/src/ui/components/background-view/BackgroundTasksDialog.tsx Outdated
Comment thread packages/core/src/tools/task-stop.ts Outdated
Comment thread packages/core/src/tools/task-stop.ts Outdated
- DreamDetailBody: comment said cancellation "lands in PR-2" but the
  same PR wires `cancelSelected` for dream entries. Reword to describe
  what's actually shipped + flag in-flight progress as the real
  follow-up.
- task_stop: drop the unreachable `!aborted` error branch. The status
  guard above already confirms `running`, and `cancelTask` is
  synchronous; in this branch it cannot return false.

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

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.


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

Comment thread packages/core/src/memory/dream.ts
Comment thread packages/core/src/memory/manager.ts
Comment thread packages/core/src/memory/manager.test.ts
…tasks

runForkedAgent maps AgentTerminateMode.CANCELLED to a resolved
{status: 'cancelled'} result rather than rejecting. The cancel-via-
task_stop path landed in the previous commit assumed the call would
throw — when it didn't, the runDream success path overwrote the
user-cancelled record with 'completed' AND bumped lastDreamAt
metadata, suppressing the next legitimate dream cycle.

Two-layer defense:

- dreamAgentPlanner now rethrows when the fork agent reports
  cancelled status (mirrors the existing failed-status throw).
  This is the source-of-truth fix.

- runDream now checks abortSignal.aborted after the await as
  defense in depth. If anything in the call chain ever forgets to
  propagate, this guard short-circuits the success path before
  metadata write.

Updates the existing dreamAgentPlanner test that previously pinned
the buggy "returns cancelled without throwing" behavior. Adds a
manager test that simulates the resolves-on-abort scenario directly
to verify the consumer-side guard catches anything the planner
might miss.

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

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.


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

Comment thread packages/core/src/tools/task-stop.ts Outdated
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.ts Outdated
Comment thread packages/core/src/memory/manager.ts
@wenshao wenshao marked this pull request as ready for review May 5, 2026 00:22
… clarity

Three fixes from the post-cancellation-PR review:

- scheduleDream now sets an initial `progressText` ("Scheduled
  managed auto-memory dream.") on the in-flight record. Without
  this, the dialog Detail's Progress section stayed empty until
  completion — the PR description's mid-flight screenshot showed
  text that production never actually rendered.

- useBackgroundTaskView gates the MemoryManager.subscribe listener
  on a dream-content signature. The manager fires for every task
  transition (extract included, ~2x per UserQuery), but the dialog
  has no extract surface; without this dedup each extract notify
  forced a full 4-source re-merge + a fresh setEntries reference,
  re-rendering the dialog and pill on entries that hadn't changed.
  Added a test that pins the reference-stability invariant.

- task-stop comment was misleading — said "the status guard above
  already confirmed running", but for the dream branch the running
  check happens IN this branch (not earlier). Reworded.

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

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.


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

Comment thread packages/core/src/memory/manager.ts
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.ts Outdated
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.test.ts Outdated
Comment thread packages/cli/src/ui/components/background-view/BackgroundTasksDialog.test.tsx Outdated
…s, sync test helper

Four fixes from the latest review pass:

- cancelTask() now enforces the AbortController invariant. The old
  `ac?.abort()` returned `true` even when no controller was found,
  meaning callers could see a successful return while the dream was
  not actually aborted (and would leak the consolidation lock until
  the agent finished naturally). The controller is registered
  synchronously alongside `status='running'`, so a missing controller
  for a running record is a contract violation — return false without
  flipping status so the caller knows the abort didn't take.

- useBackgroundTaskView's `refresh()` now reuses the dream snapshot
  the memory listener fetched for its dedup gate. The previous version
  re-read `listTasksByType('dream')` inside `computeDreamSig()` and
  again inside `refresh()` — extra work AND a race window where the
  gate signature could come from a different snapshot than the one
  used to build dreamEntries. Single read, single source of truth.

- The `dream()` test helper widened to include `'cancelled'` so it
  matches the production `MemoryTaskStatus` union. Added a small test
  asserting cancelled dreams flow through the kind discriminator (the
  dialog's terminal-cap window depends on showing the user the
  outcome of the abort they just triggered).

- Dropped the stale "PR-1 read-only / PR-2 cancellation" block
  comment above the dream-entries describe block — both are in this
  PR now.
@wenshao wenshao requested a review from Copilot May 5, 2026 00:53
@wenshao

wenshao commented May 5, 2026

Copy link
Copy Markdown
Collaborator Author

Self-review notes

What's good

  • Cancellation race is handled carefully. cancelTask flips status to 'cancelled' before aborting the signal, and runDream's catch path checks signal.aborted && record.status === 'cancelled' so the user-cancel record never gets clobbered with 'failed'. The post-await if (abortSignal.aborted) return record; is a clean defense-in-depth against the resolved-success-after-abort path.
  • Lock release stays in the existing finally block. No new cleanup path means no new chance to leak the dream consolidation lock.
  • task_stop route is dream-only — extract task IDs explicitly fall through, matching the rationale in the description.
  • Tests are dense and targeted. "drain after cancel", "resolved despite cancel" guard, topics overflow cap, dedup-signature short-circuit, extract-routing rejection — each pins a behavior that would silently regress if removed.

Issues to address

1. Redundant dream signal in Footer (UX) — blocker for clarity

packages/cli/src/ui/components/Footer.tsx:137 already shows ✦ dreaming via the older useDreamRunning. Post-PR, a running dream renders in both the new pill (1 dream) and the right-column ✦ dreaming simultaneously. The "Heads-up for users" section doesn't mention this. Either remove useDreamRunning + the right-column text, or document why both coexist.

2. task_stop returns TASK_STOP_NOT_FOUND for a known extract task ID

packages/core/src/tools/task-stop.ts:148-163 only branches into the dream path when taskType === 'dream'. A real, looked-up extract record falls through to the bottom and returns \"No background task found\". The record does exist — it's just not cancellable. From the model's perspective this is misleading; on retry the model thinks the ID was never valid. Suggest either:

  • A new error type TASK_STOP_NOT_CANCELLABLE with a message that names the kind, or
  • Routing through notRunningError('extract', taskId, status) with a tweaked message saying extract isn't cancellable.

3. pending filtering inconsistent across the two consumers

  • useDreamRunning (Footer.tsx:50): treats 'pending' || 'running' as "running" → ✦ dreaming shows.
  • useBackgroundTaskView (useBackgroundTaskView.ts:151): filters 'running' only → pill doesn't count.

Sub-second window so unlikely to be visible, but worth a one-line comment in one or the other so a future maintainer doesn't "fix" one to match the other and break the rationale.

4. computeDreamSig runs twice per refresh()

useBackgroundTaskView.ts:172-191:

const refresh = () => {
  ...
  const allDreams = memoryManager.listTasksByType('dream', projectRoot);
  ...
  lastDreamSig = computeDreamSig();   // <-- second listTasksByType iteration
  setEntries(merged);
};

Each refresh iterates MemoryManager.tasks twice. Trivial cost today, trivially fixable — derive lastDreamSig from allDreams instead of re-fetching.

Smaller / non-blocking

5. Test gap: success-path overwrite race

The "resolved despite cancel" test pins the post-await abort guard. There's no test for the trickier window: runManagedAutoMemoryDream resolves successfully (signal not yet aborted), then cancel fires before update({status: 'completed'}) runs (with await readDreamMetadata/writeDreamMetadata in between, this window is tens of ms wide). Today the cancel flips status to 'cancelled', then the success continuation overwrites with 'completed'. Worth confirming this "user cancelled too late" outcome is intended rather than a silent overwrite bug.

6. endTime for cancelled records reflects cancel moment, not fork unwind

useBackgroundTaskView.ts:177endTime: t.status === 'running' ? undefined : Date.parse(t.updatedAt). For a freshly-cancelled record, updatedAt is the cancelTask() call time; the fork agent may take seconds to actually unwind. The dialog jumps to "Stopped · Ns" immediately. Probably correct UX, but a comment on the DreamDialogEntry.endTime field would prevent a future maintainer from treating it as a real fork-finish timestamp.

7. MemoryTaskStatus widening — verified safe

Re-grepped consumers: only useBackgroundTaskView (filter), STATUS_VERBS (already maps 'cancelled''Stopped'), cancelTask itself, and the runDream catch path. No exhaustive switch would silently regress. ✓

Verdict

Approve with non-blocking comments. Items 1, 2, 4 are worth addressing before merge for UX/model-API correctness. Items 3, 5, 6 are documentation/test debt that can land in a follow-up. The core cancellation mechanic is sound and well-tested.

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

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.


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

Comment thread packages/core/src/tools/task-stop.ts
Comment thread packages/core/src/memory/manager.ts Outdated
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.ts Outdated
Combined fixes for the latest review pass — self-review notes (U1, U2,
U5, U6) plus Copilot's three new comments (C1, C2, C3):

- **Footer dream-indicator dedupe (U1)**: removed `useDreamRunning` +
  `✦ dreaming` right-column text. The new Background tasks pill
  already counts dream tasks alongside agent / shell / monitor;
  showing both produced two simultaneous signals for the same state.

- **task_stop dispatch surfaces extract distinctly (U2 + C1)**: a
  new `TASK_STOP_NOT_CANCELLABLE` error type fires when the task id
  resolves to a known-but-not-cancellable record (extract). Previously
  extract ids fell through to `NOT_FOUND`, misleading the model into
  thinking the id was never valid. Also surfaces the missing-controller
  case from `cancelTask` as an explicit error rather than reporting
  phantom success.

- **MemoryManager.cancelTask logs missing-controller violation (C2)**:
  the silent `return false` for the missing-AbortController case now
  emits a `debugLogger.warn` so the inconsistency is observable in
  debug bundles. Without the log a runaway dream burning tokens would
  leave no trail.

- **MemoryManager.subscribe taskType filter (C3)**: subscribers can
  now opt into per-type notify routing via `subscribe(fn, { taskType })`.
  Internal `notify()` calls pass the changed task's type so filtered
  consumers wake only on relevant transitions. The bg-tasks UI hook
  uses this to skip the per-UserQuery extract notify entirely — drops
  the per-extract O(n) signature work to zero.

- **runDream guards against late-cancel overwrite (U5)**: the
  success path now re-checks `abortSignal.aborted` between metadata
  read/write and before the final `update({status: 'completed'})`.
  Closes the ~tens-of-ms race window where `cancelTask` flipping
  status to `'cancelled'` would silently lose to the success
  continuation overwriting with `'completed'` + bumping
  `lastDreamAt`.

- **DreamDialogEntry.endTime semantic comment (U6)**: documents that
  `endTime` for cancelled records is the cancel-call moment (not the
  fork unwind), so a future maintainer doesn't treat it as a real
  fork-finish timestamp.

Tests: new `subscribe() taskType filter` describe block in manager,
new task_stop tests for `NOT_CANCELLABLE` (extract) and missing-
AbortController (dream); existing test renamed/widened.
@wenshao wenshao requested a review from Copilot May 5, 2026 01:15
@wenshao

wenshao commented May 5, 2026

Copy link
Copy Markdown
Collaborator Author

Self-review items addressed:

  • U1 ✅ (Footer dedupe): useDreamRunning + ✦ dreaming removed from Footer; the new pill is now the single signal for in-flight dreams.
  • U2 ✅ (NOT_CANCELLABLE error type): added TASK_STOP_NOT_CANCELLABLE and routed extract-task ids to it instead of the misleading NOT_FOUND. Test pins the dispatch.
  • U3 ✅ (auto-resolved by U1): useDreamRunning is gone, so the pending filter inconsistency between Footer and hook can't surface anymore.
  • U4 ✅ (already fixed in e6711c5): refresh() now reuses the dream snapshot the memory listener fetched — single read per cycle, no more double iteration.
  • U5 ✅ (late-cancel guard): runDream now re-checks abortSignal.aborted between metadata read/write and before the final completion update. Closes the ~tens-of-ms race window where a late x press would silently lose to the success continuation.
  • U6 ✅ (endTime semantic comment): added a JSDoc explaining endTime for cancelled records is the cancel-call moment, not the fork unwind.
  • U7 ✅ (verified, no action needed): MemoryTaskStatus widening — only the documented consumers switch on this enum.

Plus the same commit picks up Copilot's three new comments — task_stop ignoring cancelTask return value, missing-controller silent failure, and the per-extract notify wakeup. The first two now surface as explicit errors; the third is fixed at the source via MemoryManager.subscribe({ taskType: 'dream' }).

The pre-call abort checks in `runManagedAutoMemoryDream` close most
of the late-cancel race window, but each metadata helper itself does
read → mutate → write across two awaits. If the user cancels between
those two awaits the write still happens, persisting `lastDreamAt`
for an aborted run and suppressing the next legitimate dream cycle.

Thread `abortSignal` into `bumpMetadata` and
`updateDreamMetadataResult`; both now re-check between the read and
the write, returning early without persisting when the signal has
already fired. The pre-call checks remain as the first line of
defense; this guards the race that opens after the call enters.

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

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.


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

Comment thread packages/core/src/memory/manager.ts Outdated

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Review findings

Suggestion: Telemetry dropped for cancelled-but-completed dreams

File: packages/core/src/memory/dream.ts:124 (logMemoryDream)

When a dream is cancelled after the fork agent completes but before logMemoryDream is reached, the abort guard (if (abortSignal?.aborted) return agentResult;) at line 100 returns early, skipping the telemetry call entirely. No MemoryDreamEvent is emitted, so cancelled dreams are undercounted in aggregate metrics and their duration/touched-topics are lost from observability.

Suggested fix: Emit telemetry before the abort checks, or add a separate logging call for the cancelled-but-completed path with status: 'cancelled'.


Suggestion: getTask() returns live internal MemoryTaskRecord reference

File: packages/core/src/memory/manager.ts (getTask method)

getTask(taskId) returns this.tasks.get(taskId) — a direct reference to the internal Map value. The current caller (task-stop.ts) only reads from it, but any future consumer that mutates the record would bypass update() and skip subscriber notifications, causing the dialog to desync.

Suggested fix: Return a shallow copy: return this.tasks.has(taskId) ? { ...this.tasks.get(taskId)! } : undefined;

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

⚠️ Downgraded from Request changes to Comment: self-PR reviews cannot request changes on GitHub. The inline Critical finding still applies.

Comment thread packages/core/src/memory/dream.ts Outdated
Two related fixes from the latest review pass:

- Move scheduler-gating metadata writes out of `runManagedAutoMemoryDream`
  and into `MemoryManager.runDream`, sequenced AFTER the
  status='completed' flip. The previous shape left a race window
  where cancellation arriving during/after `fs.writeFile` could
  persist `lastDreamAt` while the manager flipped status to
  'cancelled' — visible UI ('Stopped') would disagree with the
  scheduler gate (sees a recent successful dream), suppressing the
  next legitimate dream cycle. The new order makes the gating
  metadata write race-free: once status !== 'running', cancelTask
  refuses, so any cancel arriving during the metadata write is
  ignored. The remaining "cancel raced the synchronous status
  update" window is handled by a post-update abort recheck that
  restores 'cancelled' and skips the metadata write.

  Drops the now-dead `bumpMetadata` helper from dream.ts; index
  rebuild stays there since it's informational, not gating.

- Surface `releaseDreamLock` failures on the task record's metadata
  (`lockReleaseError`). The previous fix logged-and-swallowed only,
  so a Windows EPERM or ENOENT race would silently block subsequent
  dreams as 'locked' with no UI signal explaining why dreaming had
  stopped. Logger keeps emitting the warn for debug bundles.

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

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.


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

Comment thread packages/core/src/memory/manager.ts

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewed end-to-end. Cancel-flow logic is solid and well-tested — the race-window analysis around the synchronous status flip + dual abort checks is precise, and the test pinning the "resolved-after-cancel" case is exactly the right defense. Approving in spirit; flagging one functional concern (metadata-write failure overwriting a completed dream) plus a few smaller polish items inline. Other risks called out in the PR description (MemoryTaskStatus widening, runForkedAgent API stability, params.config behavior change) all check out.

Comment thread packages/core/src/memory/manager.ts Outdated
Comment thread packages/core/src/memory/manager.ts Outdated
Comment thread packages/core/src/memory/manager.ts
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.ts Outdated

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

⚠️ Downgraded from Request changes to Comment: self-PR by authenticated user. GitHub does not allow requesting changes on your own PR.

[Critical] packages/cli/src/ui/utils/backgroundWorkUtils.ts:9hasBlockingBackgroundWork() and resetBackgroundStateForSessionSwitch() still only account for background agents, monitors, and shells. This PR makes dream tasks visible/cancellable as first-class background work, but /clear and resume can still proceed while a dream is running because the memory manager is not checked or reset/cancelled. A dream fork-agent can continue after a session switch/reset, using the old session/project context while UI/core state has moved on. Include running dream records in hasBlockingBackgroundWork(config), and either cancel/drain running dreams or add a memory-manager reset/cancel path in resetBackgroundStateForSessionSwitch(). Add tests for /clear/resume with a running dream.

[Suggestion] packages/core/src/tools/task-stop.ts:236 — The task_stop tool description still says only agents and shells are cancelled, but the tool now supports monitors and cancellable dream tasks. This is model-facing metadata, so the model may not discover that it can stop dream consolidation tasks. Update the description to mention agents, shells, monitors, and cancellable dream tasks.

— gpt-5.5 via Qwen Code /review

Comment thread packages/core/src/memory/manager.ts

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Posted Codex qreview finding from the latest review pass. Skipped the lock-release finding because an equivalent inline comment already exists on packages/core/src/memory/manager.ts:962.

Comment thread packages/core/src/tools/task-stop.ts

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

⚠️ Downgraded from Request Changes to Comment: self-PR cannot use Request Changes event. This review found 1 Critical and 3 Suggestion-level issues — please review the inline comments below.

— deepseek-v4-pro via Qwen Code /review

Comment thread packages/core/src/memory/manager.ts
Comment thread packages/core/src/memory/dream.ts Outdated
Comment thread packages/cli/src/ui/contexts/BackgroundTaskViewContext.tsx Outdated
Comment thread packages/core/src/memory/dream.ts
Reverts the metadata-write behavior regression, plugs the
storeWith reentrancy hole, surfaces lock/metadata warnings in the
UI, and a handful of cleanups:

- Wrap gating-metadata read+write in try/catch (manager.ts). The
  PR moved metadata writes from dream.ts (best-effort, swallowed)
  to manager.ts (unguarded). A throw from readDreamMetadata /
  writeDreamMetadata now propagates to the outer catch and
  overwrites a successfully-completed dream with 'failed' — the
  dream actually did its work and touched files are visible. New
  catch logs + writes `metadataWriteError` on the record so the UI
  can explain why the next dream may re-fire sooner than expected.

- Register the AbortController BEFORE storeWith in scheduleDream.
  storeWith fires a notify; a subscriber synchronously calling
  cancelTask(record.id) would otherwise see status='running' but
  no controller, hitting the missing-controller defensive warn
  path and reporting a phantom failure on a brand-new dream.

- Surface `lockReleaseError` and `metadataWriteError` in the dream
  view-model and DreamDetailBody (rendered as warnings, not
  errors, so the terminal status stays Completed). Previous fix
  wrote them to record.metadata only — nothing in the cli read or
  rendered them, so users still had no UI signal.

- Preserve `result.touchedTopics` on the unreachable cancel-raced-
  status-update branch. If a future refactor introduces an await
  there, the restored cancelled record would otherwise drop the
  already-produced result; the UI would report a clean cancellation
  even though memory files were already modified.

- Add `'cancelled'` to MemoryDreamEvent status union and emit a
  cancelled telemetry event from the runDream catch path. Without
  this a cancelled dream is indistinguishable from one that never
  scheduled in the first place.

- Drop the dead abortSignal param from updateDreamMetadataResult
  in dream.ts (no caller passes it after the manager.ts move).

- Swap declaration order of `computeDreamSig` and `refresh` in
  useBackgroundTaskView.ts (TDZ-fragile against a future refactor
  that adds a synchronous refresh call between them).

- Update the unreachable cancel-raced-update branch comment to
  describe what's actually true ("defense-in-depth, unreachable
  today") instead of the confusing "cancelTask flipped" path.

- cancelSelected now checks the cancelTask return value and logs
  via debugLogger when false. Today this branch is unreachable
  thanks to the controller-register-before-storeWith fix above,
  but if a future refactor breaks the invariant the silent ignore
  would let the user think the cancel took effect.

- Mirror the manual /dream metadata path's `recentSessionIdsSinceDream = []`
  reset in the auto path — field is dead code today but keeping
  the two write sites in sync avoids surprises.

Telemetry metric `recordMemoryDreamMetrics` widened to accept the
new 'cancelled' status (downstream consumer in loggers.ts).
@wenshao wenshao requested a review from Copilot May 5, 2026 14:11

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

Copilot reviewed 18 out of 18 changed files in this pull request and generated 2 comments.


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

Comment thread packages/core/src/memory/manager.ts
Comment thread packages/core/src/memory/dream.ts Outdated
wenshao added 2 commits May 5, 2026 22:26
The prior fix surfaced lockReleaseError on the dialog so the user knows
the lock release failed (Windows EPERM, ENOENT race, disk full, etc.) —
but until next process start, dreamLockExists() still sees a fresh-mtime
lock owned by an alive PID (us!) and silently suppresses every
subsequent scheduleDream() call as `{status: 'skipped',
skippedReason: 'locked'}`. The user sees the warning AND zero further
dream activity, and the staleness sweep that would clean the leaked
lock only runs at session start.

Adds a `dreamLockReleaseFailed` flag set in the catch. The next
scheduleDream() force-cleans the leaked lock file via fs.rm({force: true})
before the existence check, so dream scheduling resumes within the same
session. Best-effort: if even the forced rm fails (truly unrecoverable
filesystem state), falls through to the existing 'locked' skip path.

This is an incremental improvement on top of b00ecde's UI-surface fix.
The two together give the full story: warning visible → automatic
recovery on next attempt.
…dering

Two follow-up suggestions from review:

- **`duration_ms: 0` in cancelled-dream telemetry** (manager.ts):
  the user-cancel path emitted `MemoryDreamEvent` with
  `duration_ms: 0`, which would silently skew latency histograms / p95
  metrics by treating cancelled dreams as instant. Capture
  `dreamStartMs = Date.now()` at the top of `runDream` and emit the
  real elapsed time in the cancel branch.

- **Misleading index-rebuild comment** (dream.ts:75–84): the comment
  claimed the index rebuild "is still done before returning when
  topics were touched", but the code returns early on
  `abortSignal?.aborted` BEFORE the rebuild. Rewrote the comment to
  describe the actual cancel-aware ordering — abort returns partial
  result without rebuilding (rebuild is expensive; next dream cycle
  will rebuild against the latest files anyway), live path rebuilds
  only when topics changed.

22 / 22 manager tests pass; tsc clean.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: self-PR.

— gpt-5.5 via Qwen Code /review

@wenshao

wenshao commented May 5, 2026

Copy link
Copy Markdown
Collaborator Author

Code review

Overview

Brings managed auto-memory dream consolidation tasks into the unified Background tasks UI and makes them user-cancellable. 18 files, +1676/-100, scope-limited to dream visibility + cancellation. Extract intentionally excluded.

Strengths

Race handling is the strongest part of this PR:

  • cancelTask flips status to 'cancelled' BEFORE aborting (manager.ts:867-873), so runDream's outer catch can detect user-cancel via signal.aborted && record.status === 'cancelled' (manager.ts:1020) and skip the generic 'failed' overwrite.
  • dreamAbortControllers.set runs BEFORE storeWith (manager.ts:794-797) — handles the reentrant-cancel case where a storeWith notify subscriber synchronously calls cancelTask on the brand-new record. Without this ordering, the controller-missing defensive branch would phantom-fail a freshly scheduled dream.
  • Status flip to 'completed' happens BEFORE the metadata write (manager.ts:924-933), closing the cancel-during-writeFile race window — once status is no longer 'running', cancelTask refuses.
  • Lock-release errors and metadata-write errors are wrapped in their own try/catch (manager.ts:984-993, manager.ts:1003-1014), preventing a flaky filesystem op from overwriting a successfully-completed dream with 'failed'. Both surface as warnings on the record so the user can explain subsequent skipped-as-locked dreams or unbumped scheduler gates.
  • dreamAgentPlanner.ts:258-267 rethrows the resolved-not-rejected {status: 'cancelled'} from runForkedAgent so callers unwind via catch. Belt-and-braces signal check at manager.ts:913-915 handles a fallthrough if the call chain ever forgets.

Test coverage: 44 new core + 52 new CLI tests covering cancel mid-run, cancel on completed/unknown, fork resolves despite cancel, subscribe filter routing, unsubscribe severance, terminal-cap eviction, pending/skipped filter, and dream-content signature dedup. Inverse paths (e.g. dedup not firing when content actually changed) are also pinned.

Backward compatibility: MemoryTaskStatus widening with 'cancelled' — grepped consumers, only manager.ts and the cli view-model touch this enum. terminalStatusPresentation switch + STATUS_VERBS table in the dialog already cover all five EntryStatus values.

Performance: subscribe({ taskType: 'dream' }) is the correct primary gate — extract fires on every UserQuery and would otherwise wake the bg-tasks UI hook for dialog-irrelevant work. The dream-content signature dedup is a sensible defense-in-depth secondary gate.

Observations / minor

  • useBackgroundTaskView.ts:208 uses t.status as 'running' | 'completed' | 'failed' | 'cancelled'. Runtime filter at L187-194 makes this safe today, but a type-narrowing approach (e.g. mapping inside a switch (t.status) that handles the four legal states explicitly) would catch a future refactor that loosens the filter. Low priority.
  • Cancelled-status check at manager.ts:934-955 is documented as 'unreachable today' but kept against future refactors that introduce an await between the pre-update check and the synchronous update. Comment makes the intent clear; acceptable.
  • Reentrant cancel between storeWith and runDream start does waste an acquireDreamLock/releaseDreamLock cycle (signal already aborted, lock acquired then released on next event-loop turn). Not a correctness issue, rare path.
  • A few inline comments are 8+ lines. They explain why (invariant-preservation, race-window reasoning) so they earn their keep, but a couple could trim.

Verification

  • npm run typecheck --workspaces --if-present — clean (after building core dist first; standard monorepo workflow since cli depends on built core types).
  • npx vitest run --no-coverage src/memory/manager src/memory/dream src/tools/task-stop — 44/44 pass.
  • npx vitest run --no-coverage src/ui/components/background-view src/ui/hooks/useBackgroundTaskView — 52/52 pass.

Risks

  • MemoryTaskStatus widening: low — only two consumers, both updated.
  • Lock leak on cancel: low — abort signal triggers the existing finally { releaseDreamLock } block; staleness sweep handles the rare releaseDreamLock failure (now surfaced as a warning on the record).
  • User-visible behavior change for auto-memory build: dreams now visible in pill/dialog where previously toast-only. Documented in PR description; additive; no opt-out (acknowledged as follow-up).

Verdict

LGTM. Design anticipates multi-layer race scenarios, test coverage is comprehensive. The as-cast nit and comment density are not blockers.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

⚠️ Downgraded from Approve to Comment: self-PR cannot use Approve event.

No blocking issues found. CI all green (12/12 checks passed), build and 93 tests pass locally.

One minor note (not posted inline — low confidence): packages/core/src/memory/dream.ts\:86-97runManagedAutoMemoryDream calls logMemoryDream after await rebuildManagedAutoMemoryIndex without rechecking abortSignal. If cancellation fires during that I/O gap, telemetry emits 'updated' for a cancelled dream. Record state is correctly preserved by manager.ts defense-in-depth guards.

Code quality is high — precise cancellation flow, robust lock release, exhaustive discriminated unions in UI, comprehensive tests. LGTM! ✅

— deepseek-v4-pro via Qwen Code /review

@tanzhenxin tanzhenxin added the type/feature-request New feature or enhancement request label May 6, 2026

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

Review

This PR cleanly extends the unified Background tasks UI to a fourth kind (dream) and adds end-to-end cancellation; the cancellation race analysis is sound, test coverage is dense at the right places, and the design trade-offs are well-documented in the description.

Verdict

APPROVE — Worth landing as-is.

@tanzhenxin tanzhenxin merged commit d447866 into main May 6, 2026
13 checks passed
TaimoorSiddiquiOfficial pushed a commit to TaimoorSiddiquiOfficial/HopCode that referenced this pull request May 6, 2026
…nLM#3836)

- fix(core): prevent auto-memory recall from blocking main request (QwenLM#3814)
- feat(core,cli): surface and cancel auto-memory dream tasks (QwenLM#3836)
- fix(sdk-python): standardize TAG_PREFIX to include v suffix (QwenLM#3832)

Conflict resolutions:
- Footer.tsx: removed stale dreamRunning/configInitMessage (not used in render)
- BackgroundTaskViewContext.tsx: kept @hoptrendy/hopcode-core, added createDebugLogger
- manager.test.ts: included upstream cancelTask + subscribe filter tests,
  replaced QWEN_CODE_MEMORY_LOCAL with HOPCODE_MEMORY_LOCAL
- get-release-version.js: kept hopcode-sdk brand, adopted upstream v prefix fix

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
DragonnZhang pushed a commit that referenced this pull request May 8, 2026
* feat(cli): surface auto-memory dream tasks in Background tasks dialog

Adds `dream` as a fourth kind in the Background tasks pill + dialog,
alongside agent / shell / monitor. Subscribes to MemoryManager via
its existing subscribe() / listTasksByType() API and adapts
MemoryTaskRecord into a DreamDialogEntry view-model. Zero changes
to the core package.

Filters out `pending` (sub-second transition) and `skipped` (every
UserQuery that misses the gate creates one) records. Caps retained
terminal entries at 3 since `MemoryManager.tasks` has no eviction
path; without the cap, completed dreams would accumulate over the
project's lifetime (mirrors MonitorRegistry's terminal cap pattern).

Extract tasks are intentionally NOT surfaced — they fire on every
UserQuery, would flood the pill, and the `memory_saved` toast in
useGeminiStream already covers their completion signal.

Read-only for now: cancellation requires MemoryManager.cancelTask
+ task_stop integration which lands in a follow-up PR. The dialog
suppresses the "x stop" hint for dream entries until then to avoid
silent no-op keystrokes.

Refs #3634

* docs(cli): rephrase dream filter comment to focus on extract vs dream

The earlier comment compared the design to a non-qwen-code product;
restate the rationale in terms of the local extract / dream split
(extract fires every UserQuery and surfaces via memory_saved toast,
dream fires after gates and warrants pill / dialog visibility).

* feat(core,cli): cancel dream consolidation tasks via dialog and task_stop

Wires cancellation for the auto-memory dream task kind:

- `MemoryManager.cancelTask(taskId)` — aborts the dream's fork-agent
  via a new per-task AbortController, marks the record `cancelled`
  before aborting so the runDream catch path can detect user-intent
  and avoid overwriting with a generic `failed`. The existing
  finally block releases the consolidation lock as the agent unwinds.
- `MemoryManager.getTask(id)` — point lookup helper so cross-cutting
  consumers like `task_stop` can route by id without a project root.
- AbortSignal threaded through `scheduleDream` → `runDream` →
  `runManagedAutoMemoryDream` → `planManagedAutoMemoryDreamByAgent`
  → `runForkedAgent.abortSignal` (already supported).
- `task_stop` tool gets a 4th dispatch branch: dream task ids look
  up via MemoryManager and route through `cancelTask`. Extract is
  intentionally NOT cancellable — it runs synchronously on the
  request loop, cancelling would interfere with the user's own turn.
- `BackgroundTasksDialog` x-stop hint suppression for dream is removed
  (was a PR-1 placeholder); `cancelSelected` dream branch now calls
  `memoryManager.cancelTask`.
- `MemoryTaskStatus` gains `'cancelled'`. Dream view-model widens
  status union and filter to surface cancelled entries (terminal
  cap continues to apply).

Refs #3634

* fix(core,cli): address review feedback on dream cancellation surface

- DreamDetailBody: comment said cancellation "lands in PR-2" but the
  same PR wires `cancelSelected` for dream entries. Reword to describe
  what's actually shipped + flag in-flight progress as the real
  follow-up.
- task_stop: drop the unreachable `!aborted` error branch. The status
  guard above already confirms `running`, and `cancelTask` is
  synchronous; in this branch it cannot return false.

* fix(core): handle resolved-cancel path from runForkedAgent for dream tasks

runForkedAgent maps AgentTerminateMode.CANCELLED to a resolved
{status: 'cancelled'} result rather than rejecting. The cancel-via-
task_stop path landed in the previous commit assumed the call would
throw — when it didn't, the runDream success path overwrote the
user-cancelled record with 'completed' AND bumped lastDreamAt
metadata, suppressing the next legitimate dream cycle.

Two-layer defense:

- dreamAgentPlanner now rethrows when the fork agent reports
  cancelled status (mirrors the existing failed-status throw).
  This is the source-of-truth fix.

- runDream now checks abortSignal.aborted after the await as
  defense in depth. If anything in the call chain ever forgets to
  propagate, this guard short-circuits the success path before
  metadata write.

Updates the existing dreamAgentPlanner test that previously pinned
the buggy "returns cancelled without throwing" behavior. Adds a
manager test that simulates the resolves-on-abort scenario directly
to verify the consumer-side guard catches anything the planner
might miss.

* fix(core,cli): address review feedback on dream UX, perf, and comment clarity

Three fixes from the post-cancellation-PR review:

- scheduleDream now sets an initial `progressText` ("Scheduled
  managed auto-memory dream.") on the in-flight record. Without
  this, the dialog Detail's Progress section stayed empty until
  completion — the PR description's mid-flight screenshot showed
  text that production never actually rendered.

- useBackgroundTaskView gates the MemoryManager.subscribe listener
  on a dream-content signature. The manager fires for every task
  transition (extract included, ~2x per UserQuery), but the dialog
  has no extract surface; without this dedup each extract notify
  forced a full 4-source re-merge + a fresh setEntries reference,
  re-rendering the dialog and pill on entries that hadn't changed.
  Added a test that pins the reference-stability invariant.

- task-stop comment was misleading — said "the status guard above
  already confirmed running", but for the dream branch the running
  check happens IN this branch (not earlier). Reworded.

* fix(core,cli): tighten cancelTask contract, dedup dream snapshot reads, sync test helper

Four fixes from the latest review pass:

- cancelTask() now enforces the AbortController invariant. The old
  `ac?.abort()` returned `true` even when no controller was found,
  meaning callers could see a successful return while the dream was
  not actually aborted (and would leak the consolidation lock until
  the agent finished naturally). The controller is registered
  synchronously alongside `status='running'`, so a missing controller
  for a running record is a contract violation — return false without
  flipping status so the caller knows the abort didn't take.

- useBackgroundTaskView's `refresh()` now reuses the dream snapshot
  the memory listener fetched for its dedup gate. The previous version
  re-read `listTasksByType('dream')` inside `computeDreamSig()` and
  again inside `refresh()` — extra work AND a race window where the
  gate signature could come from a different snapshot than the one
  used to build dreamEntries. Single read, single source of truth.

- The `dream()` test helper widened to include `'cancelled'` so it
  matches the production `MemoryTaskStatus` union. Added a small test
  asserting cancelled dreams flow through the kind discriminator (the
  dialog's terminal-cap window depends on showing the user the
  outcome of the abort they just triggered).

- Dropped the stale "PR-1 read-only / PR-2 cancellation" block
  comment above the dream-entries describe block — both are in this
  PR now.

* fix(core,cli): address self-review + Copilot feedback on dream surface

Combined fixes for the latest review pass — self-review notes (U1, U2,
U5, U6) plus Copilot's three new comments (C1, C2, C3):

- **Footer dream-indicator dedupe (U1)**: removed `useDreamRunning` +
  `✦ dreaming` right-column text. The new Background tasks pill
  already counts dream tasks alongside agent / shell / monitor;
  showing both produced two simultaneous signals for the same state.

- **task_stop dispatch surfaces extract distinctly (U2 + C1)**: a
  new `TASK_STOP_NOT_CANCELLABLE` error type fires when the task id
  resolves to a known-but-not-cancellable record (extract). Previously
  extract ids fell through to `NOT_FOUND`, misleading the model into
  thinking the id was never valid. Also surfaces the missing-controller
  case from `cancelTask` as an explicit error rather than reporting
  phantom success.

- **MemoryManager.cancelTask logs missing-controller violation (C2)**:
  the silent `return false` for the missing-AbortController case now
  emits a `debugLogger.warn` so the inconsistency is observable in
  debug bundles. Without the log a runaway dream burning tokens would
  leave no trail.

- **MemoryManager.subscribe taskType filter (C3)**: subscribers can
  now opt into per-type notify routing via `subscribe(fn, { taskType })`.
  Internal `notify()` calls pass the changed task's type so filtered
  consumers wake only on relevant transitions. The bg-tasks UI hook
  uses this to skip the per-UserQuery extract notify entirely — drops
  the per-extract O(n) signature work to zero.

- **runDream guards against late-cancel overwrite (U5)**: the
  success path now re-checks `abortSignal.aborted` between metadata
  read/write and before the final `update({status: 'completed'})`.
  Closes the ~tens-of-ms race window where `cancelTask` flipping
  status to `'cancelled'` would silently lose to the success
  continuation overwriting with `'completed'` + bumping
  `lastDreamAt`.

- **DreamDialogEntry.endTime semantic comment (U6)**: documents that
  `endTime` for cancelled records is the cancel-call moment (not the
  fork unwind), so a future maintainer doesn't treat it as a real
  fork-finish timestamp.

Tests: new `subscribe() taskType filter` describe block in manager,
new task_stop tests for `NOT_CANCELLABLE` (extract) and missing-
AbortController (dream); existing test renamed/widened.

* fix(core,cli): tighten error semantics + comments on dream surface

Four fixes from the latest review pass:

- New `TASK_STOP_INTERNAL_ERROR` error type for the missing-
  AbortController contract violation. Previously the dispatcher
  reused `TASK_STOP_NOT_RUNNING`, which is misleading — the task IS
  running, cancellation just couldn't be delivered. Distinct type
  signals "this is unexpected, file a bug" vs `NOT_CANCELLABLE`
  which signals "expected behavior, use a different approach".

- Reworded the `useBackgroundTaskView` filter comment. Said "every
  UserQuery that misses the gate creates one [skipped record]" but
  `scheduleDream` returns `{status: 'skipped'}` early without
  creating a record for most gate misses; only the
  acquireDreamLock/EEXIST race actually stores a `'skipped'` record.

- Strengthened the `subscribe() unsubscribe` test. The previous
  version asserted "not called yet" without firing any notify after
  unsubscribe, so a regression that left the listener attached
  would still pass. Now schedules an extract before AND after the
  unsubscribe, verifying the call count doesn't increment.

- Moved `const debugLogger = createDebugLogger(...)` below the
  full import block in manager.ts. Previous version sat between
  imports, violating eslint-plugin-import's `import/first` rule
  (didn't trip lint locally, but worth fixing before it does).

* fix(core): skip scheduleDream early when params.config is missing

`ScheduleDreamParams.config` is optional in the type so test paths
can omit it, but production callers always pass one. Without a
config, `runManagedAutoMemoryDream` throws because the fork-agent
execution requires it. With dream tasks now visible in the
Background tasks dialog, that throw becomes a noisy `failed` entry
the user sees but didn't trigger.

Convert the omitted-config case to the same `disabled` skip path
that an explicitly-disabled config takes, so a no-config call
short-circuits before any record is stored. Existing tests that
relied on the old "no config = proceed past the disabled gate"
behavior now pass an explicit `makeMockConfig()` (matching what
they would do in any realistic scenario).

New test pins the no-config skip behavior + asserts no record
was stored (so a regression that drops the early skip would
produce a visible failed entry in the dialog and fail the test).

* fix(core): plug subscribe Map leak + dream.ts late-cancel ordering bug

Two fixes from the latest review pass:

- `MemoryManager.subscribe`'s typed-branch unsubscribe deleted the
  listener from its per-type Set but left the empty Set sitting in
  `subscribersByType`. Over a long-running session with repeated
  React mount/unmount of the bg-tasks view, that accumulates dead
  Map entries forever. Drop the entry when the bucket goes empty.

- `runManagedAutoMemoryDream` writes metadata after the fork agent
  returns (`bumpMetadata` → `rebuildManagedAutoMemoryIndex` →
  `updateDreamMetadataResult`). If the user presses 'x' between the
  fork's success return and these writes, the writes proceed and
  bump `lastDreamAt` — leaving the visible UI ('Stopped') disagreeing
  with the scheduler gate (sees a recent successful dream and
  suppresses the next cycle). manager.ts already short-circuits its
  own metadata write via the post-await abort check, but it can't
  block writes that already happened inside dream.ts. Adds the same
  abort-signal check between each write step here.

* fix(core): swallow releaseDreamLock errors so they don't poison outcome

If `releaseDreamLock` throws inside the inner finally (e.g. filesystem
error on the lock file), the exception propagates to the outer catch
and overwrites a successfully-completed dream record with 'failed'.
The on-disk metadata is already up-to-date at that point, so the user
sees a contradictory state — `lastDreamAt` was bumped but the UI
shows a failure.

Wrap the release in a try/catch with `debugLogger.warn`. The lock
file is still cleaned up on the next session via the existing
staleness sweep, so swallowing the release error doesn't risk a
permanent stuck lock.

* fix(core): thread abortSignal into dream metadata writes

The pre-call abort checks in `runManagedAutoMemoryDream` close most
of the late-cancel race window, but each metadata helper itself does
read → mutate → write across two awaits. If the user cancels between
those two awaits the write still happens, persisting `lastDreamAt`
for an aborted run and suppressing the next legitimate dream cycle.

Thread `abortSignal` into `bumpMetadata` and
`updateDreamMetadataResult`; both now re-check between the read and
the write, returning early without persisting when the signal has
already fired. The pre-call checks remain as the first line of
defense; this guards the race that opens after the call enters.

* fix(core): close dream cancel race + surface lock-release failures

Two related fixes from the latest review pass:

- Move scheduler-gating metadata writes out of `runManagedAutoMemoryDream`
  and into `MemoryManager.runDream`, sequenced AFTER the
  status='completed' flip. The previous shape left a race window
  where cancellation arriving during/after `fs.writeFile` could
  persist `lastDreamAt` while the manager flipped status to
  'cancelled' — visible UI ('Stopped') would disagree with the
  scheduler gate (sees a recent successful dream), suppressing the
  next legitimate dream cycle. The new order makes the gating
  metadata write race-free: once status !== 'running', cancelTask
  refuses, so any cancel arriving during the metadata write is
  ignored. The remaining "cancel raced the synchronous status
  update" window is handled by a post-update abort recheck that
  restores 'cancelled' and skips the metadata write.

  Drops the now-dead `bumpMetadata` helper from dream.ts; index
  rebuild stays there since it's informational, not gating.

- Surface `releaseDreamLock` failures on the task record's metadata
  (`lockReleaseError`). The previous fix logged-and-swallowed only,
  so a Windows EPERM or ENOENT race would silently block subsequent
  dreams as 'locked' with no UI signal explaining why dreaming had
  stopped. Logger keeps emitting the warn for debug bundles.

* fix(core,cli): address 8 review findings on dream surface

Reverts the metadata-write behavior regression, plugs the
storeWith reentrancy hole, surfaces lock/metadata warnings in the
UI, and a handful of cleanups:

- Wrap gating-metadata read+write in try/catch (manager.ts). The
  PR moved metadata writes from dream.ts (best-effort, swallowed)
  to manager.ts (unguarded). A throw from readDreamMetadata /
  writeDreamMetadata now propagates to the outer catch and
  overwrites a successfully-completed dream with 'failed' — the
  dream actually did its work and touched files are visible. New
  catch logs + writes `metadataWriteError` on the record so the UI
  can explain why the next dream may re-fire sooner than expected.

- Register the AbortController BEFORE storeWith in scheduleDream.
  storeWith fires a notify; a subscriber synchronously calling
  cancelTask(record.id) would otherwise see status='running' but
  no controller, hitting the missing-controller defensive warn
  path and reporting a phantom failure on a brand-new dream.

- Surface `lockReleaseError` and `metadataWriteError` in the dream
  view-model and DreamDetailBody (rendered as warnings, not
  errors, so the terminal status stays Completed). Previous fix
  wrote them to record.metadata only — nothing in the cli read or
  rendered them, so users still had no UI signal.

- Preserve `result.touchedTopics` on the unreachable cancel-raced-
  status-update branch. If a future refactor introduces an await
  there, the restored cancelled record would otherwise drop the
  already-produced result; the UI would report a clean cancellation
  even though memory files were already modified.

- Add `'cancelled'` to MemoryDreamEvent status union and emit a
  cancelled telemetry event from the runDream catch path. Without
  this a cancelled dream is indistinguishable from one that never
  scheduled in the first place.

- Drop the dead abortSignal param from updateDreamMetadataResult
  in dream.ts (no caller passes it after the manager.ts move).

- Swap declaration order of `computeDreamSig` and `refresh` in
  useBackgroundTaskView.ts (TDZ-fragile against a future refactor
  that adds a synchronous refresh call between them).

- Update the unreachable cancel-raced-update branch comment to
  describe what's actually true ("defense-in-depth, unreachable
  today") instead of the confusing "cancelTask flipped" path.

- cancelSelected now checks the cancelTask return value and logs
  via debugLogger when false. Today this branch is unreachable
  thanks to the controller-register-before-storeWith fix above,
  but if a future refactor breaks the invariant the silent ignore
  would let the user think the cancel took effect.

- Mirror the manual /dream metadata path's `recentSessionIdsSinceDream = []`
  reset in the auto path — field is dead code today but keeping
  the two write sites in sync avoids surprises.

Telemetry metric `recordMemoryDreamMetrics` widened to accept the
new 'cancelled' status (downstream consumer in loggers.ts).

* fix(memory): same-session recovery when releaseDreamLock throws

The prior fix surfaced lockReleaseError on the dialog so the user knows
the lock release failed (Windows EPERM, ENOENT race, disk full, etc.) —
but until next process start, dreamLockExists() still sees a fresh-mtime
lock owned by an alive PID (us!) and silently suppresses every
subsequent scheduleDream() call as `{status: 'skipped',
skippedReason: 'locked'}`. The user sees the warning AND zero further
dream activity, and the staleness sweep that would clean the leaked
lock only runs at session start.

Adds a `dreamLockReleaseFailed` flag set in the catch. The next
scheduleDream() force-cleans the leaked lock file via fs.rm({force: true})
before the existence check, so dream scheduling resumes within the same
session. Best-effort: if even the forced rm fails (truly unrecoverable
filesystem state), falls through to the existing 'locked' skip path.

This is an incremental improvement on top of b00ecde's UI-surface fix.
The two together give the full story: warning visible → automatic
recovery on next attempt.

* fix(memory): real cancelled-dream duration + clarify index-rebuild ordering

Two follow-up suggestions from review:

- **`duration_ms: 0` in cancelled-dream telemetry** (manager.ts):
  the user-cancel path emitted `MemoryDreamEvent` with
  `duration_ms: 0`, which would silently skew latency histograms / p95
  metrics by treating cancelled dreams as instant. Capture
  `dreamStartMs = Date.now()` at the top of `runDream` and emit the
  real elapsed time in the cancel branch.

- **Misleading index-rebuild comment** (dream.ts:75–84): the comment
  claimed the index rebuild "is still done before returning when
  topics were touched", but the code returns early on
  `abortSignal?.aborted` BEFORE the rebuild. Rewrote the comment to
  describe the actual cancel-aware ordering — abort returns partial
  result without rebuilding (rebuild is expensive; next dream cycle
  will rebuild against the latest files anyway), live path rebuilds
  only when topics changed.

22 / 22 manager tests pass; tsc clean.
xaelistic pushed a commit to xaelistic/qwen-code that referenced this pull request Jun 7, 2026
* feat(cli): surface auto-memory dream tasks in Background tasks dialog

Adds `dream` as a fourth kind in the Background tasks pill + dialog,
alongside agent / shell / monitor. Subscribes to MemoryManager via
its existing subscribe() / listTasksByType() API and adapts
MemoryTaskRecord into a DreamDialogEntry view-model. Zero changes
to the core package.

Filters out `pending` (sub-second transition) and `skipped` (every
UserQuery that misses the gate creates one) records. Caps retained
terminal entries at 3 since `MemoryManager.tasks` has no eviction
path; without the cap, completed dreams would accumulate over the
project's lifetime (mirrors MonitorRegistry's terminal cap pattern).

Extract tasks are intentionally NOT surfaced — they fire on every
UserQuery, would flood the pill, and the `memory_saved` toast in
useGeminiStream already covers their completion signal.

Read-only for now: cancellation requires MemoryManager.cancelTask
+ task_stop integration which lands in a follow-up PR. The dialog
suppresses the "x stop" hint for dream entries until then to avoid
silent no-op keystrokes.

Refs QwenLM#3634

* docs(cli): rephrase dream filter comment to focus on extract vs dream

The earlier comment compared the design to a non-qwen-code product;
restate the rationale in terms of the local extract / dream split
(extract fires every UserQuery and surfaces via memory_saved toast,
dream fires after gates and warrants pill / dialog visibility).

* feat(core,cli): cancel dream consolidation tasks via dialog and task_stop

Wires cancellation for the auto-memory dream task kind:

- `MemoryManager.cancelTask(taskId)` — aborts the dream's fork-agent
  via a new per-task AbortController, marks the record `cancelled`
  before aborting so the runDream catch path can detect user-intent
  and avoid overwriting with a generic `failed`. The existing
  finally block releases the consolidation lock as the agent unwinds.
- `MemoryManager.getTask(id)` — point lookup helper so cross-cutting
  consumers like `task_stop` can route by id without a project root.
- AbortSignal threaded through `scheduleDream` → `runDream` →
  `runManagedAutoMemoryDream` → `planManagedAutoMemoryDreamByAgent`
  → `runForkedAgent.abortSignal` (already supported).
- `task_stop` tool gets a 4th dispatch branch: dream task ids look
  up via MemoryManager and route through `cancelTask`. Extract is
  intentionally NOT cancellable — it runs synchronously on the
  request loop, cancelling would interfere with the user's own turn.
- `BackgroundTasksDialog` x-stop hint suppression for dream is removed
  (was a PR-1 placeholder); `cancelSelected` dream branch now calls
  `memoryManager.cancelTask`.
- `MemoryTaskStatus` gains `'cancelled'`. Dream view-model widens
  status union and filter to surface cancelled entries (terminal
  cap continues to apply).

Refs QwenLM#3634

* fix(core,cli): address review feedback on dream cancellation surface

- DreamDetailBody: comment said cancellation "lands in PR-2" but the
  same PR wires `cancelSelected` for dream entries. Reword to describe
  what's actually shipped + flag in-flight progress as the real
  follow-up.
- task_stop: drop the unreachable `!aborted` error branch. The status
  guard above already confirms `running`, and `cancelTask` is
  synchronous; in this branch it cannot return false.

* fix(core): handle resolved-cancel path from runForkedAgent for dream tasks

runForkedAgent maps AgentTerminateMode.CANCELLED to a resolved
{status: 'cancelled'} result rather than rejecting. The cancel-via-
task_stop path landed in the previous commit assumed the call would
throw — when it didn't, the runDream success path overwrote the
user-cancelled record with 'completed' AND bumped lastDreamAt
metadata, suppressing the next legitimate dream cycle.

Two-layer defense:

- dreamAgentPlanner now rethrows when the fork agent reports
  cancelled status (mirrors the existing failed-status throw).
  This is the source-of-truth fix.

- runDream now checks abortSignal.aborted after the await as
  defense in depth. If anything in the call chain ever forgets to
  propagate, this guard short-circuits the success path before
  metadata write.

Updates the existing dreamAgentPlanner test that previously pinned
the buggy "returns cancelled without throwing" behavior. Adds a
manager test that simulates the resolves-on-abort scenario directly
to verify the consumer-side guard catches anything the planner
might miss.

* fix(core,cli): address review feedback on dream UX, perf, and comment clarity

Three fixes from the post-cancellation-PR review:

- scheduleDream now sets an initial `progressText` ("Scheduled
  managed auto-memory dream.") on the in-flight record. Without
  this, the dialog Detail's Progress section stayed empty until
  completion — the PR description's mid-flight screenshot showed
  text that production never actually rendered.

- useBackgroundTaskView gates the MemoryManager.subscribe listener
  on a dream-content signature. The manager fires for every task
  transition (extract included, ~2x per UserQuery), but the dialog
  has no extract surface; without this dedup each extract notify
  forced a full 4-source re-merge + a fresh setEntries reference,
  re-rendering the dialog and pill on entries that hadn't changed.
  Added a test that pins the reference-stability invariant.

- task-stop comment was misleading — said "the status guard above
  already confirmed running", but for the dream branch the running
  check happens IN this branch (not earlier). Reworded.

* fix(core,cli): tighten cancelTask contract, dedup dream snapshot reads, sync test helper

Four fixes from the latest review pass:

- cancelTask() now enforces the AbortController invariant. The old
  `ac?.abort()` returned `true` even when no controller was found,
  meaning callers could see a successful return while the dream was
  not actually aborted (and would leak the consolidation lock until
  the agent finished naturally). The controller is registered
  synchronously alongside `status='running'`, so a missing controller
  for a running record is a contract violation — return false without
  flipping status so the caller knows the abort didn't take.

- useBackgroundTaskView's `refresh()` now reuses the dream snapshot
  the memory listener fetched for its dedup gate. The previous version
  re-read `listTasksByType('dream')` inside `computeDreamSig()` and
  again inside `refresh()` — extra work AND a race window where the
  gate signature could come from a different snapshot than the one
  used to build dreamEntries. Single read, single source of truth.

- The `dream()` test helper widened to include `'cancelled'` so it
  matches the production `MemoryTaskStatus` union. Added a small test
  asserting cancelled dreams flow through the kind discriminator (the
  dialog's terminal-cap window depends on showing the user the
  outcome of the abort they just triggered).

- Dropped the stale "PR-1 read-only / PR-2 cancellation" block
  comment above the dream-entries describe block — both are in this
  PR now.

* fix(core,cli): address self-review + Copilot feedback on dream surface

Combined fixes for the latest review pass — self-review notes (U1, U2,
U5, U6) plus Copilot's three new comments (C1, C2, C3):

- **Footer dream-indicator dedupe (U1)**: removed `useDreamRunning` +
  `✦ dreaming` right-column text. The new Background tasks pill
  already counts dream tasks alongside agent / shell / monitor;
  showing both produced two simultaneous signals for the same state.

- **task_stop dispatch surfaces extract distinctly (U2 + C1)**: a
  new `TASK_STOP_NOT_CANCELLABLE` error type fires when the task id
  resolves to a known-but-not-cancellable record (extract). Previously
  extract ids fell through to `NOT_FOUND`, misleading the model into
  thinking the id was never valid. Also surfaces the missing-controller
  case from `cancelTask` as an explicit error rather than reporting
  phantom success.

- **MemoryManager.cancelTask logs missing-controller violation (C2)**:
  the silent `return false` for the missing-AbortController case now
  emits a `debugLogger.warn` so the inconsistency is observable in
  debug bundles. Without the log a runaway dream burning tokens would
  leave no trail.

- **MemoryManager.subscribe taskType filter (C3)**: subscribers can
  now opt into per-type notify routing via `subscribe(fn, { taskType })`.
  Internal `notify()` calls pass the changed task's type so filtered
  consumers wake only on relevant transitions. The bg-tasks UI hook
  uses this to skip the per-UserQuery extract notify entirely — drops
  the per-extract O(n) signature work to zero.

- **runDream guards against late-cancel overwrite (U5)**: the
  success path now re-checks `abortSignal.aborted` between metadata
  read/write and before the final `update({status: 'completed'})`.
  Closes the ~tens-of-ms race window where `cancelTask` flipping
  status to `'cancelled'` would silently lose to the success
  continuation overwriting with `'completed'` + bumping
  `lastDreamAt`.

- **DreamDialogEntry.endTime semantic comment (U6)**: documents that
  `endTime` for cancelled records is the cancel-call moment (not the
  fork unwind), so a future maintainer doesn't treat it as a real
  fork-finish timestamp.

Tests: new `subscribe() taskType filter` describe block in manager,
new task_stop tests for `NOT_CANCELLABLE` (extract) and missing-
AbortController (dream); existing test renamed/widened.

* fix(core,cli): tighten error semantics + comments on dream surface

Four fixes from the latest review pass:

- New `TASK_STOP_INTERNAL_ERROR` error type for the missing-
  AbortController contract violation. Previously the dispatcher
  reused `TASK_STOP_NOT_RUNNING`, which is misleading — the task IS
  running, cancellation just couldn't be delivered. Distinct type
  signals "this is unexpected, file a bug" vs `NOT_CANCELLABLE`
  which signals "expected behavior, use a different approach".

- Reworded the `useBackgroundTaskView` filter comment. Said "every
  UserQuery that misses the gate creates one [skipped record]" but
  `scheduleDream` returns `{status: 'skipped'}` early without
  creating a record for most gate misses; only the
  acquireDreamLock/EEXIST race actually stores a `'skipped'` record.

- Strengthened the `subscribe() unsubscribe` test. The previous
  version asserted "not called yet" without firing any notify after
  unsubscribe, so a regression that left the listener attached
  would still pass. Now schedules an extract before AND after the
  unsubscribe, verifying the call count doesn't increment.

- Moved `const debugLogger = createDebugLogger(...)` below the
  full import block in manager.ts. Previous version sat between
  imports, violating eslint-plugin-import's `import/first` rule
  (didn't trip lint locally, but worth fixing before it does).

* fix(core): skip scheduleDream early when params.config is missing

`ScheduleDreamParams.config` is optional in the type so test paths
can omit it, but production callers always pass one. Without a
config, `runManagedAutoMemoryDream` throws because the fork-agent
execution requires it. With dream tasks now visible in the
Background tasks dialog, that throw becomes a noisy `failed` entry
the user sees but didn't trigger.

Convert the omitted-config case to the same `disabled` skip path
that an explicitly-disabled config takes, so a no-config call
short-circuits before any record is stored. Existing tests that
relied on the old "no config = proceed past the disabled gate"
behavior now pass an explicit `makeMockConfig()` (matching what
they would do in any realistic scenario).

New test pins the no-config skip behavior + asserts no record
was stored (so a regression that drops the early skip would
produce a visible failed entry in the dialog and fail the test).

* fix(core): plug subscribe Map leak + dream.ts late-cancel ordering bug

Two fixes from the latest review pass:

- `MemoryManager.subscribe`'s typed-branch unsubscribe deleted the
  listener from its per-type Set but left the empty Set sitting in
  `subscribersByType`. Over a long-running session with repeated
  React mount/unmount of the bg-tasks view, that accumulates dead
  Map entries forever. Drop the entry when the bucket goes empty.

- `runManagedAutoMemoryDream` writes metadata after the fork agent
  returns (`bumpMetadata` → `rebuildManagedAutoMemoryIndex` →
  `updateDreamMetadataResult`). If the user presses 'x' between the
  fork's success return and these writes, the writes proceed and
  bump `lastDreamAt` — leaving the visible UI ('Stopped') disagreeing
  with the scheduler gate (sees a recent successful dream and
  suppresses the next cycle). manager.ts already short-circuits its
  own metadata write via the post-await abort check, but it can't
  block writes that already happened inside dream.ts. Adds the same
  abort-signal check between each write step here.

* fix(core): swallow releaseDreamLock errors so they don't poison outcome

If `releaseDreamLock` throws inside the inner finally (e.g. filesystem
error on the lock file), the exception propagates to the outer catch
and overwrites a successfully-completed dream record with 'failed'.
The on-disk metadata is already up-to-date at that point, so the user
sees a contradictory state — `lastDreamAt` was bumped but the UI
shows a failure.

Wrap the release in a try/catch with `debugLogger.warn`. The lock
file is still cleaned up on the next session via the existing
staleness sweep, so swallowing the release error doesn't risk a
permanent stuck lock.

* fix(core): thread abortSignal into dream metadata writes

The pre-call abort checks in `runManagedAutoMemoryDream` close most
of the late-cancel race window, but each metadata helper itself does
read → mutate → write across two awaits. If the user cancels between
those two awaits the write still happens, persisting `lastDreamAt`
for an aborted run and suppressing the next legitimate dream cycle.

Thread `abortSignal` into `bumpMetadata` and
`updateDreamMetadataResult`; both now re-check between the read and
the write, returning early without persisting when the signal has
already fired. The pre-call checks remain as the first line of
defense; this guards the race that opens after the call enters.

* fix(core): close dream cancel race + surface lock-release failures

Two related fixes from the latest review pass:

- Move scheduler-gating metadata writes out of `runManagedAutoMemoryDream`
  and into `MemoryManager.runDream`, sequenced AFTER the
  status='completed' flip. The previous shape left a race window
  where cancellation arriving during/after `fs.writeFile` could
  persist `lastDreamAt` while the manager flipped status to
  'cancelled' — visible UI ('Stopped') would disagree with the
  scheduler gate (sees a recent successful dream), suppressing the
  next legitimate dream cycle. The new order makes the gating
  metadata write race-free: once status !== 'running', cancelTask
  refuses, so any cancel arriving during the metadata write is
  ignored. The remaining "cancel raced the synchronous status
  update" window is handled by a post-update abort recheck that
  restores 'cancelled' and skips the metadata write.

  Drops the now-dead `bumpMetadata` helper from dream.ts; index
  rebuild stays there since it's informational, not gating.

- Surface `releaseDreamLock` failures on the task record's metadata
  (`lockReleaseError`). The previous fix logged-and-swallowed only,
  so a Windows EPERM or ENOENT race would silently block subsequent
  dreams as 'locked' with no UI signal explaining why dreaming had
  stopped. Logger keeps emitting the warn for debug bundles.

* fix(core,cli): address 8 review findings on dream surface

Reverts the metadata-write behavior regression, plugs the
storeWith reentrancy hole, surfaces lock/metadata warnings in the
UI, and a handful of cleanups:

- Wrap gating-metadata read+write in try/catch (manager.ts). The
  PR moved metadata writes from dream.ts (best-effort, swallowed)
  to manager.ts (unguarded). A throw from readDreamMetadata /
  writeDreamMetadata now propagates to the outer catch and
  overwrites a successfully-completed dream with 'failed' — the
  dream actually did its work and touched files are visible. New
  catch logs + writes `metadataWriteError` on the record so the UI
  can explain why the next dream may re-fire sooner than expected.

- Register the AbortController BEFORE storeWith in scheduleDream.
  storeWith fires a notify; a subscriber synchronously calling
  cancelTask(record.id) would otherwise see status='running' but
  no controller, hitting the missing-controller defensive warn
  path and reporting a phantom failure on a brand-new dream.

- Surface `lockReleaseError` and `metadataWriteError` in the dream
  view-model and DreamDetailBody (rendered as warnings, not
  errors, so the terminal status stays Completed). Previous fix
  wrote them to record.metadata only — nothing in the cli read or
  rendered them, so users still had no UI signal.

- Preserve `result.touchedTopics` on the unreachable cancel-raced-
  status-update branch. If a future refactor introduces an await
  there, the restored cancelled record would otherwise drop the
  already-produced result; the UI would report a clean cancellation
  even though memory files were already modified.

- Add `'cancelled'` to MemoryDreamEvent status union and emit a
  cancelled telemetry event from the runDream catch path. Without
  this a cancelled dream is indistinguishable from one that never
  scheduled in the first place.

- Drop the dead abortSignal param from updateDreamMetadataResult
  in dream.ts (no caller passes it after the manager.ts move).

- Swap declaration order of `computeDreamSig` and `refresh` in
  useBackgroundTaskView.ts (TDZ-fragile against a future refactor
  that adds a synchronous refresh call between them).

- Update the unreachable cancel-raced-update branch comment to
  describe what's actually true ("defense-in-depth, unreachable
  today") instead of the confusing "cancelTask flipped" path.

- cancelSelected now checks the cancelTask return value and logs
  via debugLogger when false. Today this branch is unreachable
  thanks to the controller-register-before-storeWith fix above,
  but if a future refactor breaks the invariant the silent ignore
  would let the user think the cancel took effect.

- Mirror the manual /dream metadata path's `recentSessionIdsSinceDream = []`
  reset in the auto path — field is dead code today but keeping
  the two write sites in sync avoids surprises.

Telemetry metric `recordMemoryDreamMetrics` widened to accept the
new 'cancelled' status (downstream consumer in loggers.ts).

* fix(memory): same-session recovery when releaseDreamLock throws

The prior fix surfaced lockReleaseError on the dialog so the user knows
the lock release failed (Windows EPERM, ENOENT race, disk full, etc.) —
but until next process start, dreamLockExists() still sees a fresh-mtime
lock owned by an alive PID (us!) and silently suppresses every
subsequent scheduleDream() call as `{status: 'skipped',
skippedReason: 'locked'}`. The user sees the warning AND zero further
dream activity, and the staleness sweep that would clean the leaked
lock only runs at session start.

Adds a `dreamLockReleaseFailed` flag set in the catch. The next
scheduleDream() force-cleans the leaked lock file via fs.rm({force: true})
before the existence check, so dream scheduling resumes within the same
session. Best-effort: if even the forced rm fails (truly unrecoverable
filesystem state), falls through to the existing 'locked' skip path.

This is an incremental improvement on top of 2af76a752's UI-surface fix.
The two together give the full story: warning visible → automatic
recovery on next attempt.

* fix(memory): real cancelled-dream duration + clarify index-rebuild ordering

Two follow-up suggestions from review:

- **`duration_ms: 0` in cancelled-dream telemetry** (manager.ts):
  the user-cancel path emitted `MemoryDreamEvent` with
  `duration_ms: 0`, which would silently skew latency histograms / p95
  metrics by treating cancelled dreams as instant. Capture
  `dreamStartMs = Date.now()` at the top of `runDream` and emit the
  real elapsed time in the cancel branch.

- **Misleading index-rebuild comment** (dream.ts:75–84): the comment
  claimed the index rebuild "is still done before returning when
  topics were touched", but the code returns early on
  `abortSignal?.aborted` BEFORE the rebuild. Rewrote the comment to
  describe the actual cancel-aware ordering — abort returns partial
  result without rebuilding (rebuild is expensive; next dream cycle
  will rebuild against the latest files anyway), live path rebuilds
  only when topics changed.

22 / 22 manager tests pass; tsc clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/feature-request New feature or enhancement request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants