Skip to content

feat(core+cli): Workflow P4 — meta + /workflows + phase-tree (#4721)#5094

Merged
LaZzyMan merged 10 commits into
mainfrom
lazzy/workflow-p4-meta-workflows-pill
Jun 16, 2026
Merged

feat(core+cli): Workflow P4 — meta + /workflows + phase-tree (#4721)#5094
LaZzyMan merged 10 commits into
mainfrom
lazzy/workflow-p4-meta-workflows-pill

Conversation

@LaZzyMan

@LaZzyMan LaZzyMan commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Implements phase P4 of the Dynamic Workflows port (per #4721), building on the merged P1 (#4732), P2 (#4947), and P3 (#5034). Both halves of P4 ship in this PR:

  • P4a — meta extraction (commits 5b56c3979 / 55c23a027 / 402df8f23): extractAndStripMeta replaces P1's stripExportMeta call site inside createWorkflowSandbox.run; WorkflowMeta is a first-class field on WorkflowRunOutcome / WorkflowExecutionError; WorkflowTool display payload surfaces it when present.
  • P4b — /workflows command + phase-tree UI (commit c3f9d845e): WorkflowRunRegistry (4th sibling of BackgroundTaskRegistry / BackgroundShellRegistry / MonitorRegistry), TaskKind widening to add 'workflow', WorkflowOrchestratorEmitter for live phase / dispatch events, BackgroundTasksPill count + WorkflowDetailBody phase tree in the unified dialog, new /workflows slash command listing active + completed runs.

P4a architecture

Reuse the P1 brace-walker (zero-dep, no parser deps — matches the P1 design posture; no acorn / @babel/parser introduced) to locate the meta object literal's source range, then evaluate the literal inside a fresh vm.createContext(Object.create(null)). The eval context has a null-prototyped globalThis and no host bridge — no access to args / process / require / the workflow-sandbox bridge globals. The vm realm still exposes its OWN intrinsics (Object / Math / Date / JSON), which is fine: meta extraction is one-shot at tool invocation, not replayed on resume, so non-determinism in the meta literal does not break the resume contract the script body honours. validateMeta walks the eval result field-by-field and copies into a fresh host-realm plain object — no JSON round-trip needed because every contract field is a primitive. After eval, rejectThenablesInMeta recursively walks the result, marks any dangling thenable handled with .catch(() => {}) (so Node's default --unhandled-rejections=throw cannot terminate the host on the next tick), and throws an explicit error — closing the R3 dynamic-import() crash vector wenshao reproduced.

P4a user-visible additions:

  • extractAndStripMeta(source) exported from workflow-sandbox.ts
  • WorkflowMeta interface — verbatim shape from upstream Claude Code 2.1.168:
    interface WorkflowMeta {
      name: string;
      description: string;
      whenToUse?: string;
      phases?: Array<{ title: string; detail?: string; model?: string }>;
    }
  • WorkflowSandbox.getMeta() accessor alongside getPhases() / getLogs()
  • WorkflowRunOutcome.meta: WorkflowMeta | null (non-breaking)
  • WorkflowExecutionError.meta: WorkflowMeta | null so failure display shows the workflow's name / description / phases even when the script body throws after meta parsed cleanly
  • WorkflowTool.execute adds meta to the returnDisplay payload when present (omitted when the script had no meta)

Error messages verbatim from upstream where applicable:

  • meta.name must be a non-empty string
  • meta.description must be a non-empty string

P4b architecture

TaskKind widens from 3 → 4 ('agent' | 'shell' | 'monitor' | 'workflow'); TaskState picks up WorkflowTask (carries runId, meta, current phase, phase history, dispatch counters, recent logs). New WorkflowRunRegistry is a sibling of the three existing per-kind registries — same register / cancel / get / list / on('statusChange') shape so useBackgroundTaskView subscribes the same way. Eviction is MAX_RETAINED_TERMINAL_WORKFLOWS = 10, sized smaller than MAX_RETAINED_TERMINAL_AGENTS = 32 because workflow rows carry heavier labels (name + phase tree) and users typically run far fewer workflows than agents per session.

A new WorkflowOrchestratorEmitter interface lets the orchestrator + sandbox emit events into the host without crossing the vm-realm boundary: phaseStarted fires from safePhase, agentDispatched / agentCompleted fire from the orchestrator's countedDispatch, logAppended fires from safeLog. Defensive try/catch around every emit so a subscriber error never bubbles into the script. The orchestrator accepts an optional runId in WorkflowRunRequest so WorkflowTool can pre-generate the id and register the run with the registry BEFORE run() resolves — without this, the registry would never see the dispatch events.

WorkflowTool registers the run at execute() start, wires the emitter to the registry's onPhaseStarted / onAgentDispatched / onAgentCompleted, flips canUpdateOutput to true so the tool result block live-renders as a JSON snapshot of the phase tree, and routes terminals to registry.complete / fail / cancel. signal.aborted === truecancel rather than fail, so the dialog distinguishes user intent from script bugs.

CLI side:

  • BackgroundTasksPill.tsx: KIND_NAMES gains workflow, counts accumulator + sort order updated. Order is shell → agent → monitor → workflow → dream (user-initiated before system-initiated). The pill renders N workflow(s) alongside existing kinds.
  • useBackgroundTaskView.ts: subscribes to the workflow registry, includes workflow entries in the merged DialogEntry[]. entryId switch adds case 'workflow': return entry.runId.
  • BackgroundTasksDialog.tsx: new inline WorkflowDetailBody matches MonitorDetailBody style — header (name + description + whenToUse + status + runtime), phase tree truncated at MAX_VISIBLE_PHASES = 20 with +N more above, log tail truncated at MAX_VISIBLE_LOG_LINES = 10, error block on failure. Row label: [workflow] <name> · <currentPhase> (M/N agents). rowLabel / DetailBody / cancelSelected switches all gain a workflow case.
  • BackgroundTaskViewContext.tsx cancelSelected: case 'workflow': config.getWorkflowRunRegistry().cancel(target.runId, Date.now()). Idempotent with the WorkflowTool's signal.aborted catch arm.
  • New packages/cli/src/ui/commands/workflowsCommand.ts: bare /workflows lists active + completed runs (running first, terminal by endTime DESC). /workflows <runId> opens a per-run detail dump (meta block + status + phase tree + recent logs + errors). argumentHint is [runId]. Registered in BuiltinCommandLoader.ts gated by Config.isWorkflowsEnabled() — command vanishes from typeahead when the env-var kill switch (QWEN_CODE_DISABLE_WORKFLOWS=1) is set or the opt-in flag (QWEN_CODE_ENABLE_WORKFLOWS=1) is absent.

Scope deferrals

Out of scope Reason Plan
ACP daemon protocol widening (packages/acp-bridge/src/bridgeTypes.ts, status.ts, tasksSnapshot.ts) Cross-SDK + web-shell contract — independent review safer Follow-up PR P4c
Per-phase token rollup in WorkflowDetailBody Needs P5's budget tracker Lands with P5
/workflows save <runId> / /workflows inspect subcommands Future enhancement; binary strings reference upstream but no concrete need yet Future
Pause / resume keybindings in the workflow detail body Needs P6's resume cache Lands with P6

Why it's needed

P1's stripExportMeta only DELETED the export const meta declaration so the script could parse as a Node vm script. The meta object itself was discarded. P2/P3 ran workflows from tool calls but the user couldn't tell a workflow was running — no pill count, no dialog row, no progress UI. P4 (a+b) makes workflows visible in the TUI by piping the orchestrator's runs through the same background-task envelope that agent / shell / monitor already use, and surfaces the meta declaration so users can identify which workflow ran without re-reading the script source.

Reviewer Test Plan

How to verify

cd packages/core
npx vitest run \
  src/agents/workflow-run-registry.test.ts \
  src/agents/runtime/workflow-sandbox.test.ts \
  src/agents/runtime/workflow-orchestrator.test.ts \
  src/tools/workflow/workflow.test.ts
# → 4 files, all green (~223 tests including 14 new registry tests)

cd ../cli
npx vitest run \
  src/ui/commands/workflowsCommand.test.ts \
  src/ui/components/background-view/BackgroundTasksPill.test.tsx \
  src/ui/components/background-view/BackgroundTasksDialog.test.tsx \
  src/ui/hooks/useBackgroundTaskView.test.ts
# → 4 files, all green (~73 tests)

New tests for P4a specifically:

  • workflow-sandbox.test.ts (14 new under describe('extractAndStripMeta')): contract extraction, error-message verbatim, host-realm prototype identity, Promise-rejection guard (top-level + nested).
  • workflow-sandbox.test.ts (3 new under createWorkflowSandbox): getMeta lifecycle.
  • workflow-orchestrator.test.ts (3 new): outcome.meta null/parsed + error.meta carries on body throw.
  • workflow.test.ts (4 new): display surfaces meta, omits when absent, failure-path meta, meta-shaped result collision.

New tests for P4b specifically:

  • workflow-run-registry.test.ts (14 new): register / phase / dispatch / log-tail / complete / fail / cancel / eviction / running-never-evicted / register-callback / status-change-callback / error-tolerance.
  • workflowsCommand.test.ts (6 new): empty-runs message / list-with-running-first / non-interactive omits tip / detail-view-known-runId / detail-view-unknown-runId-error / runId trim.

tsc --noEmit + eslint + prettier --check clean on packages/core and packages/cli.

Real-LLM E2E (P4a)

Ran 6/6 against qwen3-coder-plus via DashScope (OpenAI-compatible endpoint), gated by DASHSCOPE_API_KEY so CI without the env skips the file. See workflow-p4a-meta-live.live.test.ts.

Scenario Wall-clock What it verifies end-to-end
A meta + single agent() 787ms outcome.meta mirrors the declared literal; display surfaces full meta block; Object.getPrototypeOf(outcome.meta) === Object.prototype + same for phases[] array + each phase entry — guards the T1/T8/T14 realm-escape boundary end-to-end
B no meta + single agent() 581ms outcome.meta === null; display payload completely omits the meta key (conditional spread)
C malformed meta (missing name) 4ms Throws meta.name … before the sandbox runs — 0 agent dispatches (no LLM budget burnt on a bad meta)
D meta + agent() + body throw 715ms WorkflowExecutionError.meta carries the parsed meta on the failure path; agent was called once; failure-display includes meta block
E parallel() 3-fan-out + meta 640ms Real concurrency (dispatch arrival order [BLUE,RED,GREEN] ≠ result order [RED,GREEN,BLUE] — position-aligned by parallel()); meta.phases[].title matches the executed phase list
F pipeline() 2-stage + meta 1361ms Both declared phases (TranslateShout) actually run; each input visits each stage exactly once (2/2 dispatch counts per stage); catchatCHAT, dogchienCHIEN

R3 review (wenshao) — addressed in 402df8f

  • Critical: dynamic import() (or any Promise-valued meta field) crashed the host process via dangling unhandled rejection after runInContext returned. Fix: rejectThenablesInMeta recursively walks the eval result, neutralises any thenable with .catch(() => {}), throws an explicit meta values must not be Promises error. 2 RED-first regression tests (top-level + nested in phases[]).
  • Critical: tsc --noEmit 11 errors in the new live E2E test file blocked CI Lint + all 3 Test jobs. Fix: imported WorkflowAgentOpts from workflow-sandbox.js; dropped liveDispatch's explicit type annotation; added required args: undefined to every orch.run({ script }) call.
  • 5 R3 Suggestions declined (out of scope or latent). See R3 triage summary at feat(core+cli): Workflow P4 — meta + /workflows + phase-tree (#4721) #5094 (comment).

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️ CI-only
🐧 Linux ⚠️ CI-only

Risk & Scope

  • Main risk or tradeoff — TaskKind widening from 3 → 4 ripples through every exhaustive kind switch in core + cli. The TypeScript surface forces every site to either handle workflow or fail to compile. CI typecheck on this branch verifies the rippling is complete inside CLI + core; the ACP daemon protocol surface (cross-SDK contract) is explicitly deferred to a follow-up PR — temporary filter at the ACP boundary will be added there. Within P4b's scope every consumer has been updated.
  • Security boundary unchanged — workflows run through the same vm.createContext sandbox as P1-P3; the P4b emitter is purely host-side (called from safePhase / safeLog closures + countedDispatch), never crosses the vm realm. Promise-valued meta fields rejected before they can leave a dangling rejection.
  • Not validated / out of scope — ACP daemon propagation (P4c), per-phase token rollup (P5), pause/resume (P6), ultracode keyword trigger (P7).
  • Breaking changes / migration notes — none for non-CLI consumers. CLI consumers see a new builtin command (/workflows) that defaults to hidden when isWorkflowsEnabled() is false, so it doesn't surface in typeahead by default. WorkflowRunOutcome.meta is non-breaking — existing destructuring of { runId, result, phases, logs } continues to work. TaskKind is widened from a closed 3-string union to 4 — strict pattern-matching consumers MUST add a workflow case (TypeScript will surface this).

Linked Issues

Related #4721 (parent design — multi-phase, not closed by this PR)

…4721)

First half of P4 (per the refined #4721 plan). Extracts the script's
`export const meta = {...}` declaration into a typed object so the
workflow tool's display payload, and the future /workflows command +
phase-tree UI, can read it without re-parsing the script source. The
other half of P4 (slash command + KIND_NAMES extension + phase-tree
UI + WorkflowTaskRegistry) is queued as a follow-up PR.

Architecture: reuse the P1 brace-walker (zero-dep, no parser deps) to
locate the meta object literal's source range, then evaluate the literal
inside a fresh `vm.createContext(Object.create(null))` — null-prototyped
globalThis, no host bridge (no `args` / `process` / `require` / workflow-
sandbox globals). The vm realm still exposes its OWN intrinsics
(`Object` / `Math` / `Date` / `JSON`), which is fine: meta extraction is
one-shot at tool invocation, not replayed on resume. validateMeta walks
the eval result field-by-field and copies into a fresh host-realm plain
object — no JSON round-trip needed because every contract field is a
primitive.

User-visible additions:
- `extractAndStripMeta(source)` exported from workflow-sandbox.ts
- `WorkflowMeta` interface (`{ name, description, whenToUse?, phases?: Array<{title, detail?, model?}> }`) — verbatim shape from upstream Claude Code 2.1.168
- `WorkflowSandbox.getMeta()` accessor alongside `getPhases()` / `getLogs()`
- `WorkflowRunOutcome.meta: WorkflowMeta | null` (non-breaking add)
- `WorkflowExecutionError.meta: WorkflowMeta | null` so the failure
  display shows the workflow's name / description / phases even when
  the script body throws
- `WorkflowTool.execute` adds `meta` to the returnDisplay payload when
  present (omitted when the script had no meta)

Error messages verbatim from upstream where applicable:
- `meta.name must be a non-empty string`
- `meta.description must be a non-empty string`

Refactor: P1's `stripExportMeta` is preserved as a thin wrapper around
a new `findMetaBlockBounds` helper that both old and new functions
share. All 86 existing sandbox tests pass unchanged (no behavior
regression in the strip path).

Tests:
- 11 new `extractAndStripMeta` unit tests covering happy path, optional
  fields, missing-required validation, malformed shape, vm-eval failure,
  null-prototype globalThis (no `args` / `process` / `require`), and
  unbalanced braces
- 3 new `createWorkflowSandbox.getMeta()` integration tests
- 3 new `WorkflowOrchestrator` outcome.meta tests (null path, parsed path,
  meta-survives-body-throw on the error path)
- 3 new `WorkflowTool` display payload tests (meta in payload, omitted
  when absent, present on failure path)

Suite: 207/207 workflow + adjacent regression green; typecheck +
lint clean on packages/core. (Pre-existing acp test type errors in
packages/cli are unrelated; CI will confirm.)

Related #4721 (parent design — multi-phase, not closed by this PR)
Related #4732 (P1) #4947 (P2) #5034 (P3) — all merged
P4b follow-up: /workflows command + TaskKind workflow union + BackgroundTasksPill KIND_NAMES + phase-tree UI + WorkflowTaskRegistry
@qwen-code-ci-bot

qwen-code-ci-bot commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Re-run on the combined P4a + P4b PR (prior triage was on P4a alone; the PR has since grown to include P4b with R7 fixes applied).

Template looks good ✓ — all required sections present. "Real-LLM E2E" substitutes for "Evidence (Before & After)" appropriately; the "Tested on" table and "Risk & Scope" are thorough.

On direction: clearly aligned. This is P4 of the Dynamic Workflows port under the established #4721 plan, building on three merged phases (P1 #4732, P2 #4947, P3 #5034). Upstream Claude Code's CHANGELOG has extensive workflow history — /workflows command, workflow validation fixes, workflow agents, trigger keyword shimmer — confirming this is a real, actively-developed capability. P4a (meta extraction) is the prerequisite for P4b's listing and phase-tree UI; shipping both together is the right call since P4b's display surfaces depend on P4a's WorkflowMeta type.

On approach: the combined scope (2931 additions, 26 files) is large but well-organized. P4a adds meta extraction infrastructure (~500 lines of logic + tests). P4b adds a 4th registry sibling, /workflows command, pill/dialog/hook integration, and TaskKind widening — each following established patterns from the existing three registries. The bulk of additions are tests (232 core + 116 CLI = 348 total) and UI components that mirror the existing MonitorDetailBody pattern. I don't see unrelated changes or drive-by refactors — every file touched serves the stated goal. The ACP daemon protocol widening is explicitly deferred to P4c, which is the right boundary.

Moving on to code review. 🔍

中文说明

P4a + P4b 合并 PR 的重新审查(上次 triage 仅覆盖 P4a;PR 已扩展到包含 P4b 并应用了 R7 修复)。

模板完整 ✓ — 所有必需章节齐全。"Real-LLM E2E" 替代 "Evidence (Before & After)" 合理;"Tested on" 和 "Risk & Scope" 充分。

方向:明确对齐。这是 Dynamic Workflows 移植的 P4,在已确立的 #4721 计划下,基于三个已合并阶段。上游 Claude Code CHANGELOG 有大量 workflow 历史 — /workflows 命令、workflow 验证修复、workflow agents、触发关键词 — 证实这是真实且活跃开发的能力。P4a(meta 提取)是 P4b 列表和 phase-tree UI 的前提;两者一起发布是正确的,因为 P4b 的显示依赖 P4a 的 WorkflowMeta 类型。

方案:合并范围(2931 行新增,26 个文件)较大但组织良好。P4a 添加 meta 提取基础设施(~500 行逻辑 + 测试)。P4b 添加第 4 个 registry 兄弟、/workflows 命令、pill/dialog/hook 集成、TaskKind 扩展 — 每项都遵循现有三个 registry 的既定模式。大部分新增是测试(core 232 + cli 116 = 348 总计)和镜像现有 MonitorDetailBody 模式的 UI 组件。未发现无关改动或顺手重构。ACP daemon 协议扩展展现确推迟到 P4c,边界正确。

进入代码审查 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Re-run on the combined P4a + P4b PR (commit 7b0ea82de, post-R7 fixes).

Code Review

Independent baseline before reading the diff: I'd extract meta from the export const meta declaration using the existing brace-walker, eval it in an isolated vm context, validate field-by-field, thread WorkflowMeta through the outcome/error types, create a 4th registry sibling mirroring the existing three, add a /workflows slash command mirroring /tasks, and widen TaskKind to include 'workflow' with exhaustive switch updates across the UI. The PR's approach matches this exactly.

Findings from the combined diff (26 files, ~3660 lines):

P4a — meta extraction (workflow-sandbox.ts)

  • findMetaBlockBounds extracted as a shared helper from stripExportMeta — clean refactor, zero behavior change for existing callers.
  • extractAndStripMeta evaluates the meta literal in vm.createContext(Object.create(null)) — null-prototyped globalThis, no host bridge. Security model is sound.
  • validateMeta walks field-by-field with upstream-aligned error messages. Necessarily verbose, no unnecessary abstraction.
  • rejectThenablesInMeta with WeakSet cycle guard closes the R3 dynamic import() crash vector and the R4 cyclic-meta stack overflow. Both verified non-vacuous by wenshao's mutation test and control experiments.
  • WorkflowExecutionError picks up a 4th constructor param with default null — non-breaking for existing 3-arg callers.

P4b — registry + UI (workflow-run-registry.ts, workflowsCommand.ts, BackgroundTasksDialog.tsx, etc.)

  • WorkflowRunRegistry follows the established sibling pattern: register/cancel/get/list/on('statusChange'), one-shot terminal transitions, eviction at MAX_RETAINED_TERMINAL_WORKFLOWS = 10.
  • R7 fixes are properly applied: setRecentLogs allows 'cancelled' state (dialog-cancel race), reset()/abortAll()/hasRunningEntries() wired into backgroundWorkUtils (session-reset + /clear), phase dedup moved to sandbox.
  • TaskKind widening from 3 → 4 ripples through every exhaustive kind switch — TypeScript enforces completeness. The _exhaustive: never check in BackgroundTaskViewContext.tsx confirms the new case 'workflow' is present.
  • WorkflowDetailBody mirrors MonitorDetailBody — same truncation patterns, same MaxSizedBox usage. Phase tree capped at 20, logs at 10.
  • /workflows command mirrors /tasks — same three-mode support (interactive/non_interactive/acp), same sort order (running first, terminal by endTime DESC).
  • cancelSelected in BackgroundTaskViewContext routes kind === 'workflow' to registry.cancel() correctly.

One pre-existing observation (not introduced by this PR): The interactive BackgroundTasksDialog list mode is unreachable from the keyboard — setPillFocused(true) has no non-test callers. This is a pre-existing infrastructure gap, not a regression. The text-based /workflows command provides identical data and works correctly. The tip text has been softened (R7 fix #4) to point at /workflows <runId> instead of advertising the unreachable pill path.

No critical blockers. No AGENTS.md violations. The code follows project conventions throughout — same registry patterns, same component structure, same test organization.

Test Results

$ cd packages/core && vitest run src/agents/workflow-run-registry.test.ts \
    src/agents/runtime/workflow-sandbox.test.ts \
    src/agents/runtime/workflow-orchestrator.test.ts \
    src/tools/workflow/workflow.test.ts

 ✓ src/tools/workflow/workflow.test.ts           (25 tests)  95ms
 ✓ src/agents/workflow-run-registry.test.ts       (19 tests)  14ms
 ✓ src/agents/runtime/workflow-orchestrator.test.ts (81 tests) 425ms
 ✓ src/agents/runtime/workflow-sandbox.test.ts    (107 tests) 30506ms

 Test Files  4 passed (4)
      Tests  232 passed (232)
   Duration  33.77s
$ cd packages/cli && vitest run src/ui/commands/workflowsCommand.test.ts \
    src/ui/components/background-view/BackgroundTasksPill.test.tsx \
    src/ui/components/background-view/BackgroundTasksDialog.test.tsx \
    src/ui/hooks/useBackgroundTaskView.test.ts \
    src/ui/utils/backgroundWorkUtils.test.ts \
    src/services/BuiltinCommandLoader.test.ts \
    src/ui/commands/clearCommand.test.ts \
    src/ui/hooks/useResumeCommand.test.ts

 ✓ src/ui/hooks/useBackgroundTaskView.test.ts          (16 tests)  92ms
 ✓ src/ui/commands/clearCommand.test.ts                (15 tests)  58ms
 ✓ src/ui/hooks/useResumeCommand.test.ts                (9 tests)  73ms
 ✓ src/ui/components/background-view/BackgroundTasksDialog.test.tsx (32 tests) 937ms
 ✓ src/ui/commands/workflowsCommand.test.ts             (6 tests)  18ms
 ✓ src/services/BuiltinCommandLoader.test.ts           (11 tests)  21ms
 ✓ src/ui/components/background-view/BackgroundTasksPill.test.tsx (19 tests)   9ms
 ✓ src/ui/utils/backgroundWorkUtils.test.ts             (8 tests)   6ms

 Test Files  8 passed (8)
      Tests  116 passed (116)
   Duration  16.87s
$ tsc --noEmit (core + cli)
# clean — 0 errors
$ npm run build
# 0 errors, 15 pre-existing warnings

Real-Scenario Testing (tmux)

Deterministic paths verified on the built bundle (dist/cli.js, qwen v0.18.0):

Without QWEN_CODE_ENABLE_WORKFLOWS (gate off)

> /work
  openwork-desktop-sync [Project]  Sync qwen-code packages/desktop with...
  # → /workflows NOT in autocomplete ✓

> /workflows
  ✕ Unknown command: /workflows   ← gate works ✓

With QWEN_CODE_ENABLE_WORKFLOWS=1 (gate on)

> /work
  workflows [runId]   List active and completed workflow runs (text dump...)
  openwork-desktop-sync [Project]  Sync qwen-code packages/desktop with...
  # → /workflows appears in autocomplete ✓

> /workflows
  ● No workflow runs recorded yet.   ← empty state ✓

> /workflows wf_doesnotexist
  ✕ Unknown workflow runId: wf_doesnotexist   ← error path ✓

Live workflow lifecycle (running → completed/cancelled, pill counts, phase-tree JSON, /workflows listing with meta) was verified by maintainer wenshao on the real binary with qwen3.7-max — see the maintainer verification comment above for full tmux captures including running/completed/cancelled states, pill counts, and meta surfacing.

中文说明

代码审查

独立基线:用既有 brace-walker 提取 meta,在隔离 vm context 中求值,逐字段验证,穿透 WorkflowMeta 到 outcome/error 类型,创建第 4 个 registry 兄弟,添加 /workflows 斜杠命令镜像 /tasks,扩展 TaskKind 包含 'workflow' 并全面更新 switch。PR 方案完全匹配。

P4a — meta 提取findMetaBlockBounds 提取为共享 helper,extractAndStripMeta 在 null-prototype vm context 中求值,validateMeta 逐字段走,rejectThenablesInMeta + WeakSet 关闭 R3/R4 崩溃向量。安全模型合理。

P4b — registry + UIWorkflowRunRegistry 遵循既有兄弟模式。R7 修复正确应用(setRecentLogs 允许 'cancelled'reset()/abortAll()/hasRunningEntries() 接入 backgroundWorkUtils、phase 去重移到 sandbox)。TaskKind 扩展 TypeScript 强制穷举。WorkflowDetailBody 镜像 MonitorDetailBody

先存观察(非本 PR 引入):交互式对话框的 pill 聚焦路径不可达 — setPillFocused(true) 无非测试调用方。文本版 /workflows 提供相同数据且正常工作。提示语已弱化指向 /workflows <runId>

无关键 blocker。无 AGENTS.md 违规。

测试结果

348/348 通过(core 232 + cli 116),tsc --noEmit 干净,build 0 error。

tmux 真实场景测试

确定性路径验证:门控关闭时 /workflows 不可见且被拒绝;门控开启时 autocomplete 显示、空状态、错误路径均正常。实时生命周期由维护者 wenshao 在真实二进制上验证。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Re-run on the combined P4a + P4b PR (commit 7b0ea82de).

Going back to my independent baseline: the PR's implementation matches what I'd have done — extract meta via the existing brace-walker into a null-prototyped vm context, validate field-by-field, create a 4th registry sibling, add a /workflows command mirroring /tasks, widen TaskKind with exhaustive switches. No simpler path was missed.

This solves a real need. Before P4, workflows ran invisibly — no pill count, no dialog row, no way to see what was running. P4a extracts the export const meta declaration so users can identify workflows without re-reading script source; P4b pipes orchestrator runs through the same background-task envelope that agents/shells/monitors already use. The result is that workflows become first-class citizens in the TUI.

The code is straightforward. Each piece follows established patterns — the registry mirrors its three siblings, the UI components mirror MonitorDetailBody, the slash command mirrors /tasks. No over-abstraction, no speculative features. The security boundary (null-prototyped vm context for meta eval, tests verifying process/require/args are unreachable) is solid and well-reasoned.

348 tests pass, typecheck and build are clean, tmux confirms the deterministic paths (gate on/off, empty state, error path). The live workflow lifecycle was verified by maintainer wenshao on the real binary with extensive tmux captures.

The one non-blocking observation — the interactive dialog's pill focus path is unreachable from the keyboard — is a pre-existing infrastructure gap, not introduced by this PR. The tip text has been appropriately softened, and the text-based /workflows command provides full coverage.

R7 review findings (6 items) are all properly addressed with regression tests, including RED→GREEN verification. The CI fix for mock stubs in clearCommand/useResumeCommand tests shows attention to cross-file ripple.

Approving.

中文说明

最终判定

回到独立基线:PR 的实现跟我设想的完全一致 — 用既有 brace-walker 在 null-prototype vm context 中提取 meta,逐字段验证,创建第 4 个 registry 兄弟,添加 /workflows 命令镜像 /tasks,扩展 TaskKind 配穷举 switch。没有更简路径被遗漏。

这解决了真实需求。P4 之前,workflow 运行对用户不可见。P4a 提取 meta 让用户能识别 workflow;P4b 把 orchestrator 运行接入既有的 background-task 框架。结果是 workflow 成为 TUI 中的一等公民。

代码直接,每部分遵循既有模式。无过度抽象、无投机性功能。安全边界扎实。348 测试通过,typecheck 和 build 干净,tmux 确认确定性路径。维护者 wenshao 在真实二进制上验证了实时生命周期。

唯一的非阻塞观察 — 对话框 pill 聚焦路径不可达 — 是先存基础设施缺口,非本 PR 引入。提示语已适当弱化,文本版 /workflows 提供完整覆盖。

批准。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

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 implements P4a of the Dynamic Workflows port by extracting the leading export const meta = {...} block from workflow scripts, validating it into a typed WorkflowMeta, and threading that metadata through the workflow run outcome/error so UIs (and future /workflows) can display workflow name/description/phases without re-parsing source.

Changes:

  • Add extractAndStripMeta() + WorkflowMeta to workflow-sandbox.ts, and expose extracted meta via WorkflowSandbox.getMeta().
  • Surface meta on WorkflowRunOutcome.meta and WorkflowExecutionError.meta, and include it in WorkflowTool returnDisplay payloads (success + failure paths).
  • Add/extend unit/integration tests covering meta extraction, propagation, and display payload shape.

Reviewed changes

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

Show a summary per file
File Description
packages/core/src/agents/runtime/workflow-sandbox.ts Adds meta bounds-finding helper, meta extraction/eval/validation, and getMeta() plumbing.
packages/core/src/agents/runtime/workflow-sandbox.test.ts Adds tests for extraction/validation/security properties + getMeta() behavior.
packages/core/src/agents/runtime/workflow-orchestrator.ts Threads WorkflowMeta through outcome + execution error for success/failure visibility.
packages/core/src/agents/runtime/workflow-orchestrator.test.ts Adds orchestrator tests asserting outcome.meta and WorkflowExecutionError.meta.
packages/core/src/tools/workflow/workflow.ts Includes meta in tool display payloads (omitted when absent) on both success and failure.
packages/core/src/tools/workflow/workflow.test.ts Adds tool-level tests for meta presence/omission in returnDisplay and failure-path inclusion.

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

Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts
Comment thread packages/core/src/agents/runtime/workflow-sandbox.test.ts Outdated
Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts
Comment thread packages/core/src/agents/runtime/workflow-orchestrator.ts
@github-actions

github-actions Bot commented Jun 14, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 76.34% 76.34% 80.1% 79.68%
Core 82.34% 82.34% 84.04% 84.03%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   76.34 |    79.68 |    80.1 |   76.34 |                   
 src               |    71.2 |     68.3 |   73.91 |    71.2 |                   
  gemini.tsx       |   63.74 |    65.83 |   71.42 |   63.74 | ...1170-1174,1213 
  ...ractiveCli.ts |   70.34 |    64.53 |   66.66 |   70.34 | ...1609-1611,1646 
  ...liCommands.ts |   84.88 |    77.92 |     100 |   84.88 | ...41,367,401,493 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   56.56 |    61.22 |   82.75 |   56.56 |                   
  acpAgent.ts      |   56.41 |    61.24 |   82.94 |   56.41 | ...7033,7058-7073 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   68.65 |    83.33 |   66.66 |   68.65 |                   
  filesystem.ts    |   68.65 |    83.33 |   66.66 |   68.65 | ...32,77-94,97-98 
 ...ration/session |   79.97 |    73.68 |   86.11 |   79.97 |                   
  ...ryReplayer.ts |   67.34 |     75.6 |   81.81 |   67.34 | ...54-269,282-283 
  Session.ts       |   79.58 |    72.81 |   86.66 |   79.58 | ...3993,4019-4023 
  ...entTracker.ts |    90.8 |    84.37 |   88.88 |    90.8 | ...30,194,252-261 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   84.21 |    78.57 |     100 |   84.21 | ...37-153,209-211 
  tasksSnapshot.ts |   94.06 |    86.66 |     100 |   94.06 | 60-66             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ssion/emitters |   95.85 |    93.41 |   96.96 |   95.85 |                   
  BaseEmitter.ts   |   84.61 |       70 |     100 |   84.61 | 23-24,39-40       
  ...ageEmitter.ts |   95.23 |    95.12 |     100 |   95.23 | 48-55             
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   98.44 |    94.38 |     100 |   98.44 | 318-319,420,428   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |    91.3 |    88.09 |   94.44 |    91.3 |                   
  LlmRewriter.ts   |      81 |       84 |     100 |      81 | ...,88-89,155-159 
  ...Middleware.ts |   96.74 |    86.84 |     100 |   96.74 | 135,143-145       
  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      |   58.87 |    86.66 |   47.82 |   58.87 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
  serve.ts         |   46.56 |      100 |   33.33 |   46.56 | 29-31,252-453     
 ...mmands/channel |    39.2 |    79.45 |      50 |    39.2 |                   
  ...l-registry.ts |    8.33 |      100 |       0 |    8.33 | 6-22,25-43        
  config-utils.ts  |      92 |      100 |   66.66 |      92 | 21-26             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   30.98 |       52 |   69.23 |   30.98 | ...72-475,484-486 
  status.ts        |   17.85 |      100 |       0 |   17.85 | 15-26,32-76       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   85.44 |    89.39 |   81.81 |   85.44 |                   
  consent.ts       |   72.68 |       90 |   42.85 |   72.68 | ...86-142,157-163 
  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         |   67.77 |    38.88 |     100 |   67.77 | ...,94-98,100-104 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...amples/starter |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-64              
 src/commands/mcp  |   90.28 |    88.88 |   83.33 |   90.28 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 293               
  approve.ts       |   76.19 |     87.5 |   66.66 |   76.19 | ...,89-99,114-124 
  list.ts          |   92.48 |    86.66 |      80 |   92.48 | ...60-162,178-179 
  reconnect.ts     |   77.71 |    78.57 |   85.71 |   77.71 | 40-53,160-182     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   11.57 |      100 |       0 |   11.57 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   11.32 |      100 |       0 |   11.32 | ...41-153,155-156 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 src/config        |   91.38 |    85.57 |    91.6 |   91.38 |                   
  auth.ts          |   86.74 |    80.88 |     100 |   86.74 | ...40-241,257-258 
  ...eMcpImport.ts |   87.88 |    81.52 |     100 |   87.88 | ...57-365,447-448 
  config.ts        |   87.16 |    84.52 |   82.14 |   87.16 | ...2034,2036-2044 
  keyBindings.ts   |   96.87 |       50 |     100 |   96.87 | 201-204           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  mcpApprovals.ts  |   96.12 |    94.87 |     100 |   96.12 | 193-194,199-201   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  settings.ts      |   79.18 |    86.71 |    87.8 |   79.18 | ...1550,1565-1568 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.22 |    94.33 |     100 |   96.22 | ...95-197,212-213 
 ...nfig/migration |   94.89 |    78.94 |   83.33 |   94.89 |                   
  index.ts         |   94.87 |    88.88 |     100 |   94.87 | 91-92             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.74 |    96.06 |     100 |   94.74 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.56 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   69.39 |    66.66 |   63.15 |   69.39 |                   
  ...tputBridge.ts |   69.48 |     67.3 |    64.7 |   69.48 | ...82-383,391-394 
  ...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          |   82.47 |    75.94 |   65.71 |   82.47 |                   
  index.ts         |   63.68 |    69.56 |   53.84 |   63.68 | ...70-271,281-286 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,184   
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |   72.45 |    71.03 |   74.07 |   72.45 |                   
  session.ts       |   76.46 |    69.34 |   85.71 |   76.46 | ...32-833,842-852 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...90-591,594-595 
 ...active/control |   76.29 |    88.23 |      80 |   76.29 |                   
  ...rolContext.ts |    6.89 |        0 |       0 |    6.89 | 50-86             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...49-367,383,386 
  ...rolService.ts |     7.4 |        0 |       0 |     7.4 | 46-185            
 ...ol/controllers |    25.4 |    35.71 |   35.48 |    25.4 |                   
  ...Controller.ts |   36.97 |       80 |      80 |   36.97 | ...15-117,127-210 
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   28.33 |    34.48 |      40 |   28.33 | ...64-573,588-593 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |   21.97 |    28.57 |   27.27 |   21.97 | ...39-451,460-489 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.01 |    93.77 |   95.23 |   98.01 |                   
  ...putAdapter.ts |   97.89 |    92.82 |   98.07 |   97.89 | ...1303,1398-1399 
  ...putAdapter.ts |      96 |     90.9 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 83-84,124-125     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |    78.4 |    81.87 |   78.18 |    78.4 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.26 |    92.64 |     100 |   93.26 | ...07-308,311-313 
  ...temAdapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    95.45 |     100 |     100 | 341               
  daemonLogger.ts  |   98.63 |    90.32 |   95.83 |   98.63 | 161,165           
  ...usProvider.ts |   67.01 |    51.42 |     100 |   67.01 | ...40-245,278-286 
  debugMode.ts     |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  envSnapshot.ts   |   92.75 |       84 |     100 |   92.75 | 110-113,179-186   
  eventBus.ts      |     100 |      100 |     100 |     100 |                   
  ...oryChannel.ts |       0 |        0 |       0 |       0 | 1-14              
  index.ts         |       0 |        0 |       0 |       0 | 1-143             
  loopbackBinds.ts |     100 |      100 |     100 |     100 |                   
  ...ssionAudit.ts |     100 |      100 |   93.33 |     100 |                   
  rateLimit.ts     |   90.37 |    87.77 |   93.75 |   90.37 | ...95-297,348-352 
  runQwenServe.ts  |   68.33 |    83.54 |      32 |   68.33 | ...1373,1376-1383 
  server.ts        |   80.17 |    83.11 |   83.33 |   80.17 | ...4601,4667-4676 
  status.ts        |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...paceAgents.ts |   62.47 |    70.34 |   90.47 |   62.47 | ...1346,1356-1366 
  ...paceMemory.ts |   87.13 |    78.46 |     100 |   87.13 | ...54-361,421-428 
 src/serve/acpHttp |   65.38 |    67.03 |    93.4 |   65.38 |                   
  ...onRegistry.ts |    86.3 |    77.19 |   92.59 |    86.3 | ...34-338,409-423 
  dispatch.ts      |   56.25 |    58.89 |     100 |   56.25 | ...2469,2543-2546 
  index.ts         |   75.63 |    68.21 |    90.9 |   75.63 | ...31,734,760-762 
  jsonRpc.ts       |     100 |    96.96 |     100 |     100 | 92                
  sseStream.ts     |   93.85 |    87.87 |   84.61 |   93.85 | ...48-150,152-154 
  ...portStream.ts |       0 |        0 |       0 |       0 | 1                 
  wsStream.ts      |   91.76 |       80 |     100 |   91.76 | 43,48,91,95-98    
 src/serve/auth    |   86.86 |    79.18 |   93.87 |   86.86 |                   
  deviceFlow.ts    |   96.35 |       80 |   97.61 |   96.35 | ...1358,1453,1519 
  ...owProvider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 src/serve/fs      |   85.12 |    81.01 |     100 |   85.12 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 201               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.82 |    77.08 |     100 |   77.82 | ...64,493-497,510 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...FileSystem.ts |   84.03 |    78.55 |     100 |   84.03 | ...2031,2058-2059 
 src/serve/routes  |   75.89 |    76.51 |   94.28 |   75.89 |                   
  a2uiAction.ts    |     100 |    93.65 |     100 |     100 | 114-118,163,267   
  ...ceFileRead.ts |   94.41 |    76.92 |     100 |   94.41 | ...28-329,390-392 
  ...eFileWrite.ts |    82.1 |    60.52 |     100 |    82.1 | ...42-244,247-249 
  ...ceSettings.ts |   23.62 |      100 |      50 |   23.62 | ...10-223,230-327 
 ...kspace-service |   81.05 |     82.4 |   86.66 |   81.05 |                   
  index.ts         |   81.23 |    83.17 |   92.85 |   81.23 | ...92-497,557-622 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/services      |   91.95 |    90.65 |   97.56 |   91.95 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 97-110            
  ...killLoader.ts |     100 |    93.33 |     100 |     100 | 48,67             
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.84 |    80.64 |   83.33 |   75.84 | ...10-211,277-278 
  ...mandLoader.ts |     100 |    97.14 |     100 |     100 | 66                
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.21 |    96.66 |     100 |   98.21 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |    88.3 |    85.49 |   92.59 |    88.3 |                   
  DataProcessor.ts |   88.22 |    85.48 |      95 |   88.22 | ...1341,1345-1352 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...teRenderer.ts |   45.45 |      100 |       0 |   45.45 | 13-51             
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.35 |    84.84 |     100 |   97.35 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   66.82 |    78.94 |   66.66 |   66.82 |                   
  ...reeStartup.ts |   66.82 |    78.94 |   66.66 |   66.82 | ...08-312,363-426 
 src/test-utils    |   93.71 |    83.33 |      80 |   93.71 |                   
  ...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            |   69.74 |       75 |   60.31 |   69.74 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   70.12 |    68.63 |   52.63 |   70.12 | ...3251,3255-3259 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...inePresets.ts |   98.28 |    89.87 |     100 |   98.28 | ...34,261,420-422 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   59.16 |    65.94 |   51.11 |   59.16 |                   
  AuthDialog.tsx   |   62.87 |     42.1 |   18.18 |   62.87 | ...03,310-332,336 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.03 |    70.37 |      56 |   60.03 | ...87,791,800,803 
  useAuth.ts       |   94.55 |    73.52 |     100 |   94.55 | ...19-220,239-245 
  ...rSetupFlow.ts |   43.52 |    33.33 |      50 |   43.52 | ...72-393,410-453 
 src/ui/commands   |   77.13 |    81.53 |   85.43 |   77.13 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.47 |    81.25 |     100 |   89.47 | 92-93,95-100      
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...90-595,680-688 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    77.41 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |   89.44 |    80.35 |     100 |   89.44 | ...81,106-111,190 
  clearCommand.ts  |   79.64 |       68 |     100 |   79.64 | ...24-125,133-142 
  ...essCommand.ts |   67.95 |    55.88 |      75 |   67.95 | ...86-187,201-204 
  ...astCommand.ts |   70.86 |    74.07 |      75 |   70.86 | ...,61-93,117-122 
  ...extCommand.ts |   65.35 |     66.1 |   84.61 |   65.35 | ...42-575,586-587 
  copyCommand.ts   |   98.49 |    95.78 |     100 |   98.49 | ...80,280,321,327 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |     87.5 |     100 |     100 | ...61,224-225,238 
  ...ryCommand.tsx |   81.84 |    86.11 |   91.66 |   81.84 | ...66-271,318-325 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   61.27 |    87.06 |    87.5 |   61.27 | ...71-372,445-665 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   51.54 |    48.14 |   69.23 |   51.54 | ...97,251-303,364 
  forgetCommand.ts |     100 |       90 |     100 |     100 | 59                
  forkCommand.ts   |     100 |    94.11 |     100 |     100 | 96,147            
  goalCommand.ts   |   91.46 |    84.44 |      90 |   91.46 | ...87-190,202-205 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.13 |    65.71 |   85.71 |   81.13 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  ...figCommand.ts |   52.83 |    81.25 |      70 |   52.83 | ...74-319,321-330 
  initCommand.ts   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   92.17 |    82.69 |     100 |   92.17 | ...39,159,168-178 
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   75.09 |    78.18 |      75 |   75.09 | ...20-225,262-267 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...berCommand.ts |      96 |       70 |     100 |      96 | 57,62             
  renameCommand.ts |   85.71 |    86.04 |     100 |   85.71 | ...02-209,216-221 
  ...oreCommand.ts |   90.47 |    84.61 |     100 |   90.47 | ...32-137,167-168 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |    85.5 |    81.25 |     100 |    85.5 | 36-44,70          
  statsCommand.ts  |   91.48 |    89.47 |     100 |   91.48 | 40-43,134-141     
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.46 |      100 |      50 |    6.46 | 31-329            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  ...owsCommand.ts |   88.66 |    82.92 |      60 |   88.66 | ...,92-93,102-107 
 src/ui/components |   62.65 |    77.66 |   60.51 |   62.65 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |    88.7 |       75 |     100 |    88.7 | 36,38-43,45       
  ...odeDialog.tsx |   87.24 |    72.22 |   33.33 |   87.24 | ...85,233-238,245 
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   16.27 |      100 |       0 |   16.27 | 19-58             
  ...TextInput.tsx |   77.01 |       76 |     100 |   77.01 | ...20,234-236,263 
  Composer.tsx     |    81.6 |     64.7 |     100 |    81.6 | ...90,108,160,173 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.86 |      100 |       0 |   11.86 | 69-550            
  DiffDialog.tsx   |    2.47 |      100 |       0 |    2.47 | 68-732            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   78.12 |    51.16 |     100 |   78.12 | ...43,176,198-203 
  ...ngSpinner.tsx |   68.42 |       80 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   76.19 |    81.81 |     100 |   76.19 | 24-30,46-50       
  Header.tsx       |   98.62 |    94.28 |     100 |   98.62 | 162,164           
  Help.tsx         |   98.32 |       90 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |   65.77 |    55.55 |     100 |   65.77 | ...71,374,377-383 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |    83.1 |    78.07 |   83.33 |    83.1 | ...1652,1667,1717 
  ...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  |   87.11 |    88.31 |   66.66 |   87.11 | ...26,284,343-347 
  MemoryDialog.tsx |   61.87 |    76.05 |    62.5 |   61.87 | ...72,391,428-430 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   85.19 |    69.17 |     100 |   85.19 | ...80-596,653-657 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   92.42 |    84.37 |     100 |   92.42 | ...,70-71,143-145 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   66.31 |    71.16 |      75 |   66.31 | ...16-824,830-831 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...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            
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.85 |      100 |       0 |    8.85 | ...5,49-84,92-238 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    3.28 |      100 |       0 |    3.28 | 25-258            
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |    5.46 |      100 |       0 |    5.46 | 24-215            
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.33 |    88.23 |     100 |   96.33 | 137-140           
  ...nsDisplay.tsx |   87.25 |       64 |     100 |   87.25 | ...57-159,166-168 
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   91.42 |    64.28 |     100 |   91.42 | 15,21,24          
  ...s-helpers.tsx |      25 |      100 |       0 |      25 | ...3,86-89,94-102 
 ...nts/agent-view |   38.22 |    78.82 |   41.66 |   38.22 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   10.84 |      100 |       0 |   10.84 | 59-308            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |   87.39 |    62.85 |     100 |   87.39 | ...,85,98-106,124 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.59 |    70.53 |   60.86 |   45.59 |                   
  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 |    9.92 |      100 |       0 |    9.92 | 27-164            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   72.67 |    82.52 |   86.84 |   72.67 |                   
  ...sksDialog.tsx |   67.69 |    80.48 |   78.26 |   67.69 | ...1411,1473-1475 
  ...TasksPill.tsx |   67.03 |     86.2 |     100 |   67.03 | ...02-122,130-138 
  ...gentPanel.tsx |    97.4 |    85.39 |     100 |    97.4 | 120,433-437       
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.88 |    94.23 |   66.66 |   54.88 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 20-131            
  ...nListStep.tsx |   88.43 |    94.73 |      80 |   88.43 | 52-53,59-72,106   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   86.85 |    81.37 |   91.89 |   86.85 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   21.66 |    89.36 |   76.92 |   21.66 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |    3.66 |      100 |       0 |    3.66 | 41-712            
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-30              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |     92.1 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   26.36 |    54.54 |   42.85 |   26.36 |                   
  ...icateStep.tsx |    5.67 |      100 |       0 |    5.67 | 40-66,69-307      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.15 |      100 |       0 |    5.15 | 31-251            
  ...rListStep.tsx |   75.18 |    59.37 |     100 |   75.18 | ...53-158,169-173 
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |   69.02 |       50 |     100 |   69.02 | ...22,125,134-143 
 ...nents/messages |   82.43 |    79.86 |    75.6 |   82.43 |                   
  ...ionDialog.tsx |   80.84 |     77.6 |    62.5 |   80.84 | ...98,516,534-536 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.72 |     100 |   97.67 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   70.56 |    77.77 |      70 |   70.56 | ...07-320,324-336 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...tsDisplay.tsx |    95.1 |    88.05 |     100 |    95.1 | ...29,131,164-169 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   55.67 |       40 |   28.57 |   55.67 | ...20-125,133-145 
  ...ryMessage.tsx |   14.28 |      100 |       0 |   14.28 | 23-62             
  ...onMessage.tsx |   82.15 |    73.33 |   33.33 |   82.15 | ...65-467,474-476 
  ...upMessage.tsx |   82.63 |    92.85 |     100 |   82.63 | ...85-412,434-449 
  ToolMessage.tsx  |    87.8 |    73.28 |    92.3 |    87.8 | ...59-764,791-793 
 ...ponents/shared |   84.43 |    80.54 |    95.5 |   84.43 |                   
  ...ctionList.tsx |   99.14 |       96 |     100 |   99.14 | 99                
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   83.01 |    86.25 |   88.88 |   83.01 | ...12-513,618-619 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   76.25 |       80 |     100 |   76.25 | 44-58,65-68       
  StaticRender.tsx |   72.72 |      100 |     100 |   72.72 | 31-33             
  TextInput.tsx    |    80.8 |    66.07 |      80 |    80.8 | ...36-240,252-258 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   84.26 |    80.88 |      90 |   84.26 | ...68-696,743-765 
  text-buffer.ts   |   85.94 |    81.18 |   97.91 |   85.94 | ...2651,2749-2750 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |    3.61 |      100 |       0 |    3.61 |                   
  ...gerDialog.tsx |    3.61 |      100 |       0 |    3.61 | ...90-148,151-694 
 ...ents/subagents |   30.87 |        0 |       0 |   30.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   10.95 |      100 |       0 |   10.95 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |   21.51 |    59.52 |   27.27 |   21.51 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   70.21 |    67.32 |    64.7 |   70.21 |                   
  ContextUsage.tsx |   70.88 |    63.88 |      80 |   70.88 | ...20-426,463-557 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   77.47 |    77.77 |   81.03 |   77.47 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   92.45 |    62.79 |      50 |   92.45 | ...69-270,272-276 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   81.67 |     81.6 |     100 |   81.67 | ...1199,1203-1205 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   43.26 |     62.5 |    62.5 |   43.26 | ...64-267,276-279 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 134-135           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 203-204           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
 src/ui/daemon     |   90.76 |    73.73 |   95.45 |   90.76 |                   
  ...TuiAdapter.ts |   90.76 |    73.73 |   95.45 |   90.76 | ...53,771-772,858 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |   81.63 |     80.9 |    86.4 |   81.63 |                   
  ...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 |   83.94 |    62.56 |      80 |   83.94 | ...1010,1031-1035 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   91.79 |    86.88 |     100 |   91.79 | ...05-206,243-246 
  ...ifications.ts |   86.91 |    96.29 |     100 |   86.91 | 116-130           
  ...tIndicator.ts |   83.49 |    70.96 |     100 |   83.49 | ...60,168,170-178 
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   93.84 |    74.46 |     100 |   93.84 | ...25-129,218,224 
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   92.53 |    71.42 |     100 |   92.53 | ...32,172,245-248 
  ...ompletion.tsx |   96.01 |    83.87 |     100 |   96.01 | ...22-223,225-226 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   77.27 |       50 |     100 |   77.27 | ...2,75-79,93-101 
  ...eteCommand.ts |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...ialogClose.ts |    12.5 |      100 |     100 |    12.5 | 85-181            
  useDiffData.ts   |   11.62 |      100 |       0 |   11.62 | 44-87             
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |    63.9 |    76.47 |   66.66 |    63.9 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   89.15 |     62.5 |      50 |   89.15 | ...22-124,149-150 
  ...miniStream.ts |      79 |    76.85 |    92.3 |      79 | ...2689,2737-2745 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   97.43 |    98.18 |     100 |   97.43 | 52,139-142        
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   63.15 |       75 |      50 |   63.15 | 42-52,64-67       
  ...cpApproval.ts |   92.37 |    83.33 |     100 |   92.37 | ...00-103,115-116 
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |   83.14 |    78.57 |     100 |   83.14 | 54-63,74-79       
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...ouseEvents.ts |   87.17 |    88.88 |   66.66 |   87.17 | 81-82,86-88       
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derUpdates.ts |   86.49 |    77.96 |    90.9 |   86.49 | ...26,288-300,348 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |    84.7 |    93.33 |     100 |    84.7 | ...71-276,372-382 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...tleRepaint.ts |     100 |      100 |     100 |     100 |                   
  ...umeCommand.ts |   96.96 |    83.33 |     100 |   96.96 | 101-102,131       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   97.05 |    96.07 |     100 |   97.05 | ...90-191,245-248 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.73 |    85.41 |   94.73 |   82.73 | ...70-672,680-716 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |    96.3 |    92.19 |     100 |    96.3 | ...77-380,466-473 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 44-45,87          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    90.9 |    90.62 |     100 |    90.9 |                   
  ...AppLayout.tsx |   90.72 |       90 |     100 |   90.72 | 57-59,101-106     
  ...AppLayout.tsx |   91.17 |    91.66 |     100 |   91.17 | 70-75             
 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.39 |    72.83 |     100 |   98.39 |                   
  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   |   97.91 |       92 |     100 |   97.91 | ...51-352,354-355 
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   87.98 |    82.89 |     100 |   87.98 | ...48-357,362-363 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   83.34 |    82.83 |   92.79 |   83.34 |                   
  ...Colorizer.tsx |   79.53 |    83.78 |     100 |   79.53 | ...51-152,249-275 
  ...nRenderer.tsx |   68.83 |    70.14 |      50 |   68.83 | ...52-254,274-293 
  ...wnDisplay.tsx |   86.01 |    87.66 |     100 |   86.01 | ...87,704,729-754 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.08 |    80.45 |      95 |   92.08 | ...76-679,723-728 
  ...odeDisplay.ts |   96.55 |     90.9 |     100 |   96.55 | 34                
  asciiCharts.ts   |   96.77 |    87.62 |     100 |   96.77 | 173-180,281       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   51.92 |    72.72 |   91.66 |   51.92 | ...21,624-633,636 
  commandUtils.ts  |      96 |    88.77 |     100 |      96 | ...72,174-175,302 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   88.37 |    72.22 |     100 |   88.37 | 23,25,29,31,33    
  formatters.ts    |   95.23 |    98.33 |     100 |   95.23 | 117-120           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    96.77 |     100 |     100 | 43                
  historyUtils.ts  |   94.11 |       94 |     100 |   94.11 | 94-97             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |    89.47 |     100 |     100 | 81,110            
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |   98.66 |    96.77 |     100 |   98.66 | 48-49             
  ...geRenderer.ts |   86.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   90.71 |    73.33 |   88.88 |   90.71 | ...40-143,200-201 
  osc8.ts          |   94.73 |    87.75 |     100 |   94.73 | ...49,434,438-439 
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |   99.02 |    97.14 |     100 |   99.02 | 106               
  ...storyUtils.ts |   62.74 |    71.26 |      90 |   62.74 | ...84,432,437-459 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.61 |    94.84 |   92.85 |   97.61 | ...50-251,386-387 
  todoSnapshot.ts  |   89.33 |    93.47 |     100 |   89.33 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |      57 |     40.8 |   79.41 |      57 |                   
  collect.ts       |   55.92 |    50.58 |   86.36 |   55.92 | ...25-640,642-647 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   58.11 |    20.51 |      80 |   58.11 | ...13-314,328-363 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   71.99 |    89.12 |   90.43 |   71.99 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.72 |    97.14 |     100 |   96.72 | 165-168           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   90.51 |    91.89 |     100 |   90.51 | 67-76,116         
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.38 |    71.83 |   88.88 |   70.38 | ...27,430-431,438 
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   97.14 |    96.42 |     100 |   97.14 | 125-126           
  errors.ts        |   90.85 |    96.36 |    92.3 |   90.85 | 69-70,298-310     
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |    92.2 |    95.23 |   88.88 |    92.2 | 130-141           
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   89.17 |    92.77 |     100 |   89.17 | ...55,272-273,318 
  languageUtils.ts |   98.19 |    96.87 |     100 |   98.19 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.37 |    93.07 |     100 |   96.37 | ...15-416,514,527 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   93.22 |    81.25 |     100 |   93.22 | 65-67,80          
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-1054            
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.51 |    91.79 |   89.74 |   82.51 | ...76-694,701-709 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   26.82 |    73.77 |   43.47 |   26.82 | ...36-837,840-859 
  ...upProfiler.ts |   98.46 |    94.52 |     100 |   98.46 | 130-131,305       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   95.12 |    89.06 |     100 |   95.12 | ...43-244,249-253 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  ...alSequence.ts |     100 |    95.23 |     100 |     100 | 60,90             
  ...iffPreview.ts |   94.11 |    83.33 |     100 |   94.11 | 13                
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |    62.1 |       75 |     100 |    62.1 | 93,107,118-157    
 ...s/housekeeping |   90.15 |     89.7 |   94.11 |   90.15 |                   
  cleanup.ts       |   94.33 |       95 |     100 |   94.33 | 60-62             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   89.71 |    88.23 |   85.71 |   89.71 | 51-55,66,116-120  
  throttledOnce.ts |   86.66 |    85.18 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   82.34 |    84.03 |   84.04 |   82.34 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   88.97 |    80.46 |   94.11 |   88.97 |                   
  ...transcript.ts |   92.25 |    85.71 |     100 |   92.25 | ...01,320-321,452 
  ...ent-resume.ts |   83.08 |    69.86 |   78.12 |   83.08 | ...1120-1124,1127 
  ...ound-tasks.ts |   95.07 |    88.12 |     100 |   95.07 | ...1151,1171-1174 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...n-registry.ts |   94.51 |    85.48 |     100 |   94.51 | ...59-260,332-336 
 src/agents/arena  |   76.54 |    66.87 |   78.72 |   76.54 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.37 |    63.37 |   78.26 |   75.37 | ...1860,1866-1867 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   76.43 |    86.23 |   73.04 |   76.43 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.98 |     90.9 |   86.66 |   91.98 | ...95,250-270,329 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   85.94 |    84.49 |   77.57 |   85.94 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   77.48 |    73.56 |   65.21 |   77.48 | ...1713,1740-1787 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   84.48 |    78.04 |   63.63 |   84.48 | ...00-401,404-405 
  ...nteractive.ts |   80.55 |    81.35 |   74.07 |   80.55 | ...79,481,483,486 
  ...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 |                   
  ...chestrator.ts |   91.46 |     89.6 |      80 |   91.46 | ...1312,1361-1364 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...ow-sandbox.ts |   96.85 |    94.54 |     100 |   96.85 | ...24-325,330-331 
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   80.31 |    83.19 |    86.5 |   80.31 |                   
  TeamManager.ts   |   67.11 |    76.25 |   74.41 |   67.11 | ...1433,1456-1457 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   94.76 |    86.36 |   92.85 |   94.76 | 86-87,348-354     
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   88.85 |    82.47 |   96.29 |   88.85 | ...-990,1034-1035 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...37-141,148-152 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    93.38 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    77.77 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.08 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   78.65 |    83.67 |   64.15 |   78.65 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   77.04 |    82.83 |    60.5 |   77.04 | ...4915,4920-4921 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.24 |    91.13 |   88.09 |   94.24 | ...68-369,372-373 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   88.24 |    83.94 |   91.82 |   88.24 |                   
  baseLlmClient.ts |   81.74 |    77.52 |   77.77 |   81.74 | ...24,526-536,545 
  client.ts        |   87.71 |    81.49 |   89.83 |   87.71 | ...2584,2678-2679 
  ...tGenerator.ts |   84.86 |    69.23 |     100 |   84.86 | ...84,386,393-396 
  ...lScheduler.ts |   87.27 |    81.79 |   95.89 |   87.27 | ...4132,4160-4171 
  geminiChat.ts    |   89.04 |    87.24 |      95 |   89.04 | ...3253,3320-3321 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |    95.83 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   86.48 |    72.22 |     100 |   86.48 | ...97-198,212-221 
  ...issionFlow.ts |   98.78 |       96 |     100 |   98.78 | 93                
  prompts.ts       |   88.93 |    87.87 |   72.72 |   88.93 | ...-910,1113-1114 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...allIdUtils.ts |      98 |    91.42 |     100 |      98 | 31,40             
  ...okTriggers.ts |   99.43 |    91.34 |     100 |   99.43 | 172,183           
  turn.ts          |   96.35 |    88.67 |     100 |   96.35 | ...28,441-442,486 
 ...ntentGenerator |   94.88 |    82.07 |      94 |   94.88 |                   
  ...tGenerator.ts |   96.29 |    83.18 |   92.85 |   96.29 | ...1,971,999-1001 
  converter.ts     |   94.51 |    80.72 |     100 |   94.51 | ...06-607,617,823 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.53 |    71.64 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.96 |   92.85 |      90 | ...80-286,304-305 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   94.22 |    83.96 |   91.17 |   94.22 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   94.09 |     82.5 |   90.62 |   94.09 | ...1025-1026,1054 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   86.47 |    84.42 |   93.67 |   86.47 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   85.16 |    82.33 |   96.15 |   85.16 | ...1485,1654-1669 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   54.54 |    68.75 |      50 |   54.54 | ...79,87-91,95-99 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   94.38 |     86.5 |     100 |   94.38 | ...38-539,547,615 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |    90.2 |    87.65 |     100 |    90.2 | ...39-343,373-374 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.67 |    88.94 |   96.07 |   96.67 |                   
  dashscope.ts     |   97.37 |    91.39 |   93.33 |   97.37 | ...90-291,369-370 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   95.79 |    89.65 |   88.88 |   95.79 | 122-123,193-195   
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
 src/extension     |   62.64 |    79.47 |   80.31 |   62.64 |                   
  ...-converter.ts |   66.28 |    52.03 |     100 |   66.28 | ...98-799,808-840 
  ...ionManager.ts |   47.85 |    82.31 |    65.9 |   47.85 | ...1402,1412-1431 
  ...onSettings.ts |   93.46 |    93.05 |     100 |   93.46 | ...17-221,228-232 
  ...-converter.ts |   54.88 |    94.44 |      60 |   54.88 | ...35-146,158-192 
  github.ts        |   46.41 |     87.3 |   63.63 |   46.41 | ...66-372,411-464 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.31 |    93.75 |     100 |   97.31 | ...65,185-186,275 
  npm.ts           |   59.01 |    71.69 |    87.5 |   59.01 | ...23-425,432-436 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   75.82 |    71.49 |    90.9 |   75.82 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   96.29 |    88.88 |     100 |   96.29 | 78,108,122        
  speculation.ts   |   63.01 |    40.29 |   71.42 |   63.01 | ...73-574,577-582 
  ...onToolGate.ts |     100 |    96.55 |     100 |     100 | 95                
  ...nGenerator.ts |   70.23 |    74.57 |   83.33 |   70.23 | ...83-247,317-319 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   89.57 |    83.57 |   94.44 |   89.57 |                   
  ...eGoalStore.ts |    85.1 |    95.45 |   84.61 |    85.1 | ...63-166,174-182 
  goalHook.ts      |   97.26 |    91.66 |     100 |   97.26 | 100-105           
  goalJudge.ts     |   84.33 |    74.28 |     100 |   84.33 | ...57-358,366-368 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   86.88 |    85.58 |   88.01 |   86.88 |                   
  ...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.35 |    90.69 |     100 |   96.35 | ...00-301,382,384 
  ...entHandler.ts |   95.27 |    86.74 |   94.11 |   95.27 | ...63,920-921,931 
  hookPlanner.ts   |   86.29 |    83.33 |   85.71 |   86.29 | ...15-219,226-237 
  hookRegistry.ts  |   91.48 |    84.61 |     100 |   91.48 | ...97,416,420,424 
  hookRunner.ts    |   62.42 |    72.04 |   66.66 |   62.42 | ...64-765,774-775 
  hookSystem.ts    |   86.78 |      100 |   68.88 |   86.78 | ...07-708,714-715 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   96.37 |     90.9 |      90 |   96.37 | 342-350,424-425   
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   96.66 |    91.66 |     100 |   96.66 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   92.83 |       94 |    87.5 |   92.83 | ...87-488,573-577 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   75.55 |    83.52 |   78.33 |   75.55 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   66.14 |    81.75 |   66.66 |   66.14 | ...3-964,993-1001 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   42.42 |     51.9 |   52.14 |   42.42 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |   42.81 |    73.07 |      50 |   42.81 | ...76-427,433-450 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   25.31 |    62.06 |   41.66 |   25.31 | ...85-704,710-740 
  ...eLspClient.ts |   32.77 |       80 |   17.64 |   32.77 | ...84-288,294-295 
  ...LspService.ts |   51.85 |    65.98 |   68.57 |   51.85 | ...1339,1399-1409 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   79.21 |    76.52 |   76.36 |   79.21 |                   
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.64 |    97.77 |     100 |   98.64 | 88-89             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.72 |    87.05 |   86.36 |   79.72 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   83.44 |    84.21 |   92.85 |   83.44 | ...68-178,186-187 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   73.76 |    77.65 |   72.68 |   73.76 |                   
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |      66 |    73.33 |      50 |      66 | 51,108-149        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   63.77 |    79.16 |      50 |   63.77 | ...72-180,183-189 
  extract.ts       |   92.72 |    74.19 |     100 |   92.72 | ...32,151-154,211 
  ...entPlanner.ts |   67.59 |     73.8 |      50 |   67.59 | ...31,240-243,415 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |      46 |    61.53 |   44.44 |      46 | ...05,212,215-347 
  indexer.ts       |    86.3 |       50 |     100 |    86.3 | ...56,62-63,75-76 
  manager.ts       |    75.5 |    81.04 |    75.6 |    75.5 | ...1292,1305-1307 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   79.06 |    95.12 |     100 |   79.06 | 32-33,49-86       
  prompt.ts        |   94.87 |    78.57 |     100 |   94.87 | ...63,166,304-305 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  ...ceSelector.ts |   93.02 |    81.81 |     100 |   93.02 | ...24,126-127,135 
  scan.ts          |   92.92 |    78.26 |     100 |   92.92 | ...51-52,62,90-91 
  ...entPlanner.ts |   58.33 |    66.66 |   56.25 |   58.33 | ...61-282,358-403 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   93.33 |    81.25 |     100 |   93.33 | ...,94-95,119-120 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   79.38 |    78.33 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.98 |    87.37 |   88.15 |   89.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.24 |    91.42 |     100 |   90.24 | 142,148,151-160   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.66 |    92.85 |     100 |   98.66 | 162,324,330       
  modelRegistry.ts |     100 |    98.63 |     100 |     100 | 229               
  modelsConfig.ts  |   86.24 |    85.23 |   82.92 |   86.24 | ...1328,1357-1358 
  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   |   82.68 |    91.88 |   68.32 |   82.68 |                   
  autoMode.ts      |   97.84 |    94.27 |     100 |   97.84 | 523-524,545-552   
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |   93.95 |    94.44 |     100 |   93.95 | 158-165,383-387   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   84.86 |     89.1 |      80 |   84.86 | ...1024,1130-1134 
  rule-parser.ts   |   97.39 |    93.82 |     100 |   97.39 | ...-882,1031-1033 
  ...-semantics.ts |   70.28 |    90.69 |   46.21 |   70.28 | ...2214,2277-2280 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   99.04 |    95.23 |     100 |   99.04 |                   
  system-prompt.ts |   99.04 |    95.23 |     100 |   99.04 | 219               
 src/plan-gate     |    79.3 |    92.75 |   81.25 |    79.3 |                   
  ...viewAgents.ts |   56.02 |    88.46 |   66.66 |   56.02 | ...09-175,197-198 
  ...provalGate.ts |      95 |    95.12 |    87.5 |      95 | 164-165,252-258   
  state.ts         |     100 |      100 |     100 |     100 |                   
  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/providers     |   79.44 |    64.39 |   64.28 |   79.44 |                   
  all-providers.ts |      68 |      100 |       0 |      68 | 68-69,73-79,83-89 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   98.87 |    87.27 |     100 |   98.87 | 268-269           
  ...der-config.ts |   69.73 |    47.29 |   68.42 |   69.73 | ...10-411,418-427 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.31 |    86.36 |      50 |   97.31 |                   
  ...oding-plan.ts |   87.34 |      100 |       0 |   87.34 | 82-84,87-89,91-94 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.01 |    81.25 |      75 |   97.01 | 120-121           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |    85.3 |     78.8 |   95.89 |    85.3 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.55 |    73.71 |   90.62 |   82.55 | ...1183-1199,1229 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/services      |   87.28 |    84.26 |   93.72 |   87.28 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.35 |    85.34 |     100 |   97.35 | ...94,117,417-418 
  ...ionService.ts |   96.45 |    94.44 |     100 |   96.45 | ...34,650,779-787 
  ...ingService.ts |    84.2 |    81.92 |   83.33 |    84.2 | ...1438,1453-1454 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |     100 |    97.43 |     100 |     100 | 215,268           
  cronScheduler.ts |   94.18 |     88.6 |     100 |   94.18 | ...-774,1034-1035 
  cronTasksFile.ts |   95.18 |    85.71 |     100 |   95.18 | ...54-157,182-183 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   80.43 |    95.45 |      75 |   80.43 | ...19-134,140-141 
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   91.27 |    82.69 |    90.9 |   91.27 | ...94,196,294-301 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    69.4 |    68.82 |   93.33 |    69.4 | ...2064,2092-2093 
  ...ionService.ts |   98.86 |    98.09 |     100 |   98.86 | 368-369,416-417   
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   96.06 |    91.48 |   96.96 |   96.06 | ...49,850,864-866 
  ...orRegistry.ts |   97.26 |    91.22 |     100 |   97.26 | ...50-451,605-606 
  ...ttachments.ts |   97.24 |    90.39 |     100 |   97.24 | ...08,646,661-662 
  sessionRecap.ts  |     9.7 |      100 |       0 |     9.7 | 44-174            
  ...ionService.ts |   87.31 |    79.37 |   94.44 |   87.31 | ...1483,1553-1573 
  sessionTitle.ts  |   94.07 |    73.21 |     100 |   94.07 | ...51-254,285-286 
  ...ionService.ts |      83 |    79.17 |   90.47 |      83 | ...2103,2109-2114 
  ...pInhibitor.ts |   97.02 |    90.74 |     100 |   97.02 | ...14-115,289-290 
  ...Estimation.ts |     100 |    86.66 |     100 |     100 | 96-97             
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...oryService.ts |   89.03 |    65.38 |     100 |   89.03 | ...23-325,330-331 
  ...reeCleanup.ts |   14.56 |      100 |   33.33 |   14.56 | 58-185            
  ...ionService.ts |   84.21 |    79.41 |     100 |   84.21 | ...18-219,235-236 
 ...icrocompaction |   98.76 |    92.85 |     100 |   98.76 |                   
  microcompact.ts  |   98.76 |    92.85 |     100 |   98.76 | ...24,432,436,571 
 src/skills        |   88.14 |    86.62 |      90 |   88.14 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   83.39 |    81.42 |   82.35 |   83.39 | ...1199,1206-1210 
  skill-paths.ts   |   89.15 |    86.36 |     100 |   89.15 | ...00-101,106-107 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |       98 |     100 |   97.91 | 277-278           
 src/subagents     |   85.84 |    85.55 |   94.33 |   85.84 |                   
  ...ter-schema.ts |     100 |    98.07 |     100 |     100 | 99                
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |    81.2 |    79.93 |   91.17 |    81.2 | ...1432,1509-1510 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   78.56 |    87.65 |   80.33 |   78.56 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   98.96 |    79.48 |     100 |   98.96 | 169,183           
  ...on-tracing.ts |   74.55 |    73.21 |   70.58 |   74.55 | ...95,336-338,354 
  ...attributes.ts |   98.13 |       88 |     100 |   98.13 | 185-187           
  ...-exporters.ts |   46.37 |      100 |   44.44 |   46.37 | ...85,88-89,92-93 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.09 |    95.61 |      95 |   99.09 | 141,365-366       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   54.08 |    65.85 |   60.86 |   54.08 | ...1250,1267-1287 
  metrics.ts       |   75.31 |    80.85 |   77.19 |   75.31 | ...1021,1024-1035 
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   86.75 |     88.4 |   66.66 |   86.75 | ...17-621,659-681 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.04 |    87.94 |   96.55 |   90.04 | ...1504,1535-1538 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  trace-context.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.56 |    88.63 |     100 |   98.56 | 52,101            
  types.ts         |   79.46 |    93.91 |   84.21 |   79.46 | ...1241,1244-1273 
  uiTelemetry.ts   |      92 |    95.34 |   80.95 |      92 | ...00,206-216,244 
 ...ry/qwen-logger |   68.17 |     80.2 |   65.51 |   68.17 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.17 |       80 |   64.91 |   68.17 | ...1077,1115-1116 
 src/test-utils    |   93.44 |    96.15 |   77.77 |   93.44 |                   
  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.71 |    97.36 |   74.19 |   91.71 | ...54,218-219,232 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   79.72 |    82.11 |    85.8 |   79.72 |                   
  ...erQuestion.ts |   90.03 |    79.36 |   91.66 |   90.03 | ...99-400,407-408 
  cron-create.ts   |   88.18 |    93.33 |    62.5 |   88.18 | ...,45-46,177-185 
  cron-delete.ts   |   97.53 |      100 |   83.33 |   97.53 | 31-32             
  cron-list.ts     |   97.82 |    95.45 |   83.33 |   97.82 | 30-31             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   80.82 |    83.48 |      75 |   80.82 | ...08-709,819-869 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |   90.69 |       75 |   85.71 |   90.69 | 55-56,74-79       
  exit-worktree.ts |   84.23 |    85.96 |   91.66 |   84.23 | ...92-293,298-312 
  exitPlanMode.ts  |   82.94 |    77.35 |     100 |   82.94 | ...62-374,386-389 
  glob.ts          |   90.63 |    88.33 |   84.61 |   90.63 | ...28,171,302,305 
  grep.ts          |   79.04 |    85.71 |      75 |   79.04 | ...73-580,604-605 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.77 |    60.09 |   90.32 |   72.77 | ...1211,1213-1214 
  ...nt-manager.ts |   80.51 |     78.4 |   84.44 |   80.51 | ...2981,2983-2984 
  mcp-client.ts    |      43 |    87.57 |      75 |      43 | ...1790,1794-1797 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   77.21 |    83.96 |   79.41 |   77.21 | ...1259,1267-1268 
  ...ool-events.ts |       8 |      100 |       0 |       8 | 123-149           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 175-176           
  mcp-tool.ts      |   91.36 |    89.32 |   96.55 |   91.36 | ...40-641,691-692 
  ...sport-pool.ts |   83.27 |       80 |   84.61 |   83.27 | ...1399,1406-1410 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-47              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   91.65 |    84.05 |   88.46 |   91.65 | ...87,600,796-801 
  notebook-edit.ts |   85.11 |    76.42 |   81.25 |   85.11 | ...54-870,916-917 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   82.57 |    89.74 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   94.75 |    90.32 |   81.81 |   94.75 | ...02,305,388-389 
  ripGrep.ts       |   94.17 |    85.71 |    87.5 |   94.17 | ...96-497,547-548 
  ...-transport.ts |    6.34 |      100 |       0 |    6.34 | 47-145            
  send-message.ts  |   79.48 |    86.95 |    62.5 |   79.48 | ...97-203,286-294 
  ...n-mcp-view.ts |   92.37 |    93.54 |   88.88 |   92.37 | 118-126           
  shell.ts         |   74.32 |    80.89 |   90.54 |   74.32 | ...4272,4331-4332 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |    89.4 |     92.5 |   88.88 |    89.4 | ...43,447,476-498 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |   93.85 |     92.3 |   81.81 |   93.85 | 41-45,59-60,91    
  task-list.ts     |   73.38 |    77.77 |   83.33 |   73.38 | ...02,105,109-116 
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  task-update.ts   |   80.67 |       78 |    92.3 |   80.67 | ...75-383,415-426 
  team-create.ts   |   97.22 |    85.71 |   83.33 |   97.22 | 48-49,129-130     
  team-delete.ts   |   86.74 |    83.33 |   83.33 |   86.74 | 37-38,42-48,72-73 
  todoWrite.ts     |   89.27 |    82.05 |   92.85 |   89.27 | ...50-555,577-578 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   76.19 |     76.1 |   81.39 |   76.19 | ...53-854,862-863 
  tool-search.ts   |   92.35 |    85.84 |    92.3 |   92.35 | ...08-213,320-329 
  tools.ts         |   92.36 |    90.74 |   90.47 |   92.36 | ...99-500,516-522 
  web-fetch.ts     |   88.84 |       80 |   92.85 |   88.84 | ...12-313,315-316 
  write-file.ts    |   82.65 |    80.45 |   84.61 |   82.65 | ...65-668,696-731 
 src/tools/agent   |   76.31 |    84.65 |   76.66 |   76.31 |                   
  agent.ts         |   76.53 |    84.86 |    77.1 |   76.53 | ...3091,3118-3181 
  fork-subagent.ts |   71.08 |       75 |   71.42 |   71.08 | ...25-126,161-172 
 ...s/computer-use |   90.03 |    81.27 |   75.36 |   90.03 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   73.22 |    89.65 |   64.28 |   73.22 | ...70-172,233-242 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |   96.24 |    85.29 |     100 |   96.24 | 75-76,184,251-257 
 ...tools/workflow |   86.69 |    72.58 |   88.23 |   86.69 |                   
  workflow.ts      |   86.69 |    72.58 |   88.23 |   86.69 | ...81-382,394-397 
 src/utils         |   89.58 |    88.46 |   93.99 |   89.58 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.76 |    93.26 |     100 |   94.76 | ...30-531,634-638 
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |   76.31 |    53.33 |     100 |   76.31 | ...37,43-44,65-66 
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...ncyLimiter.ts |   94.64 |    95.23 |     100 |   94.64 | 64-66             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.11 |    89.47 |     100 |   91.11 | ...46-147,154-155 
  cronDisplay.ts   |   83.33 |    81.48 |     100 |   83.33 | 44-45,47-51       
  cronParser.ts    |   93.16 |       90 |     100 |   93.16 | ...46,60-61,63-64 
  debugLogger.ts   |   96.42 |    94.11 |   88.23 |   96.42 | 185-189           
  editHelper.ts    |   93.63 |    83.52 |     100 |   93.63 | ...28-429,463-464 
  editor.ts        |    97.6 |     95.4 |     100 |    97.6 | ...25-326,328-329 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.78 |    89.13 |      95 |   96.78 | ...51-252,257,403 
  errorParsing.ts  |    97.7 |    97.05 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.54 |       80 |      50 |   70.54 | ...15-231,235-241 
  fetch.ts         |    70.8 |     77.5 |   71.42 |    70.8 | ...41-142,161,186 
  fileUtils.ts     |    91.5 |    86.13 |   95.23 |    91.5 | ...1191,1195-1201 
  forkedAgent.ts   |   80.68 |    78.12 |   83.33 |   80.68 | ...39-545,550-556 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  gitDiff.ts       |   92.36 |    79.53 |     100 |   92.36 | ...55-856,928-929 
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   72.91 |    90.32 |   83.33 |   72.91 | ...,77-78,102-153 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   88.98 |    90.66 |   91.66 |   88.98 | ...46-349,359-365 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.01 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   93.77 |    89.02 |     100 |   93.77 | ...13-319,406-407 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  modelId.ts       |   98.96 |    98.18 |     100 |   98.96 | 153               
  ...kerChecker.ts |   90.78 |    91.66 |     100 |   90.78 | 73-79             
  notebook.ts      |   94.57 |    89.83 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   90.85 |    87.87 |     100 |   90.85 | ...97-199,222-227 
  partUtils.ts     |     100 |    98.61 |     100 |     100 | 206               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.21 |    91.95 |     100 |   93.21 | ...89-390,392-394 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   93.75 |    88.34 |     100 |   93.75 | ...13,218-219,262 
  readManyFiles.ts |   87.59 |       84 |     100 |   87.59 | ...09-211,227-238 
  retry.ts         |   95.93 |    91.83 |     100 |   95.93 | ...33,524-525,543 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.52 |    96.84 |     100 |   97.52 | ...05,255-256,282 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   46.79 |    83.33 |   66.66 |   46.79 | ...45-246,258-335 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   82.18 |    85.18 |   95.23 |   82.18 | ...24,549,578-587 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |    97.5 |    88.57 |     100 |    97.5 | 162-163           
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    88.23 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   95.79 |     86.4 |     100 |   95.79 | ...14,223-226,280 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   96.89 |    85.84 |     100 |   96.89 | ...51,367,447,466 
  shell-utils.ts   |   84.39 |    90.46 |     100 |   84.39 | ...1583,1590-1594 
  ...lAstParser.ts |   95.57 |    85.79 |     100 |   95.57 | ...1066-1068,1078 
  ...ContextEnv.ts |     100 |      100 |     100 |     100 |                   
  ...nlyChecker.ts |   95.08 |    91.66 |     100 |   95.08 | ...15-316,324-325 
  sideQuery.ts     |   86.17 |    86.53 |     100 |   86.17 | ...55-161,163-169 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   81.48 |       75 |     100 |   81.48 | 54-59             
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  ...ultCleanup.ts |   15.45 |    33.33 |      25 |   15.45 | 33-136            
  truncation.ts    |   75.31 |    85.71 |   71.42 |   75.31 | ...49-454,458-482 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   95.81 |    89.39 |     100 |   95.81 | ...74-275,299-301 
  xml.ts           |    97.8 |     87.5 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    73.84 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.58 |    81.02 |   94.28 |   83.58 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   83.07 |    77.74 |   94.82 |   83.07 | ...1468,1502-1503 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...70-271,273-274 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  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.

Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts
Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts
Comment thread packages/core/src/agents/runtime/workflow-sandbox.test.ts

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] extractErrorMessage is duplicated byte-for-byte in both workflow.ts:281 and workflow-orchestrator.ts:1294 (the comment at workflow.ts:278 even references the other copy). A future fix to one will likely be missed in the other. Consider exporting it from workflow-orchestrator.ts and importing it here.

[Suggestion] Import statements (import * as vm and import { createDebugLogger }) are placed at line 310, after ~300 lines of function definitions. ESM hoisting makes this work, but it violates the project convention — other files in this PR have imports at the top. Consider moving them to the top of the file.

— qwen3.7-max via Qwen Code /review

Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts
Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts
After PR #5094 opened without an E2E run, ran a 3-lens adversarial
review (correctness / security / completeness) of the meta-extraction
assertion strength against extractAndStripMeta and the meta-on-outcome
threading path. All 3 reviewers refuted the claim that the existing
assertions catch realistic regressions. Triage:

- 18 of 24 findings already covered by workflow-sandbox.test.ts
  (string-with-brace, comments-inside-meta, phases[].model,
  missing-description error text, args/process/require unreachability,
  Promise/Math.constructor escape, etc.)
- 4 findings (regex literal / template literal / `/m` flag / spread)
  are host-side parse-path branches the brace walker handles
  structurally but without explicit negative tests
- 2 truly novel gaps closed here:

  1. HIGH × 3 lenses: a regression in validateMeta that returns the
     vm-realm `raw` value directly (skipping the host-realm copy at
     workflow-sandbox.ts:283-294) would re-open T1/T8/T14 realm
     escape via outcome.meta.constructor.constructor('return process')().
     Vitest toEqual is structural and does NOT check prototype
     identity, so every prior assertion in the suite would still pass.
     Add returned-meta + phases array + phase entries prototype-
     identity check in workflow-sandbox.test.ts; mirror end-to-end
     in the live test's scenario A.

  2. MEDIUM: meta-shaped result collision — if a script returns
     `{ name, description, phases }`, the safeStringifyDisplayPayload
     spread must keep `meta` and `result` distinct at the top level.
     Add a workflow.test.ts case that returns a meta-shaped object and
     asserts both display.meta and display.result hold their own
     distinct values.

Also add the real-LLM E2E harness at workflow-p4a-meta-live.live.test.ts
(6 scenarios: meta+agent, no-meta, malformed-meta short-circuit,
body-throw with meta preservation, parallel() fan-out with meta phases,
pipeline() multi-stage with meta phases). The suite is gated by
DASHSCOPE_API_KEY — describe.skip when absent, so CI without the
env shows 0 tests in this file rather than failing. Verified locally
6/6 against qwen3-coder-plus via DashScope OpenAI-compatible endpoint.

Final test count: 129/129 (89 sandbox + 34 tool + 6 live).

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

CI is currently red (Lint + Test ×3). The Lint failure is prettier --check: 5 of the changed files are not formatted — workflow-sandbox.ts, workflow.ts, workflow-sandbox.test.ts, workflow-p4a-meta-live.live.test.ts, workflow.test.ts (eslint is clean). Run npx prettier --write on them. The Test-job failures reproduce neither in the three changed unit suites (201 pass locally) nor the live file (it skips cleanly without DASHSCOPE_API_KEY), so they look unrelated to the reviewed code — worth a separate look. Substantive findings are inline below.

— claude-opus-4-8[1m] via Qwen Code /qreview

Comment thread packages/core/src/agents/runtime/workflow-p4a-meta-live.live.test.ts Outdated
Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⚠️ Downgraded from Request Changes to Comment: CI failing (Lint, Test ×3, Post Coverage Comment).

Incremental review (since R1 at 5b56c39): new commit 55c23a0 adds 3 test files (+446 lines) that close the adversarial-review gaps identified in R1 — prototype-identity assertions for vm-realm escape defense and meta-shaped-result collision test. All 123 unit tests pass locally.

However, the 11 tsc errors in workflow-p4a-meta-live.live.test.ts from R1 remain unfixednpm run typecheck is still red. See inline comment for details.

— qwen3.7-max via Qwen Code /review

Comment thread packages/core/src/agents/runtime/workflow-p4a-meta-live.live.test.ts Outdated
@wenshao

wenshao commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Local verification (merge reference)

Verified 55c23a0270 on Linux (Node 22.22.2). The P4a meta-extraction feature is solid and its sandbox boundary holds under adversarial probing — but the branch currently fails npm run typecheck / preflight because of the new live E2E test file. Details below.

⚠️ Finding (please fix before merge): npm run typecheck is red

workflow-p4a-meta-live.live.test.ts (added in the post-review commit 55c23a02) does not typecheck — npm run typecheck --workspace packages/core reports 11 errors, all in that file:

  • error TS2459: imports WorkflowAgentOpts from ./workflow-orchestrator.js, which doesn't export it.
  • error TS2322 (×4): assigns a dispatch result (WorkflowAgentResult = string | object) to a string.
  • error TS2345 (×4): calls the orchestrator's run with { script }, but args is required on WorkflowRunRequest.

I confirmed it's isolated: deleting only that file makes typecheck exit 0. So the live E2E was written against a stale orchestrator API.

Why it's easy to miss, and why it still matters:

  • The test is gated on DASHSCOPE_API_KEY, so npm run test:ci skips it (6 skipped) and stays green.
  • PR CI (ci.yml) runs lint + test:ci but not tsc --noEmit, so PR CI is green too.
  • typecheck runs in preflight and release.yml — both go red on this branch. The PR body's "npm run typecheck --workspace=packages/core" claim no longer holds at the current head.

Fix is small (3 items in the live test): import/export WorkflowAgentOpts correctly, type the dispatch return as WorkflowAgentResult, and pass args in the run requests.

The P4a feature itself — solid

Tests: the 4 reviewer-plan files pass — 209 passed (sandbox 102 · orchestrator 78 · workflow 21 · concurrencyLimiter 8). Lint clean, git diff --check clean, and typecheck is clean once the live test file is removed.

Mutation: making validateMeta return the raw vm object instead of the fresh host-realm copy fails exactly the post-review gap test returned meta + phases array + phase entries are all host-realm objects — so the host-realm copy is genuinely load-bearing.

Adversarial security probe (real extractAndStripMeta) — the vm boundary holds against vectors beyond the existing tests:

Attack in the meta literal Result
get name() reading globalThis.process returns 'no-process' — no host process
get description() via this.constructor.constructor('return typeof process')() 'undefined'/threw — Function ctor stays in the vm realm
["__proto__"]: {…} on the meta object host Object.prototype not polluted
["__proto__"]: {…} on a phase entry not polluted; phase lands as a clean host object

End-to-end in a real process (tsx in tmux)createWorkflowSandbox().run(metaScript)getMeta():

RUN return value : "body-done"
getMeta()        : {"name":"demo-wf","description":"A demo workflow","phases":[{"title":"Scan","detail":"grep"},{"title":"Fix","model":"sonnet"}]}
meta host-realm? : true
ADVERSARIAL process: threw (contained) → ...failed to evaluate meta object literal: Reference[process is not defined]
ADVERSARIAL proto  : Object.prototype polluted? false
MALFORMED (no name): meta.name must be a non-empty string   ← upstream-verbatim

So the meta surfaces correctly on the run, the validation errors match upstream, and a malicious meta literal can neither reach host globals nor pollute the prototype.

Verdict

The P4a feature is well-implemented, well-tested, and the sandbox boundary is robust — I'd happily approve the meta-extraction code. The one blocker is mechanical: the live E2E test breaks npm run typecheck / preflight / release (stale orchestrator API, masked by runtime-skip + PR-CI not running tsc). Fix those 3 type issues (or drop/@ts--guard the live file) and it's good to merge.

中文版(Chinese version)

本地验证(合并参考)

Linux(Node 22.22.2)上验证 55c23a0270。P4a 的 meta 提取功能扎实,沙箱边界在对抗性探测下也守得住——但当前分支会让 npm run typecheck / preflight 失败,原因是新增的 live E2E 测试文件。 详见下文。

⚠️ 发现(合并前请修复):npm run typecheck 为红

workflow-p4a-meta-live.live.test.ts(在 review 后的提交 55c23a02 中加入)无法通过类型检查——npm run typecheck --workspace packages/core11 个错误,全部在该文件:

  • TS2459:从 ./workflow-orchestrator.js 导入 WorkflowAgentOpts,但该模块并未导出它。
  • TS2322(×4):把 dispatch 的返回(WorkflowAgentResult = string | object)赋给 string
  • TS2345(×4):用 { script } 调用 orchestrator 的 run,但 WorkflowRunRequest 必填 args

我确认是孤立的:删除该文件,typecheck 即 exit 0。所以这个 live E2E 是对着过时的 orchestrator API 写的。

为什么容易被忽略、又为什么仍然重要:

  • 该测试以 DASHSCOPE_API_KEY 为门控,npm run test:ci跳过它(6 skipped),保持绿色。
  • PR CI(ci.yml)跑 lint + test:ci,但tsc --noEmit,所以 PR CI 也是绿的。
  • typecheckpreflightrelease.yml 中运行——两者在此分支都会变。PR 描述里"npm run typecheck --workspace=packages/core"通过的说法,在当前 head 已不成立。

修复很小(live 测试里 3 处):正确导入/导出 WorkflowAgentOpts、把 dispatch 返回类型写成 WorkflowAgentResult、在 run 请求里传 args

P4a 功能本身 —— 扎实

测试: 评审计划的 4 个文件通过——209 通过(sandbox 102 · orchestrator 78 · workflow 21 · concurrencyLimiter 8)。lint 干净、git diff --check 干净;移除 live 测试文件后 typecheck 也干净。

变异测试:validateMeta 返回原始 vm 对象而非新建的 host-realm 副本,恰好让 review 后补的 gap 测试 returned meta + phases array + phase entries are all host-realm objects 失败——所以 host-realm 拷贝确实承重。

对抗性安全探测(真实 extractAndStripMeta) —— vm 边界在既有测试之外的向量下也守得住:

meta 字面量中的攻击 结果
get name() 读取 globalThis.process 返回 'no-process'——拿不到宿主 process
get description()this.constructor.constructor('return typeof process')() 'undefined'/抛错——Function 构造器停留在 vm realm
meta 对象上的 ["__proto__"]: {…} 宿主 Object.prototype 被污染
phase 条目上的 ["__proto__"]: {…} 未污染;phase 落地为干净的宿主对象

真实进程端到端(tmux 中用 tsx) —— createWorkflowSandbox().run(metaScript)getMeta():

RUN return value : "body-done"
getMeta()        : {"name":"demo-wf","description":"A demo workflow","phases":[{"title":"Scan","detail":"grep"},{"title":"Fix","model":"sonnet"}]}
meta host-realm? : true
ADVERSARIAL process: threw (contained) → ...failed to evaluate meta object literal: Reference[process is not defined]
ADVERSARIAL proto  : Object.prototype polluted? false
MALFORMED (no name): meta.name must be a non-empty string   ← 与上游逐字一致

即:meta 在 run 后正确浮现,校验错误与上游一致,恶意 meta 字面量既够不到宿主全局,也污染不了原型。

结论

P4a 功能实现良好、测试充分、沙箱边界稳健——meta 提取代码我乐于 approve。唯一阻塞是机械性的:live E2E 测试让 npm run typecheck / preflight / release 变红(对着过时的 orchestrator API,被运行时跳过 + PR CI 不跑 tsc 所掩盖)。修掉那 3 处类型问题(或删除/@ts- 守护该 live 文件)即可合并。

…ttier (#4721)

Round 3 review fixes:

1. **(Critical, wenshao R1)** A Promise — typically from `import('node:fs')`
   inside a meta literal — used to crash the host process. `runInContext`
   evaluates the literal synchronously and returns; `validateMeta` drops
   the non-contract field silently; the workflow returns its result;
   THEN the dangling unhandled rejection terminates the process under
   Node's default `--unhandled-rejections=throw`, decoupled from the run
   that triggered it. Wenshao reproduced on Node 22.22 with:

       export const meta = { name:'x', description:'d', extra: import('node:fs') }
       return 1
       → run returns 1, process exits with code 1.

   Mitigation: after `vm.Script(...).runInContext(...)`, walk the eval
   result recursively, call `.catch(() => {})` on any thenable to mark
   the rejection handled, and throw an explicit
   "meta values must not be Promises" so the malformed meta is rejected
   before validation continues. Recursion covers `phases[]` entries
   embedding `import()` below the top level. Two RED-first regression
   tests in workflow-sandbox.test.ts (top-level + nested-in-phases).

2. **(Critical, wenshao R2/R3)** `tsc --noEmit` failed with 11 errors in
   the new live E2E test file, blocking CI Lint + all 3 Test jobs:

   - TS2459 (L36): `WorkflowAgentOpts` is exported from
     `workflow-sandbox.js`, not from `workflow-orchestrator.js` —
     fixed import path.
   - TS2322 (L108/165/220): typing `liveDispatch` as
     `WorkflowAgentDispatch` widens the return to `string | object`,
     which doesn't fit `lastText: string`. Dropped the type annotation;
     the inferred `Promise<string>` is still assignment-compatible with
     `WorkflowAgentDispatch` (string ⊂ string | object).
   - TS2345 (×6): `WorkflowRunRequest.args` is required (`args: unknown`,
     not optional). Added `args: undefined` to every `orch.run({ script })`
     call.

3. Prettier: `--write` on the 4 touched files. R2 also flagged this;
   pre-commit lint-staged would normally cover it but the live test
   file's TS errors short-circuited it.

Final local verification:
- `tsc --noEmit`: 0 errors
- 209/209 tests pass across workflow-sandbox + workflow-orchestrator +
  workflow.test.ts + live (6 scenarios against qwen3-coder-plus via DashScope)
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

Round 3 triage — fixed in 402df8f

Thread File Verdict Action
Critical: dynamic import() crashes process via dangling Promise workflow-sandbox.ts:198 ✅ fixed rejectThenablesInMeta walks eval result, neutralizes thenables, throws explicit error; 2 RED-first regression tests
Critical: tsc --noEmit 11 errors in live test (R2 + R3) workflow-p4a-meta-live.live.test.ts ✅ fixed WorkflowAgentOpts re-import + liveDispatch type narrowed + args: undefined ×6; tsc clean
Suggestion: stripExportMeta: error prefix misleading (2 reviewers) workflow-sandbox.ts:128 ❌ declined stripExportMeta is preserved as the thin wrapper / shared throw site; prefix is functionally accurate. R3 + Suggestion ≠ blocking.
Suggestion: validateMeta branch coverage + endBraceIncl test gap workflow-sandbox.test.ts:211 ❌ declined Shared infrastructure preserved from P1, not a new surface this PR introduces. Out of P4a's extraction-+-display scope.
Suggestion: array meta produces misleading "meta.name" error workflow-sandbox.ts:225 ❌ declined Array case still rejects (just with suboptimal text). 2-line ergonomic improvement, fits a follow-up PR.
Suggestion: stale meta retained on sandbox reuse workflow-sandbox.ts:929 ❌ declined Latent — orchestrator builds a fresh sandbox per run(). No reuse path on the P4-P7 roadmap.

Prettier was also flushed on the 4 touched files. Final local verification: tsc --noEmit clean, 209/209 tests pass (workflow-sandbox + orchestrator + tool + live E2E 6/6).

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review aborted with an API error before posting comments. See workflow logs.

@LaZzyMan LaZzyMan changed the title feat(core): Workflow P4a — extractAndStripMeta + meta on RunOutcome (#4721) feat(core+cli): Workflow P4 — meta + /workflows + phase-tree (#4721) Jun 15, 2026
@LaZzyMan LaZzyMan changed the title feat(core+cli): Workflow P4 — meta + /workflows + phase-tree (#4721) feat(core): Workflow P4a — extractAndStripMeta + meta on RunOutcome (#4721) Jun 15, 2026
@wenshao

wenshao commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

✅ Independent verification report — real-CLI E2E + adversarial reverse-audit

I validated this PR by building and running the real qwen CLI from the PR branch (lazzy/workflow-p4-meta-workflows-pill @ 402df8f23) and by writing an independent adversarial suite that does not rely on the PR's own tests. TL;DR: the core change is correct, well-tested, and the meta-eval sandbox does not escape to the host — I recommend merge. I also found 2 hardening gaps + 1 doc nuance in the meta-extraction path, each with a reproducer; none block the feature for intended use, but #1/#2 are worth a quick follow-up (or folding in).

How it was validated

Area Method Result
PR's own suite vitest run on the 4 cited files 211/211 green (PR body says 208; 3 extra, all pass)
Real-CLI E2E (meta present) built core+cli, ran TUI in tmux, QWEN_CODE_ENABLE_WORKFLOWS=1, model glm-4.7 called the workflow tool meta block surfaces in the actual tool-result card, distinct from result
Real-CLI E2E (no meta) same, script without export const meta meta key omitted from returnDisplay
Security boundary standalone probes of realm-escape vectors against the real compiled fn all blocked (process/require/globalThis.process/Function('return process') → throw/undefined) ✓
Host-realm copy independent vitest assertions returned meta + phases[] + entries are host-realm; non-contract fields dropped ✓
Brace-walker "known gaps" strings/regex/templates/comments/spread w/ braces inside meta all strip cleanly, no body corruption ✓
Live test gating ran *.live.test.ts without DASHSCOPE_API_KEY 6 skipped, file not failed — CI-safe ✓

Environment: worktree off the PR base (which is ahead of upstream main and adds proper-lockfile), node v22.22.2, deps hardlinked + the new dep installed, core/cli dist built (tsc reports the pre-existing @google/genai phantom errors but emits JS correctly).

Real-CLI E2E evidence (actual TUI tool-result cards):

// meta present → distinct top-level "meta" key alongside "result"
{ "runId": "wf_f9460a356668d355",
  "meta": { "name": "capital-demo", "description": "P4a meta surfacing E2E", "phases": [ { "title": "Plan" } ] },
  "phases": [], "logs": [], "result": { "ok": true, "marker": "P4A_E2E_OK" } }

// no meta → "meta" key omitted (conditional spread works)
{ "runId": "wf_6311d94f0bb390d1", "phases": [], "logs": [], "result": { "ok": true, "marker": "NO_META_CASE" } }

🟠 Finding 1 — meta eval has no wall-clock cap (DoS parity gap) · Medium

The script body eval is capped at 30s (workflow-sandbox.ts:982), but the meta eval passes no timeout (workflow-sandbox.ts:198). A model-authored meta containing synchronous infinite computation hangs the host event loop forever (no recovery without kill):

export const meta = { name: (function(){ while(true){} })(), description: 'd' }   // hangs at line 198
export const meta = { name: 'x', description: 'd', get phases(){ while(true){} } } // hangs in Object.values() during rejectThenablesInMeta
return 1

Both reproduced via the real compiled function under an OS timeout → killed (exit 124). The body is protected against exactly this class (see the T23/T40 comments in the file); the meta path should have parity. Note a timeout: on the eval (line 198) fixes the IIFE case but not the getter case (that getter fires in host code during Object.values, outside any vm watchdog) — reading data properties via getOwnPropertyDescriptor/skipping accessors, or structuredClone first, would close both.

🟠 Finding 2 — Promise-crash fix is incomplete (≥2 promises leak) · Low–Medium

The R3 fix (402df8f23) intends to "walk raw, neutralise any thenables." In practice rejectThenablesInMeta (workflow-sandbox.ts:230) .catch()-es only the first thenable it meets, then throws (:243) — so the recursion never reaches the rest. A meta with two rejecting promises leaks the second:

export const meta = { name: 'x', description: 'd', a: Promise.reject(new Error('boom1')), b: Promise.reject(new Error('boom2')) }
return 1
  • Bare core embedder (no global handler): the sync error is thrown and caught, but boom2 then fires as an unhandled rejection → hard crash, exit 1 (SURVIVED never printed). This is the exact crash class the R3 fix targeted, just re-triggered by ≥2 promises.
  • Shipped qwen CLI: intercepted by the pre-existing global handler (gemini.tsx:175, installed for both interactive + non-interactive at :426) → routed to the "CRITICAL: Unhandled Promise Rejection!" log path, not a crash. I confirmed in the TUI that the tool surfaces a clean meta values must not be Promises error and the process stays alive — but the leak still fires the path the fix meant to eliminate, and also reaches sharedTokenManager's own unhandledRejection cleanup (sharedTokenManager.ts:197).
  • The PR's only promise test covers the single-promise case, which passes — masking this.

Fix: complete the walk (collect a found flag, neutralise every thenable) and throw once at the end, instead of throwing on the first.

⚪ Finding 3 — host-realm-copy rationale is imprecise (no code change needed) · Informational

The PR/tests state that returning the raw vm value would "re-open T1/T8/T14 realm escape via outcome.meta.constructor.constructor('return process')()". Empirically, a raw vm.runInContext object's constructor chain stays in the vm realm, so that expression yields typeof process === 'undefined', not the host process — the escape does not actually materialize. The host-realm copy is still valuable, but for the accurate reasons: allowlist projection (strips getters/extra keys/__proto__ tricks so only validated primitives cross) and prototype normalization (so instanceof/serialization behave). Worth fixing the comment so the security model is documented accurately.


Recommendation

Approve / mergeable. The feature is correct and the sandbox boundary holds end-to-end. Findings #1 and #2 harden the meta path against pathological/adversarial model output and are small, well-contained changes — fine to fold in here or as an immediate follow-up; #3 is a comment fix.

Validated against 402df8f23. Repro scripts run the real compiled extractAndStripMeta; E2E ran the real CLI TUI via tmux with glm-4.7. The PR's *.live.test.ts (DashScope) was not run (no key); its meta-specific scenarios were covered through the real CLI instead.

🇨🇳 中文版验证报告(点击展开)

✅ 独立验证报告 — 真实 CLI 端到端 + 对抗式反向审计

我通过在本地构建并运行真实的 qwen CLI(PR 分支 lazzy/workflow-p4-meta-workflows-pill @ 402df8f23),并编写了一套不依赖 PR 自带测试的对抗式用例来验证本 PR。结论:核心改动正确、测试充分,且 meta 求值沙箱不会逃逸到宿主环境 —— 建议合并。同时发现 meta 提取路径上的 2 个加固缺口 + 1 处文档表述不准确,均附复现脚本;都不影响功能的正常使用,但 #1/#2 值得快速跟进(或直接并入本 PR)。

验证方式

范围 方法 结果
PR 自带测试 对 4 个引用文件执行 vitest run 211/211 通过(PR 描述写 208,多出 3 个,全过)
真实 CLI E2E(有 meta) 构建 core+cli,在 tmux 中运行 TUI,QWEN_CODE_ENABLE_WORKFLOWS=1,由 glm-4.7 调用 workflow 工具 工具结果卡片中出现 meta,与 result 区分 ✓
真实 CLI E2E(无 meta) 同上,脚本不含 export const meta returnDisplay省略 meta
安全边界 用独立探针对真实编译产物测试逃逸向量 全部被拦截process/require/globalThis.process/Function('return process') 均抛错或 undefined)✓
宿主域拷贝 独立 vitest 断言 返回的 meta+phases[]+条目均为宿主域对象;非契约字段被丢弃 ✓
花括号扫描器"已知盲区" meta 内含 字符串/正则/模板串/注释/展开运算 的花括号 均正确剥离,未破坏脚本体 ✓
live 测试门控 未设 DASHSCOPE_API_KEY 时运行 *.live.test.ts 6 个 skip,文件不失败 —— CI 安全 ✓

环境:基于 PR base 的 worktree(该 base 领先上游 main,新增了 proper-lockfile 依赖),node v22.22.2,依赖硬链接 + 安装新依赖,core/cli dist 已构建(tsc 报的是既有的 @google/genai 幻影错误,但 JS 正常产出)。

真实 CLI E2E 证据(实际 TUI 工具结果卡片):

// 有 meta → 顶层独立的 "meta" 键,与 "result" 并列
{ "runId": "wf_f9460a356668d355",
  "meta": { "name": "capital-demo", "description": "P4a meta surfacing E2E", "phases": [ { "title": "Plan" } ] },
  "phases": [], "logs": [], "result": { "ok": true, "marker": "P4A_E2E_OK" } }

// 无 meta → 省略 "meta" 键(条件展开生效)
{ "runId": "wf_6311d94f0bb390d1", "phases": [], "logs": [], "result": { "ok": true, "marker": "NO_META_CASE" } }

🟠 发现 1 — meta 求值缺少时钟上限(DoS 对等缺口)·

脚本的求值有 30s 上限(workflow-sandbox.ts:982),但 meta 的求值没有传 timeoutworkflow-sandbox.ts:198)。模型编写的 meta 中若含同步死循环,会让宿主事件循环永久挂起(不杀进程无法恢复):

export const meta = { name: (function(){ while(true){} })(), description: 'd' }   // 在 198 行挂死
export const meta = { name: 'x', description: 'd', get phases(){ while(true){} } } // 在 rejectThenablesInMeta 的 Object.values() 中挂死
return 1

两者均用真实编译产物在 OS 超时下复现 → 被杀(exit 124)。脚本体本就防护了这一类(见文件中 T23/T40 注释),meta 路径应当对齐。注意:仅给 198 行加 timeout: 能解决 IIFE 情形,但解决不了 getter 情形(getter 在 Object.values 期间于宿主代码中触发,不受 vm 看门狗约束)—— 改用 getOwnPropertyDescriptor 读数据属性 / 跳过访问器,或先 structuredClone,可同时堵住两者。

🟠 发现 2 — Promise 崩溃修复不完整(≥2 个 Promise 会泄漏)· 低–中

R3 修复(402df8f23)意图"遍历 raw,中和任何 thenable"。但实际上 rejectThenablesInMetaworkflow-sandbox.ts:230)只对遇到的第一个 thenable 做 .catch(),随后就 throw:243),递归永远到不了其余的。含两个拒绝态 Promise 的 meta 会泄漏第二个:

export const meta = { name: 'x', description: 'd', a: Promise.reject(new Error('boom1')), b: Promise.reject(new Error('boom2')) }
return 1
  • 裸用 core 的嵌入方(无全局处理器): 同步错误被抛出并捕获,但 boom2 随后作为未处理拒绝触发 → 硬崩溃,exit 1SURVIVED 从未打印)。这正是 R3 修复想消除的崩溃类型,只是被 ≥2 个 Promise 重新触发。
  • 已发布的 qwen CLI: 被既有全局处理器拦截(gemini.tsx:175,在交互/非交互两条路径于 :426 处都已安装)→ 走 "CRITICAL: Unhandled Promise Rejection!" 日志路径,不会崩溃。我在 TUI 中确认工具给出干净的 meta values must not be Promises 错误且进程存活 —— 但该泄漏仍触发了修复本想消除的路径,并会波及 sharedTokenManager 自己的 unhandledRejection 清理(sharedTokenManager.ts:197)。
  • PR 仅有的 Promise 测试覆盖单个 Promise 情形(通过),从而掩盖了本问题。

修复: 遍历完整结构(用 found 标志收集,中和每一个 thenable),最后只抛一次,而不是遇到第一个就抛。

⚪ 发现 3 — 宿主域拷贝的理由表述不准确(无需改代码)· 提示性

PR/测试声称:直接返回 vm 原始值会"经由 outcome.meta.constructor.constructor('return process')() 重新打开 T1/T8/T14 realm 逃逸"。实测:vm.runInContext 返回对象的构造链留在 vm 域内,因此该表达式得到的是 typeof process === 'undefined'并非宿主 process —— 逃逸并不会真正发生。宿主域拷贝依然有价值,但准确的理由是:白名单投影(剥离 getter/多余键/__proto__ 把戏,只让校验过的原始值通过)与原型规范化(保证 instanceof/序列化行为正常)。建议修订注释,使安全模型的描述更准确。


建议

通过 / 可合并。 功能正确,沙箱边界端到端成立。发现 #1#2 是针对异常/对抗式模型输出对 meta 路径的加固,改动很小且自包含 —— 并入本 PR 或紧随其后跟进皆可;#3 改注释即可。

基于 402df8f23 验证。复现脚本运行的是真实编译后的 extractAndStripMeta;E2E 通过 tmux 用 glm-4.7 运行真实 CLI TUI。PR 的 *.live.test.ts(DashScope)因无 key 未运行,其 meta 相关场景已改由真实 CLI 覆盖。

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One non-blocking suggestion inline (sandbox robustness in the new rejectThenablesInMeta walker).

Verified locally on 402df8f: tsc --noEmit, ESLint, and the 203 unit tests across the three suites are all green; the prior typecheck and dynamic-import() blockers are confirmed resolved. The only red check, review-pr, is the Qwen review bot aborting on an API error (infra, not code).

FYI (not posted inline, non-blocking): prettier --check still flags workflow.ts:202-203 — the const meta = … collapses onto one 80-col line. It does not fail CI because the Lint job runs prettier --write . with no follow-up git status gate, so the committed file simply diverges from npm run format output. A quick npm run format cleans it.

— claude-opus-4-8[1m] via Qwen Code /qreview

Comment thread packages/core/src/agents/runtime/workflow-sandbox.ts Outdated

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: CI failing (review-pr — bot API error, not code). tsc 0, eslint 0, 211 tests pass, CI Lint/Test/CodeQL all green. — qwen3.7-max via Qwen Code /review

…orkflowRunRegistry (#4721)

P4b completes phase P4 of the Dynamic Workflows port. P4a (already on
this branch, commits 5b56c39 / 55c23a0 / 402df8f) locked the
meta contract: outcome.meta / err.meta / display payload. P4b adds the
consumer side — visible workflow runs in the TUI.

## Core (4 changes, 1 new file)

- `TaskKind` widened in `packages/core/src/agents/tasks/types.ts` from
  3 → 4 variants (adds `'workflow'`). `TaskState` union picks up
  `WorkflowTask` automatically.
- New `WorkflowRunRegistry` (`packages/core/src/agents/workflow-run-
  registry.ts`) — sibling of `BackgroundTaskRegistry` /
  `BackgroundShellRegistry` / `MonitorRegistry`. Same register / cancel /
  get / list / on('statusChange') shape; per-kind state holds runId,
  meta, current phase, phase history, dispatch counters, recent logs.
  Eviction: `MAX_RETAINED_TERMINAL_WORKFLOWS = 10` mirrors monitor cap.
- `Config.getWorkflowRunRegistry()` exposed via the same Object.create
  override pattern as the other registries.
- `WorkflowOrchestratorEmitter` interface added to workflow-sandbox.ts —
  fires `phaseStarted` (from sandbox safePhase), `agentDispatched` /
  `agentCompleted` (from orchestrator countedDispatch), and
  `logAppended` (from sandbox safeLog). Defensive try/catch around
  every emit so a subscriber error never bubbles into the script.
  Orchestrator accepts optional `runId` in WorkflowRunRequest so
  callers can pre-generate the id and register the run BEFORE run()
  resolves.
- `WorkflowTool` now registers the run with the registry at execute()
  start, wires the emitter to the registry's update methods + the
  tool's _updateOutput callback, flips `canUpdateOutput` to `true`
  for live phase-tree rendering, and routes terminals to
  registry.complete / fail / cancel (cancel on signal.aborted so
  user intent stays distinct from script bugs).
- `WorkflowRunRegistry` exported from core/index.ts.

## CLI (5 changes, 2 new files)

- `BackgroundTasksPill.tsx` `KIND_NAMES` gains `workflow:
  { singular, plural }`. Counts accumulator + sort order updated:
  `shell → agent → monitor → workflow → dream` (user-initiated
  before system-initiated).
- `useBackgroundTaskView.ts` subscribes to the workflow registry
  alongside the existing three; `entryId` switch adds
  `case 'workflow': return entry.runId`; cleanup unsubscribes.
- `BackgroundTasksDialog.tsx` adds `WorkflowDetailBody` (inline,
  matches MonitorDetailBody style) — renders workflow name,
  description, status, runtime, current phase, agent dispatch
  counts (M/N), the phase tree (capped at MAX_VISIBLE_PHASES=20
  with "+N more above"), and the log tail (capped at
  MAX_VISIBLE_LOG_LINES=10). rowLabel switch surfaces
  `[workflow] <name> · <phase> (M/N)`. DetailBody + statusVerb
  switches gain workflow cases.
- `BackgroundTaskViewContext.tsx` cancelSelected: `case 'workflow':
  registry.cancel(runId, Date.now())`. Idempotent with the
  WorkflowTool's signal.aborted catch path.
- `BackgroundTasksDialog.test.tsx` entryId mock gains workflow case.

## New /workflows slash command

- `packages/cli/src/ui/commands/workflowsCommand.ts` + tests.
  Bare `/workflows` lists active + completed runs (running first,
  then terminal by endTime DESC). `/workflows <runId>` opens a
  per-run detail dump (meta block, status, runtime, phase tree,
  recent logs, errors).
- Gated by `Config.isWorkflowsEnabled()` in BuiltinCommandLoader —
  command vanishes from typeahead when the flag is off. Already-
  defined env-var overrides (`QWEN_CODE_ENABLE_WORKFLOWS` opt-in,
  `QWEN_CODE_DISABLE_WORKFLOWS` kill switch) inherited for free.
- Interactive mode adds a "Tip: focus the Background tasks pill"
  redirect; non-interactive / acp modes omit the tip since they
  have no dialog.

## Scope deferrals

- **ACP daemon protocol widening** (acp-bridge bridgeTypes / status /
  tasksSnapshot) is deferred to a follow-up PR. Workflows remain
  invisible to SDK + web-shell consumers in P4b; the CLI-internal
  surface is complete.
- **Phase-tree token rollup** (per-phase token totals in the detail
  body) needs P5's budget tracker. The infrastructure (registry
  records, emitter fire sites) is ready for the column when P5 lands.
- **Save / inspect subcommands** (`/workflows save <runId>` to
  materialize a script) are future enhancements; the slash command
  ships with list + detail only.

## Verification

- 223/223 tests pass on the workflow surface — 14 new registry tests,
  6 real-LLM E2E scenarios against qwen3-coder-plus (DashScope),
  plus all existing P3/P4a tests continuing to pass with the new
  emitter wiring.
- 73/73 CLI tests pass across BackgroundTasksPill, BackgroundTasks
  Dialog, useBackgroundTaskView, workflowsCommand.
- `tsc --noEmit` clean (0 P4b errors in core + cli).
- `prettier --check` + `eslint` clean on all touched files.
@LaZzyMan LaZzyMan changed the title feat(core): Workflow P4a — extractAndStripMeta + meta on RunOutcome (#4721) feat(core+cli): Workflow P4 — meta + /workflows + phase-tree (#4721) Jun 15, 2026
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

P4b shipped — full P4 ready for review (c3f9d84)

Heads up @wenshao: P4b is in. PR title + body updated to reflect full P4 scope (P4a + P4b on this same branch).

What P4b adds (commit c3f9d845e, +1285 / -23, 17 files)

  • WorkflowRunRegistry (new) — 4th sibling of BackgroundTaskRegistry / BackgroundShellRegistry / MonitorRegistry. Same register / cancel / get / list / on('statusChange') shape. Eviction MAX_RETAINED_TERMINAL_WORKFLOWS = 10. 14 unit tests.
  • TaskKind widening 'agent' | 'shell' | 'monitor' | 'workflow'. 6 exhaustive kind switches across BackgroundTasksPill, BackgroundTasksDialog (rowLabel + DetailBody), useBackgroundTaskView (entryId), BackgroundTaskViewContext (cancelSelected) updated. Core typecheck + CLI typecheck both clean.
  • WorkflowOrchestratorEmitter — host-side event channel. phaseStarted fires from sandbox safePhase, agentDispatched / agentCompleted fire from orchestrator countedDispatch, logAppended fires from sandbox safeLog. Defensive try/catch on every emit so a subscriber error never bubbles into the script.
  • WorkflowTool wires registryexecute() pre-generates runId, registers the run with WorkflowRunRegistry, builds an emitter closure into the registry's update methods, flips canUpdateOutput to true for live phase-tree rendering. On terminal: registry.complete (success) / registry.fail (script throw) / registry.cancel (signal.aborted — preserves user-intent vs script-bug distinction).
  • WorkflowDetailBody — new inline component in BackgroundTasksDialog.tsx. Renders name + description + status + runtime + current phase + agent counts (M/N) + phase tree (capped at MAX_VISIBLE_PHASES = 20 with +N more above) + log tail (capped at MAX_VISIBLE_LOG_LINES = 10) + error block on failure.
  • /workflows slash command — bare lists active + completed; /workflows <runId> opens detail dump. Gated by Config.isWorkflowsEnabled(). 6 unit tests.
  • PillKIND_NAMES gains workflow, render order shell → agent → monitor → workflow → dream (user-initiated before system-initiated).

Out of scope (queued)

  • ACP daemon protocol widening (acp-bridge bridgeTypes / status / tasksSnapshot) → follow-up PR P4c
  • Per-phase token rollup in WorkflowDetailBody → lands with P5 budget
  • /workflows save <runId> / inspect subcommands → future enhancement
  • Pause / resume keybindings → lands with P6 resume

Verification on c3f9d845e

  • 223/223 core workflow tests pass (14 new registry + 6 real-LLM E2E against qwen3-coder-plus + all existing P1-P4a tests with the new emitter wiring)
  • 73/73 CLI tests pass (Pill / Dialog / useBackgroundTaskView / workflowsCommand)
  • tsc --noEmit clean on core + cli (0 P4b errors)
  • prettier --check + eslint clean on all 17 touched files

Ready for review.

@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

Round 5 triage — fixed in 2af3536, declines explained per thread

R5 produced 20 inline threads on commits `2491911` + `e9ad07683`. Triage:

Fixed (2 Critical)

  • registry integration untested (workflow.ts:155) — fakeConfig() short-circuited the whole registry path. Added 3 tests covering success / failure / pre-aborted-signal in workflow.test.ts using a real WorkflowRunRegistry.
  • orchestrator emitter callbacks untested (workflow-orchestrator.ts:1124) — added 3 tests covering happy-path ordering, agentCompleted error-arg on rejection, defensive try/catch swallowing.

Declined as hostile-provider hardening (1 [Critical] re-graded, R5)

  • Proxy bypass of WeakSet thenable walker (workflow-sandbox.ts:230) — PoC confirmed reproducible (typeof Proxy === 'function' in null-prototyped vm context, walker completes cleanly, unhandled rejection escapes). Re-grading because R3/R4 fixed accidentally-triggerable crashes (dynamic import / cyclic spread are common patterns); R5 Proxy attack requires deliberate trap construction. Defense-in-depth at meta extraction doesn't materially change residual risk for hostile model output (many other crash vectors exist) — the right defense layer is application-level (model trust + Workflow tool permission gate). Full reasoning in the inline reply.

Declined as R5 Suggestions (12)

  • buildLivePhaseTreeDisplay perf — bounded payload, React throttle absorbs emit frequency
  • list() vs getAll() naming — semantic distinction (mutable snapshot vs immutable getter)
  • terminal-transition debug logs — observable via statusChange callback
  • register() overwrite — runId is 8-byte randomBytes, collision negligible
  • post-run mutation of registryEntry.meta — intentional fast-track for meta.name → description
  • entry.error length bound — upstream already strips stack frames
  • WorkflowDetailBody untested — covered by the tmux E2E
  • cancel race — registry.cancel is idempotent
  • makeConfig mock under-stub — covered by registry's own 14 tests + workflow.test.ts additions
  • agentCompleted error arg semantics — same overload as success path
  • React key uniqueness on phase rows — sandbox dedups consecutive identical phases
  • cycle-Promise test variant — same threat-model framing as Proxy bypass

Resolved as noise (4)

Four single-word "test" comments at 05:59 (4-second window) — look like a review-tool artifact, no actionable body.

Verification on 2af3536

  • 231/231 workflow tests pass (was 225; +6 from R5 fixes — 3 registry + 3 emitter)
  • tsc 0, prettier clean
  • Comprehensive reply on each thread explaining decline reason individually

@wenshao

wenshao commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /review

@github-actions

Copy link
Copy Markdown
Contributor
_Qwen Code review request accepted. Review is queued in [workflow run](https://github.com/QwenLM/qwen-code/actions/runs/27538013193)._

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review aborted with an API error before posting comments. See workflow logs.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review aborted with an API error before posting comments. See workflow logs.

Comment thread packages/cli/src/ui/commands/workflowsCommand.ts
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.test.ts
Comment thread packages/cli/src/ui/commands/workflowsCommand.ts
Comment thread packages/cli/src/ui/hooks/useBackgroundTaskView.test.ts
DragonnZhang
DragonnZhang previously approved these changes Jun 15, 2026

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

Workflow P4 implementation: /workflows slash command with list + detail views, phase-tree rendering, workflow run registry (WorkflowRunRegistry), and workflow-sandbox isolation. workflowsCommand gated behind isWorkflowsEnabled feature flag. Comprehensive test coverage (160+ lines for command, orchestrator, registry, sandbox). CI green. LGTM ✅ — claude-opus-4-6 via Qwen Code /review

@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

Round 6 triage + CI status

R6 triage — 4 inline threads, 2 distinct findings, all declined

Both findings flagged at R6 as Suggestion-level:

  • ANSI/control-character sanitization on rendered meta strings (workflowsCommand.ts:11 + :178 — same finding, 2 sites): declined as hostile-provider hardening at the wrong layer. meta.* fields come from author-controlled export const meta = {...} literals; entry.error is bounded post extractErrorMessage. The WorkflowTool permission gate ('ask') means the user reviews the script before approval — the threat model that motivates sanitization for untrusted LLM output / shell output doesn't apply here.
  • Mock no-op vs vi.fn() on workflow registry's setStatusChangeCallback (useBackgroundTaskView.test.ts:99 — same finding, 2 sites): declined as test-coverage gap on already-covered behavior. Registry's own 14 tests at workflow-run-registry.test.ts cover statusChange firing in isolation; adding the integration variant would assert the same behavior twice with no incremental signal.

4 threads replied + resolved.

CI status on 2af353677

  • Lint, Test (ubuntu-latest), Test (windows-latest), Post Coverage Comment, CodeQL — all green
  • Test (macos-latest, Node 22.x) — failed on src/services/cronScheduler.test.ts > durable ownership > takes over via the lock probe after the owner releases the lock with AssertionError: expected [] to include 'probe-job'. This test is unrelated to the workflow surface — it tests CronScheduler durable-lock semantics. The PR touches zero cronScheduler code. The failure mode (timing-dependent lock-probe assertion, macOS-only) is a classic pre-existing flake. Will not chase unless it reproduces on the other test jobs.

Approvals

Workflow surface verification still holds: 231/231 unit tests pass locally, 6/6 real-LLM E2E pass against qwen3-coder-plus, tmux TUI verification covered pill + dialog + /workflows command + live update path.

Comment thread packages/core/src/agents/workflow-run-registry.ts
Comment thread packages/core/src/tools/workflow/workflow.ts
Comment thread packages/core/src/tools/workflow/workflow.ts
Comment thread packages/core/src/agents/workflow-run-registry.ts
Comment thread packages/core/src/config/config.ts
@wenshao

wenshao commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Local runtime verification (real source + real bundle in tmux)

I verified this PR on the merged state (pr-5094 × origin/main, clean merge-tree, merge-base e8342715e) rather than the branch in isolation, driving the real sandbox/orchestrator/registry (no LLM, no mocks of the unit under test) and the real esbuild bundle in tmux against a mock OpenAI provider that emits a genuine workflow tool-call. Result: the P4a meta pipeline (incl. both crash fixes you raised in R3/R4), the P4b registry/emitter, and the /workflows text commands + pill + live updates + gating all work. One non-blocking gap: the interactive phase-tree dialog (WorkflowDetailBody) and the /workflows tip point at a footer-pill focus path that does not exist in the codebase.

What I ran

Layer How Result
P4a meta extraction tsx over real workflow-sandbox.ts 36/36 custom checks
P4b WorkflowRunRegistry tsx over real source 32/32 custom checks
Orchestrator emitter + meta threading + emitter→real-registry e2e built dist, barrel-first to dodge a circular-import TDZ 25/25 custom checks
PR's own suites (core) vitest run registry+sandbox+orchestrator+workflow 225/225
PR's own suites (cli) vitest run workflowsCommand+pill+dialog+hook+loader 84/84
Full ordered build scripts/build.js (tsc --build all pkgs) + esbuild bundle clean
P4b TUI real dist/cli.js in tmux + mock provider workflow tool-call see below

P4a — meta extraction & the two crash fixes (source-level, decisive)

  • Contract + validation: full {name,description,whenToUse,phases[{title,detail,model}]} extracted; source stripped of export const meta; all error strings verbatim (meta.name must be a non-empty string, meta.phases[].title must be a non-empty string, …).
  • R3 — Promise / dynamic-import() in meta no longer crashes the host ✅. A thenable meta value throws meta values must not be Promises (top-level and nested in phases[]), and I registered unhandledRejection/uncaughtException listeners + a tick delay — the host stayed clean (rejectThenablesInMeta neutralises the thenable with .catch()).
  • R4 — cyclic meta no longer stack-overflows ✅. A get self(){return this} getter (what Object.values re-enters) returns valid meta. Control: I replicated the pre-fix unguarded walk on the identical input → RangeError. So the new WeakSet guard is load-bearing, not cosmetic.
  • Realm boundary: meta eval context is null-prototyped — process / require / args all throw ReferenceError; the returned meta, its phases[] array, and each phase entry have host-realm Object.prototype / Array.prototype identity.
  • getMeta() lifecycle: null before run → parsed after success → still carries meta when the body throws after a clean parse → stays null on malformed meta.

P4b — registry, orchestrator emitter, end-to-end

  • Registry: phase-collapse, dispatch/complete counters, log-tail cap (100, keeps tail), complete/fail/cancel one-shot, cancel aborts the controller, eviction at MAX_RETAINED_TERMINAL_WORKFLOWS=10 (oldest-by-endTime first), running-never-evicted, register/statusChange callbacks + throwing-subscriber tolerance.
  • Orchestrator: outcome.meta mirrors the literal; WorkflowExecutionError.meta carries on body-throw; emitter ordering is dispatch(A) → complete(A) → dispatch(B); a throwing subscriber never bubbles into the script; caller-supplied runId honored.
  • e2e: wiring the orchestrator emitter into a real WorkflowRunRegistry exactly as WorkflowTool does, a 3-agent/2-phase run produced 3/3 agents · 2 phases · completed, and the /workflows row formatter rendered it faithfully.

P4b — real TUI in tmux (mock provider emits a real workflow tool-call)

✅ /workflows surfaces in typeahead when enabled (with description)
✅ bare /workflows → "● No workflow runs recorded yet."
✅ workflow tool-call → approval card → runs → tool block renders the full phase-tree JSON
   (meta + phases:[Collect,Summarize] + logs + result:{status:ok,items:3})
✅ /workflows lists completed runs:
     wf_ed804600e6557500  completed  22.1s  pr5094-slow-demo · Execute · 2/2 agents · 2 phases
     wf_755975ce4a70764c  completed   5ms   pr5094-fast-demo · Summarize · 2 phases
✅ /workflows <runId> → detail dump (name/description/whenToUse/status/phases/logs)
✅ LIVE: footer pill shows "1 workflow" mid-run; live JSON shows status:running,
   currentPhase, agentsDispatched/Completed ticking; 2/2 agents proven through the
   REAL subagent-dispatch path (not just the unit emitter)
✅ pill terminal: "2 tasks done"; terminal sort newest-first
✅ gating OFF (no QWEN_CODE_ENABLE_WORKFLOWS): /workflows absent from typeahead,
   submit → "✕ Unknown command: /workflows"

Findings

1. (Non-blocking, but worth a follow-up) The interactive phase-tree dialog + the /workflows tip point at a non-functional path.
The /workflows tip says "focus the Background tasks pill in the footer (use ↓ from an empty composer) and press Enter for the interactive dialog with phase tree…". But:

  • setPillFocused(true) exists nowhere — confirmed in the cli source and in the shipped dist/cli.js (only setPillFocused(false) is present). So pillFocused is always false, the pill's useKeypress is never active, and openDialog() — its only caller — never fires. openDialog() is what sets dialogMode='list', the mode that renders the workflow roster + WorkflowDetailBody.
  • from an empty composer only descends to the agent-only LiveAgentPanel / Arena tab bar (isLiveAgentPanelVisibleEntry returns kind === 'agent'), and that panel's Enter opens detail-from-panel for the selected agent, not the workflow list.

Net: in the shipped binary the new WorkflowDetailBody is effectively unreachable for a workflow, and the tip advertises a path that doesn't work. This is a pre-existing infra gap (base main has the same zero setPillFocused(true)), so it's not a regression — but P4b adds UI into that dialog and a tip pointing at it. The text-mode /workflows / /workflows <id> render the same data and work, so no capability is lost. Suggest either wiring pill focus (e.g. descendFromComposer focuses the pill when entries exist and no live panel/arena is shown) or softening the tip.

2. (Doc nit) WorkflowOrchestrator.run() comment overstates. The comment says it "validates the shape (wf_<hex>)" of a caller-supplied runId, but the code is const runId = req.runId ?? generateRunId(); — any string is accepted unvalidated. Either add the validation or fix the comment.

3. Confirming the triage bot's earlier note — the two extractAndStripMeta tests using identical source ({ name: args.x, description: 'd' }) are duplicates; one can go.

Verdict

Approve / mergeable. P4a + P4b are correct and well-covered, and the two host-crash vectors from your R3/R4 review are genuinely fixed (verified with adversarial controls, not just the happy path). Finding #1 is non-blocking because the /workflows text commands fully substitute, but it's the one thing worth a quick follow-up so the phase-tree dialog you built is actually reachable.

中文版(点击展开)

本地真实运行验证(真实源码 + 真实打包产物 + tmux)

我在合并态pr-5094 × origin/mainmerge-tree 干净合并,merge-base e8342715e)上验证,而非孤立分支;直接驱动真实的 sandbox/orchestrator/registry(无 LLM、被测对象不打桩)以及 tmux 中的真实 esbuild 产物,配一个会发出真正 workflow tool-call 的 mock OpenAI provider。结论:P4a 的 meta 流水线(含你在 R3/R4 提出的两个崩溃修复)、P4b 的 registry/emitter、以及 /workflows 文本命令 + footer pill + 实时更新 + 开关门控全部可用。 一个非阻塞缺口:交互式 phase-tree 对话框WorkflowDetailBody)和 /workflows 的提示语指向一个在代码里根本不存在的 footer-pill 聚焦路径。

跑了什么

方式 结果
P4a meta 提取 tsx 跑真实 workflow-sandbox.ts 36/36 自定义检查
P4b WorkflowRunRegistry tsx 跑真实源码 32/32
Orchestrator emitter + meta 透传 + emitter→真实 registry 端到端 构建后的 dist,先加载 barrel 规避循环依赖 TDZ 25/25
PR 自带用例(core) vitest run 225/225
PR 自带用例(cli) vitest run 84/84
全量有序构建 scripts/build.js(全包 tsc --build)+ esbuild 通过
P4b TUI tmux 跑真实 dist/cli.js + mock provider 见下

P4a — meta 提取与两个崩溃修复(源码级,决定性)

  • 契约 + 校验:完整提取 {name,description,whenToUse,phases[{title,detail,model}]},源码中 export const meta 被剥离,错误信息与上游逐字一致。
  • R3 — meta 里的 Promise / 动态 import() 不再使宿主进程崩溃 ✅。thenable 抛 meta values must not be Promises(顶层与 phases[] 嵌套都覆盖);我挂了 unhandledRejection/uncaughtException 监听并延迟一个 tick——宿主保持干净(rejectThenablesInMeta.catch() 把 thenable 标记为已处理)。
  • R4 — 环状 meta 不再栈溢出 ✅。get self(){return this}Object.values 会重入)返回合法 meta。对照实验:我用修复前未加保护的遍历跑同一输入 → RangeError。所以新加的 WeakSet 是实打实起作用的,不是摆设。
  • realm 边界:meta 求值上下文是 null 原型——process/require/args 全部 ReferenceError;返回的 meta、其 phases[] 数组、每个 phase 元素都是宿主 realmObject.prototype/Array.prototype
  • getMeta() 生命周期:run 前 null → 成功后为解析值 → 正文在干净解析之后抛错时仍带着 meta → meta 非法时保持 null

P4b — registry、orchestrator emitter、端到端

  • Registry:phase 折叠、dispatch/complete 计数、日志尾部封顶(100,保留尾部)、complete/fail/cancel 一次性、cancel 触发 controller abort、MAX_RETAINED_TERMINAL_WORKFLOWS=10 淘汰(按 endTime 最旧先淘汰)、running 永不淘汰、注册/状态变更回调 + 抛异常订阅者的容错。
  • Orchestrator:outcome.meta 镜像字面量;正文抛错时 WorkflowExecutionError.meta 携带;emitter 顺序为 dispatch(A) → complete(A) → dispatch(B);订阅者抛异常不会冒泡进脚本;调用方传入的 runId 被采用。
  • 端到端:完全按 WorkflowTool 的接线,把 orchestrator emitter 接到真实 WorkflowRunRegistry,3-agent/2-phase 跑出 3/3 agents · 2 phases · completed/workflows 行格式化忠实呈现。

P4b — tmux 真实 TUI(mock provider 发出真正的 workflow tool-call)

✅ 开启时 /workflows 出现在命令补全(带描述)
✅ 裸 /workflows → "● No workflow runs recorded yet."
✅ workflow tool-call → 审批卡 → 运行 → 工具结果块渲染完整 phase-tree JSON
   (meta + phases:[Collect,Summarize] + logs + result:{status:ok,items:3})
✅ /workflows 列出已完成运行(含 name·phase·agents·phases)
✅ /workflows <runId> → 详情(name/description/whenToUse/status/phases/logs)
✅ 实时:运行中 footer pill 显示 "1 workflow";实时 JSON 显示 status:running、
   currentPhase、agentsDispatched/Completed 递增;2/2 agents 是经由**真实子代理派发**路径验证的
✅ pill 终态:"2 tasks done";终态按最新优先排序
✅ 门控关闭(不设 QWEN_CODE_ENABLE_WORKFLOWS):补全里没有 /workflows,
   提交 → "✕ Unknown command: /workflows"

发现

1.(非阻塞,但建议后续修)交互式 phase-tree 对话框 + /workflows 提示语指向一个不存在的路径。
提示语说“聚焦 footer 的 Background tasks pill(空输入框按 ↓)再按 Enter 进入带 phase tree 的交互对话框”。但是:

  • setPillFocused(true) 在代码里根本不存在——cli 源码与打包后的 dist/cli.js 都只有 setPillFocused(false)。所以 pillFocused 恒为 false,pill 的 useKeypress 永不激活,openDialog()(它唯一的调用方)永不触发;而 openDialog() 正是把 dialogMode 置为 'list'、从而渲染 workflow 列表 + WorkflowDetailBody 的入口。
  • 空输入框按 只会下沉到仅限 agentLiveAgentPanel / Arena tab bar(isLiveAgentPanelVisibleEntry 返回 kind === 'agent'),其 Enter 打开的是选中子代理detail-from-panel,不是 workflow 列表。

即:发布产物里新加的 WorkflowDetailBody 对 workflow 实际上不可达,提示语指向一个走不通的路径。这是 既有 基础设施的缺口(base main 同样 setPillFocused(true) 计数为 0),不是回归——但 P4b 往这个对话框里加了 UI 并加了指向它的提示语。文本版 /workflows / /workflows <id> 呈现同样的数据且可用,没有功能损失。建议要么接通 pill 聚焦(例如 descendFromComposer 在有条目且无 live panel/arena 时聚焦 pill),要么弱化提示语。

2.(文档小疵)WorkflowOrchestrator.run() 注释言过其实。 注释说它会“校验形状 wf_<hex>”,但代码是 const runId = req.runId ?? generateRunId();——任意字符串都被原样接受。要么补上校验,要么改注释。

3. 印证 triage bot 早先的提示——extractAndStripMeta 里两个用例源码相同({ name: args.x, description: 'd' }),重复,可删其一。

结论

同意合并 / 可合并。 P4a + P4b 实现正确、覆盖充分,你在 R3/R4 评审里提出的两个宿主崩溃向量都已真正修复(用对照实验验证,不只是 happy path)。发现 #1 非阻塞(/workflows 文本命令完全可替代),但它是值得一个快速后续修复的点——好让你做的 phase-tree 对话框真正可达。


Verification harnesses, mock provider, and tmux captures kept under /root/wt/run5094. Methodology: real source via tsx for the unit-under-test, built dist for the circular-dep-heavy orchestrator, full esbuild bundle for the TUI; merged-state worktree so this reflects what landing produces.

)

Wenshao's R7 review (with real build + tmux verification on the
merged state) approved the PR but surfaced 6 valid findings. All
fixed, all RED-first tested, all verified end-to-end against
qwen3-coder-plus via DashScope.

## 1. Dialog-cancel drops accumulated logs (Critical)

`registry.setRecentLogs(...)` previously guarded `status === 'running'`
only. Dialog-initiated cancel marks `status='cancelled'` synchronously
BEFORE the tool's catch arm tries to write logs — so cancelled runs
always showed an empty Logs section in the dialog. Allow the write
after a `'cancelled'` transition too; keep `'completed'` and `'failed'`
as final-state rejects. 2 regression tests: cancel-then-logs-still-
writes, and complete/fail-still-reject.

## 2. WorkflowRunRegistry missing session-reset wiring (Critical)

Sibling drift miss from P4b: `BackgroundTaskRegistry` /
`BackgroundShellRegistry` / `MonitorRegistry` all exposed `reset()` +
`abortAll()`, and `backgroundWorkUtils` (`hasBlockingBackgroundWork`,
`resetBackgroundStateForSessionSwitch`) wired all three. `Workflow
RunRegistry` had neither. Result: `/clear` and session-resume ran
while a workflow was mid-run (orphaned dispatch loop), and terminal
rows leaked from session to session in the pill / dialog /
`/workflows` list.

Added `hasRunningEntries()`, `reset()` (drops entries, no controller
touch), `abortAll()` (cancels every running entry + aborts its
controller). Wired into both `backgroundWorkUtils` helpers + updated
their tests for the 4-sibling shape.

## 3. Phase dedup inconsistency — sandbox vs registry (Critical)

`phase('X'); phase('X')` previously yielded `outcome.phases = ['X','X']`
(sandbox `safePhase` unconditional push) but `entry.phases = ['X']`
(registry `onPhaseStarted` collapsed). The same run showed different
phase counts in the terminal `returnDisplay` JSON vs the live UI.
The `agent({phase})` wrapper already deduped (`__b.lastPhase()`); my
docstring on `safePhase` claimed it deduped too, but it didn't.

Fix at the sandbox layer (single source of truth): `safePhase` skips
when `phases[last] === t`. Registry-side dedup is now redundant but
harmless (defense in depth, doesn't double-collapse). Updated test
in workflow-sandbox.test.ts pins
`phase('X'); phase('X'); phase('Y'); phase('X')` → `['X','Y','X']`.

## 4. /workflows tip pointed at non-functional path (UX/docs)

`/workflows` tip text said *"focus the Background tasks pill in the
footer (use ↓ from an empty composer) and press Enter for the
interactive dialog with phase tree + live updates."* But
`setPillFocused(true)` doesn't exist anywhere in the codebase
(confirmed by wenshao's grep, and reproducible on my own tmux runs
where `↓ Enter` never opened the dialog — I previously misattributed
to a tmux limitation). The dialog IS reachable through other paths
but the tip's specific instructions are wrong.

Soften the tip to point at the actually-working text-mode detail
view: `Tip: use /workflows <runId> for the per-run detail view
(name, description, phase tree, recent logs).` — same information,
working instructions.

## 5. `runId` validation comment was aspirational (docs)

Comment on `workflow-orchestrator.ts` `run()` claimed *"validates
the shape (`wf_<hex>`)"* but the code is `const runId = req.runId
?? generateRunId();` — no validation. Caller (`WorkflowTool`) does
use the same `wf_<8hex>` generator as `generateRunId()`, so the
behavior is safe in practice. Fixed the comment to describe what
the code actually does (trusts the caller, no validation).

## 6. Duplicate extractAndStripMeta test (test hygiene)

Two tests at workflow-sandbox.test.ts:227 and :242 used identical
source `{ name: args.x, description: 'd' }` — copilot R1 originally
flagged this, I declined as bot finding, wenshao re-confirmed. The
intent was to pin two distinct things: (a) generic unknown
identifier throws, (b) the bridge global `args` specifically is
not reachable. Updated the first test to use `totallyUnknown` (a
genuine unknown name) and kept the second as the explicit `args`
regression — now the two tests pin different things.

## Verification

- 231/231 core workflow tests pass (registry + sandbox + orchestrator
  + tool) — +6 new from R7 RED-first regression tests
- 81/81 CLI ripple tests pass (pill + dialog + hook + command +
  backgroundWorkUtils)
- tsc 0 errors on core + cli (after rebuilding core dist for the
  new registry methods)
- prettier + eslint clean on all touched files
- **tmux re-verified end-to-end** against qwen3-coder-plus via
  DashScope on a fresh `npm run bundle`:
  - Phase dedup: `phase("Phase A"); phase("Phase A")` →
    `outcome.phases = ["Phase A", "Phase B"]` (was `["Phase A",
    "Phase A", "Phase B"]` pre-fix) — confirmed both in the tool
    result JSON AND in `/workflows wf_xxx · 2 phases`
  - New `/workflows` tip text rendered as expected, no more
    advertising broken pill focus path
  - `/workflows <runId>` detail dump still works: name, status,
    runtime, phases tree, agent counts
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

Round 7 triage — 6 fixes in b53bc4e, tmux re-verified

Wenshao's R7 review (real build + bundle + tmux verification on the merged state) approved the PR but surfaced 9 substantive findings (6 inline + 3 in the verification verdict). All fixes landed in b53bc4efb + tmux re-verified end-to-end.

Fixed (6)

# Source File Fix
1 inline JkH_f (Critical) workflow-run-registry.ts:209 Allowed setRecentLogs after 'cancelled' transition; 2 RED-first tests
2 inline Ju-Fy (Suggestion → consistency) workflow-sandbox.ts:624 Moved phase dedup to sandbox so outcome.phases + entry.phases agree by construction; tmux confirmed phase("Phase A") × 2["Phase A", "Phase B"]
3 inline Ju-F0 (Suggestion → session leak) config.ts + backgroundWorkUtils.ts Added reset/abortAll/hasRunningEntries to WorkflowRunRegistry, wired into 4-sibling backgroundWorkUtils
4 verification #1 (UX/docs) workflowsCommand.ts:154 Softened tip — now points at /workflows <runId> instead of advertising non-existent pill focus path
5 verification #2 (docs) workflow-orchestrator.ts:1080 Fixed "validates the shape" comment to describe actual no-validation behavior
6 verification #3 (test hygiene) workflow-sandbox.test.ts:227 First duplicate now uses totallyUnknown (unknown identifier shape); second still pins the args bridge-global shape

Declined (3)

  • inline JkH_w — metaExtracted emitter callback: ergonomic R7 Suggestion, deferred to future emitter expansion PR
  • inline JkH_1 — updateOutput vi.fn() test: covered by tmux real-LLM E2E, would lock in rendered shape without catching real bugs
  • inline JkH_3 — pill workflowEntry helper: covered by tmux runs that already verified pill render with workflow kind

Re-verification on b53bc4e

231/231 core workflow tests pass        (+6 from R7 RED-first regression tests)
81/81 CLI ripple tests pass
tsc 0 errors on core + cli
prettier clean

tmux real-LLM (qwen3-coder-plus via DashScope) on fresh npm run bundle:
  ✅ phase dedup: phase("Phase A"); phase("Phase A") → outcome.phases = ["Phase A", "Phase B"]
                  /workflows shows · 2 phases · (not 3)
  ✅ /workflows tip text:
     "Tip: use /workflows <runId> for the per-run detail view (name, description, phase tree, recent logs)."
  ✅ /workflows <runId> detail dump still works (status, runtime, phases tree, agent counts)
  ✅ pill mid-run + post-terminal as before

The unit test in workflow-run-registry.test.ts pins the setRecentLogs
guard widening in isolation. This integration test stands up the full
production wiring — real WorkflowTool, real WorkflowRunRegistry, real
sandbox, real emitter — and reproduces the exact dialog-cancel race
that the R7 fix targets:

1. Start execute() with a controllable dispatch that hangs until
   externally rejected.
2. Wait for the run to register + the dispatch to be in flight + at
   least one log() call to have accumulated.
3. Simulate the dialog: call registry.cancel(runId) directly. This
   is the exact entry point cancelSelected() uses in
   BackgroundTaskViewContext.cancelSelected for kind='workflow'.
4. Cascade the dispatch rejection (the production path: the registry's
   abortController abort propagates through dispatchController → the
   orchestrator's limiter → the in-flight dispatch).
5. Await execute() — the tool's catch arm runs setRecentLogs with the
   accumulated logs.
6. Assert: status='cancelled' AND recentLogs contains the script's
   log('before agent dispatch') entry.

RED→GREEN verified: temporarily reverted the setRecentLogs guard to
the pre-R7 single-state form, the test failed with
`AssertionError: expected 0 to be greater than 0` (recentLogs was
empty because the guard rejected). Restored fix, test passes.

Production reachability note: the dialog itself is not currently
reachable through the TUI pill focus chain (setPillFocused(true)
does not exist anywhere in the codebase — wenshao R7 verification
finding #1, pre-existing infra gap out of P4 scope). This
integration test is the closest available real-scenario
verification for the fix without modifying out-of-scope code; the
test drives the EXACT registry.cancel + dispatch rejection +
catch-arm sequence the dialog would trigger.
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

Full R7 real-scenario E2E verification

Followed up on the previous E2E summary by running the remaining real-scenario tests for fixes #1 (cancel-drops-logs) and #3 (session-reset).

#3 — `/clear` resets workflow registry (tmux verified)

  1. Ran a workflow against `qwen3-coder-plus` via DashScope, completed successfully (`wf_249d040e98ec8c59`)
  2. `/workflows` showed: `Workflow runs (1 total · 0 running) → Recent → wf_249d040e98ec8c59 completed 3.1s · plan · 1/1 agents · 1 phase`
  3. Issued `/clear` — pill dropped from `1 task done` to clean
  4. `/workflows` after `/clear` showed: `No workflow runs recorded yet.` ✅

Confirms WorkflowRunRegistry.reset() is wired into resetBackgroundStateForSessionSwitch and the session boundary is honored.

#1 — Dialog-cancel preserves logs (integration test, commit aa62afa)

The dialog itself is not currently reachable through the TUI pill focus chain — wenshao R7 verification finding #1 noted that `setPillFocused(true)` does not exist anywhere in the codebase (pre-existing infra gap, out of P4 scope and explicitly marked as such). So a literal tmux dialog cancel cannot be triggered without modifying out-of-scope code.

To get the closest possible real-scenario verification, I added an integration test (`R7: dialog-cancel race during run`) in workflow.test.ts that drives the EXACT production code path the dialog cancel would trigger:

  • Real WorkflowTool + real WorkflowRunRegistry + real sandbox + real emitter wiring (configWithRegistry helper)
  • Script calls `log('before agent dispatch')` then `await agent(...)` against a controllable dispatch
  • Mid-flight, the test calls `registry.cancel(runId)` — the exact entry point cancelSelected() uses in BackgroundTaskViewContext for kind='workflow'
  • The in-flight dispatch is then rejected (cascading from controller abort)
  • Awaiting execute() runs the tool's catch arm with setRecentLogs(runId, logs)
  • Assertion: status='cancelled' AND recentLogs contains the script's log() output

RED→GREEN verified by temporarily reverting the setRecentLogs guard:

  • Pre-R7 guard (`status === 'running'` only) → `AssertionError: expected 0 to be greater than 0` (recentLogs empty, bug reproduces)
  • Post-R7 guard (`status === 'running' || status === 'cancelled'`) → test passes, recentLogs preserved

Final verification on aa62afa

  • 232/232 core workflow tests pass (+1 from new integration test)
  • 81/81 CLI ripple tests pass
  • tsc 0 errors on core + cli
  • prettier clean
  • tmux verified: phase dedup, /workflows tip, /workflows listing + detail, `/clear` clears workflow registry ← previously skipped
  • Integration test verified: dialog-cancel race preserves logs ← previously only unit-tested in isolation

All 6 R7 valid findings now have a real-scenario verification (tmux for the user-facing surfaces, integration test for the dialog-cancel race that the production dialog can't currently trigger via the TUI).

* after the loop — the per-entry `cancel()` path would have fired
* the callback for every running entry, wasteful on shutdown.
*/
abortAll(): void {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] abortAll() is added, documented as "Called on session/Config shutdown so workflow runs don't outlive the CLI process and leak orphaned dispatches", and unit-tested — but it has no production caller. Its three sibling registries are aborted on shutdown; the workflow registry is not:

  • config/config.ts:2917-2919 (shutdown()) aborts task/monitor/shell but omits this.workflowRunRegistry.abortAll(). This is the site the earlier config.ts review (CHANGES_REQUESTED) asked to wire.
  • nonInteractive/session.ts:666-670 (abortTaskRegistries(), the headless/serve teardown — 4 call sites) likewise omits it. Unlike /clear + resume, this path has no hasBlockingBackgroundWork gate, so a still-running workflow's abortController is never signaled and its orchestrator dispatch loop is genuinely orphaned.

The sibling fixes in this commit — reset() + hasRunningEntries() — were correctly wired into backgroundWorkUtils.ts, but abortAll() (the third method added here) was wired nowhere, so the docstring's "called on shutdown" contract is currently aspirational.

// config/config.ts shutdown(), after line 2919:
this.workflowRunRegistry.abortAll();

// nonInteractive/session.ts abortTaskRegistries(), alongside the three siblings:
this.config.getWorkflowRunRegistry().abortAll();

— claude-opus-4-8[1m] via Qwen Code /qreview

…mand mocks (#4721)

CI fix for b53bc4e (the R7 fix commit).

R7 (commit b53bc4e) wired WorkflowRunRegistry's new reset() /
abortAll() / hasRunningEntries() methods into backgroundWorkUtils.ts
(hasBlockingBackgroundWork + resetBackgroundStateForSessionSwitch).
clearCommand.ts and useResumeCommand.ts call both utils, but their
mock configs didn't stub getWorkflowRunRegistry — so once the util
started calling it, every clearCommand test threw
`TypeError: config.getWorkflowRunRegistry is not a function`. CI
ubuntu/macos/windows × 10 tests × clearCommand.test.ts went red.

This is the same sibling-drift miss as the BuiltinCommandLoader fix
in 2491911 (R7 pre-cursor): I added a new Config method, every
existing mock that ships a Config-shaped object goes stale until
stubbed.

Fix: add the same `getWorkflowRunRegistry` stub shape to:
- clearCommand.test.ts: 3 sites (default mock + non-interactive mock
  + blocked-background mock)
- useResumeCommand.test.ts: 4 sites (all 4 mock configs)

Stub shape mirrors the 3 sibling registries' interfaces exposed via
backgroundWorkUtils: `hasRunningEntries`, `reset`, `abortAll`.
Returns false / vi.fn() so default behavior matches "no workflow
running" + "reset is observable". Existing tests that exercise the
blocked-background path (hasUnfinalizedTasks: true) keep working
because workflow's hasRunningEntries=false still allows the
agent-side block to trigger.

Verification: 24/24 in clearCommand+useResumeCommand pass locally;
the 7-file P4 + impacted suite pass 105/105 (registries + commands +
hooks + dialog + pill + workflowsCommand + backgroundWorkUtils).
@LaZzyMan

Copy link
Copy Markdown
Collaborator Author

CI fix — 7b0ea82

The Test job (×3 OS) was red on b53bc4efb for the same sibling-drift pattern as the earlier 2491911 fix. R7 wired WorkflowRunRegistry.reset()/abortAll()/hasRunningEntries() into backgroundWorkUtils.ts (hasBlockingBackgroundWork + resetBackgroundStateForSessionSwitch). clearCommand.ts and useResumeCommand.ts call both utils, but their mock configs didn't stub getWorkflowRunRegistry — so every clearCommand test threw TypeError: config.getWorkflowRunRegistry is not a function. 10 tests × 3 OS red for this single missing-mock reason.

Fix: added the same stub shape (hasRunningEntries, reset, abortAll) to the 7 affected mock sites (3 in clearCommand.test.ts, 4 in useResumeCommand.test.ts). Default returns false / vi.fn() so existing tests are behaviorally unchanged.

Verification:

  • 24/24 clearCommand + useResumeCommand pass
  • 105/105 P4 + impacted CLI suite pass

aa62afa CI run (from before this fix push) — still in progress; new CI on 7b0ea82 starting.

@wenshao

wenshao commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

✅ Local real-build verification (maintainer)

I built this PR from source and exercised it in the real qwen TUI (tmux), on top of the full automated suite plus a mutation check. Posting as a merge reference.

Setup

  • Worktree at PR HEAD aa62afa581 (R7 — note the branch has iterated past the R3 the description was written against; I verified the latest).
  • npm ci && npm run build0 errors (15 pre-existing lint warnings only). Ran node packages/cli/dist/index.js (qwen v0.18.0).
  • Live runs: qwen3.7-max, YOLO mode, QWEN_CODE_ENABLE_WORKFLOWS=1.

1. Automated tests — all green

core: 4 files, 232 passed   (workflow-run-registry 19 · workflow 25 · workflow-orchestrator 81 · workflow-sandbox 107)
cli : 6 files,  92 passed   (useBackgroundTaskView 16 · workflowsCommand 6 · BackgroundTasksPill 19 ·
                             backgroundWorkUtils 8 · BuiltinCommandLoader 11 · BackgroundTasksDialog 32)
TOTAL: 324 passed, 0 failed

2. Mutation test — the new tests are not vacuous

Injected name: obj['name']name: 'MUTANT' in validateMeta (workflow-sandbox.ts), re-ran the extractAndStripMeta suite:

× extracts the required name + description fields  → expected 'MUTANT' to deeply equal 'demo'
× extracts optional whenToUse + phases array       → expected 'MUTANT' to deeply equal 'multi'
× rejects a cyclic meta value (spread)             → expected 'MUTANT' to deeply equal 'x'
× rejects a cyclic meta value (nested)             → expected 'MUTANT' to deeply equal 'x'
✓ throws "meta.name must be a non-empty string"    (error-path tests correctly unaffected)

4 happy-path tests fail on the wrong value, the error-message tests stay green → the meta-extraction tests genuinely assert extracted values. Source restored afterward (clean tree).

3. Real-TUI verification (tmux, real binary)

Feature gating (deterministic, no LLM):

Condition /work typeahead /workflows
QWEN_CODE_ENABLE_WORKFLOWS=1 workflows [runId] List active and completed workflow runs… works
QWEN_CODE_DISABLE_WORKFLOWS=1 (kill switch) (no suggestion) ✕ Unknown command: /workflows

Empty / error paths (deterministic):

  • /workflows on empty registry → ● No workflow runs recorded yet.
  • /workflows wf_doesnotexist✕ Unknown workflow runId: wf_doesnotexist

Live lifecycle (model drove the workflow tool with a verbatim script):

Running state — meta + 2 phases + 2 agent() calls. Captured live:

╭ Workflow  Run a workflow script (350 chars) ──────────────────────╮
│  { "runId": "wf_bb29bb61e539021d", "status": "running",           │
│    "currentPhase": "collect", "phases": ["collect"],              │
│    "agentsDispatched": 1, "agentsCompleted": 0 }                  │
╰───────────────────────────────────────────────────────────────────╯
  YOLO mode … · 1 workflow          ← footer pill, P4b workflow count

Cancel path — pressed Esc; the run went to cancelled (not failed), confirming the signal.aborted → cancel design:

> /workflows
  Workflow runs (1 total · 0 running)
  Recent
    wf_bb29bb61e539021d  cancelled  5m 32s  P5094Verify · collect · 1/1 agents · 1 phase

> /workflows wf_bb29bb61e539021d
  Workflow wf_bb29bb61e539021d
    name        : P5094Verify
    description : PR5094 smoke test      ← P4a meta extraction, end-to-end
    status      : cancelled
    currentPhase: collect
    agents      : 1/1
    Phases (1) · collect
    Logs (last 1)  started collect

(The long runtime was idealab endpoint latency, not the registry — agentsCompleted ticked 0→1 exactly as I cancelled, i.e. the subagent had just finished.)

Completed state — a no-agent() script (instant, isolates the registry/meta path from subagent latency):

╭ ✓ Workflow  Run a workflow script (237 chars) ────────────────────╮
│  "meta": { "name": "P5094Done", "description": "no-agent completed │
│            run", "whenToUse": "smoke",                             │
│            "phases": [{"title":"alpha"},{"title":"beta"}] },       │
│  "phases": ["alpha","beta"], "logs": ["entered alpha","entered    │
│   beta"], "result": { "ok": true }                                │
╰───────────────────────────────────────────────────────────────────╯

> /workflows
  Workflow runs (2 total · 0 running)
  Recent
    wf_6d4453f8332eae3e  completed     4ms  P5094Done · beta · 2 phases
    wf_bb29bb61e539021d  cancelled  5m 32s  P5094Verify · collect · 1/1 agents · 1 phase

This confirms end-to-end: P4a meta extraction (name/description/whenToUse/phases surfaced) and P4b registry lifecycle (runningcancelled/completed), terminal retention + endTime DESC ordering, the live canUpdateOutput JSON snapshot, and the footer pill count (1 workflow running → 2 tasks done terminal).


⚠️ One non-blocking observation (pre-existing, not introduced by this PR)

I could not open the interactive BackgroundTasksDialog list mode from the keyboard, so the in-dialog phase-tree UI for a workflow row couldn't be exercised live. Tracing it:

  • openDialog() (list mode, the only view that renders workflow rows) is called only from BackgroundTasksPill's keypress handler, which is active only when pillFocused === true.
  • setPillFocused(true) has no non-test callers in the build; the composer→panel→tab-bar focus chain (InputPrompt / AgentTabBar) never routes to the pill (AgentTabBar's Down is an explicit no-op — "the tab bar is the bottom of the chain"). The pill's own comment (Composer ↓ → AgentTabBar ↓ → Pill ↓ → Dialog) looks stale.
  • The LiveAgentPanel → Enter path opens detail-from-panel, which only shows kind === 'agent' entries and exits straight back — it never reaches workflow rows.

Why it doesn't block P4: the diff doesn't touch InputPrompt.tsx / AgentTabBar.tsx / the focus chain; this is the dialog-open mechanism that predates the PR. The dialog's workflow rendering is covered by the 32 BackgroundTasksDialog unit tests, and the identical data is fully inspectable via /workflows / /workflows <runId> (verified above). Worth a separate look at whether the pill is meant to be focusable — the /workflows description ("interactive dialog opens via the footer pill") currently doesn't hold for the keyboard path.

Verdict

P4a + P4b behave correctly in the real binary; 324/324 tests pass and the meta tests are non-vacuous. Verified — good to merge from my side, with the dialog-reachability gap tracked separately as pre-existing.

中文版

✅ 本地真实构建验证(维护者)

我从源码构建了本 PR,并在真实 qwen TUI(tmux)中实跑,外加完整自动化测试与一次变异测试。作为合并参考发布。

环境

  • worktree 检出在 PR HEAD aa62afa581(R7 —— 注意分支已迭代到 PR 描述所基于的 R3 之后,我验证的是最新版)。
  • npm ci && npm run build0 error(仅 15 个既有 lint 警告)。运行 node packages/cli/dist/index.js(qwen v0.18.0)。
  • 实时运行:qwen3.7-max、YOLO 模式、QWEN_CODE_ENABLE_WORKFLOWS=1

1. 自动化测试 —— 全绿

core:4 文件 232 通过  (workflow-run-registry 19 · workflow 25 · workflow-orchestrator 81 · workflow-sandbox 107)
cli :6 文件  92 通过  (useBackgroundTaskView 16 · workflowsCommand 6 · BackgroundTasksPill 19 ·
                       backgroundWorkUtils 8 · BuiltinCommandLoader 11 · BackgroundTasksDialog 32)
合计:324 通过,0 失败

2. 变异测试 —— 新测试非空过

validateMeta(workflow-sandbox.ts)注入 name: obj['name']name: 'MUTANT',重跑 extractAndStripMeta 套件:

× extracts the required name + description fields  → expected 'MUTANT' to deeply equal 'demo'
× extracts optional whenToUse + phases array       → expected 'MUTANT' to deeply equal 'multi'
× rejects a cyclic meta value (spread)             → expected 'MUTANT' to deeply equal 'x'
× rejects a cyclic meta value (nested)             → expected 'MUTANT' to deeply equal 'x'
✓ throws "meta.name must be a non-empty string"    (错误路径测试不受影响,正确)

4 个 happy-path 测试因取值错误而失败,错误消息测试保持绿色 → meta 提取测试确实在校验提取出的值。验证后已还原源码(工作树干净)。

3. 真实 TUI 验证(tmux,真实二进制)

特性门控(确定性,无需 LLM):

条件 /work typeahead /workflows
QWEN_CODE_ENABLE_WORKFLOWS=1 workflows [runId] List active and completed workflow runs… 正常
QWEN_CODE_DISABLE_WORKFLOWS=1(杀死开关) (无建议) ✕ Unknown command: /workflows

空 / 错误路径(确定性):

  • 空注册表执行 /workflows● No workflow runs recorded yet.
  • /workflows wf_doesnotexist✕ Unknown workflow runId: wf_doesnotexist

实时生命周期(模型以 verbatim 脚本驱动 workflow 工具):

运行态 —— meta + 2 phases + 2 个 agent(),实时捕获:

╭ Workflow  Run a workflow script (350 chars) ──────────────────────╮
│  { "runId": "wf_bb29bb61e539021d", "status": "running",           │
│    "currentPhase": "collect", "phases": ["collect"],              │
│    "agentsDispatched": 1, "agentsCompleted": 0 }                  │
╰───────────────────────────────────────────────────────────────────╯
  YOLO mode … · 1 workflow          ← 底栏 pill,P4b 的 workflow 计数

取消路径 —— 按 Esc;该运行进入 cancelled(而非 failed),验证了 signal.aborted → cancel 的设计:

> /workflows
  Workflow runs (1 total · 0 running)
  Recent
    wf_bb29bb61e539021d  cancelled  5m 32s  P5094Verify · collect · 1/1 agents · 1 phase

> /workflows wf_bb29bb61e539021d
  Workflow wf_bb29bb61e539021d
    name        : P5094Verify
    description : PR5094 smoke test      ← P4a meta 提取,端到端
    status      : cancelled
    currentPhase: collect
    agents      : 1/1
    Phases (1) · collect
    Logs (last 1)  started collect

(超长 runtime 是 idealab 端点延迟,不是 registry —— agentsCompleted 在我取消的瞬间恰好 0→1,即子 agent 刚跑完。)

完成态 —— 一个无 agent() 的脚本(瞬时完成,把 registry/meta 路径与子 agent 延迟隔离开):

╭ ✓ Workflow  Run a workflow script (237 chars) ────────────────────╮
│  "meta": { "name": "P5094Done", "description": "no-agent completed │
│            run", "whenToUse": "smoke",                             │
│            "phases": [{"title":"alpha"},{"title":"beta"}] },       │
│  "phases": ["alpha","beta"], "logs": ["entered alpha","entered    │
│   beta"], "result": { "ok": true }                                │
╰───────────────────────────────────────────────────────────────────╯

> /workflows
  Workflow runs (2 total · 0 running)
  Recent
    wf_6d4453f8332eae3e  completed     4ms  P5094Done · beta · 2 phases
    wf_bb29bb61e539021d  cancelled  5m 32s  P5094Verify · collect · 1/1 agents · 1 phase

由此端到端确认:P4a meta 提取(name/description/whenToUse/phases 均被呈现)与 P4b registry 生命周期(runningcancelled/completed)、终态留存 + endTime 倒序、实时 canUpdateOutput JSON 快照,以及底栏 pill 计数(运行中 1 workflow → 终态 2 tasks done)。


⚠️ 一处非阻塞观察(先于本 PR 存在,本 PR 引入)

我无法用键盘打开交互式 BackgroundTasksDialoglist 模式,因此对话框内某条 workflow 行的 phase-tree UI 没法实跑。溯源:

  • openDialog()(list 模式,唯一渲染 workflow 行的视图)BackgroundTasksPill 的 keypress 处理器调用,而后者仅在 pillFocused === true 时激活。
  • setPillFocused(true) 在 build 中无任何非测试调用;composer→panel→tab-bar 的焦点链(InputPrompt / AgentTabBar)从不路由到 pill(AgentTabBar 的 Down 是显式 no-op —— "tab bar is the bottom of the chain")。pill 自己的注释(Composer ↓ → AgentTabBar ↓ → Pill ↓ → Dialog)看起来已过时。
  • LiveAgentPanel → Enter 走的是 detail-from-panel,只显示 kind === 'agent' 条目且退出即关,触不到 workflow 行。

为何不阻塞 P4: diff 没有改动 InputPrompt.tsx / AgentTabBar.tsx / 焦点链;这是先于本 PR 的对话框开启机制。对话框的 workflow 渲染由 32 个 BackgroundTasksDialog 单测覆盖,且同样的数据可通过 /workflows / /workflows <runId> 完整查看(上文已验证)。建议另行确认 pill 是否本该可聚焦 —— /workflows 的描述("interactive dialog opens via the footer pill")目前在键盘路径上并不成立。

结论

P4a + P4b 在真实二进制中行为正确;324/324 测试通过且 meta 测试非空过。已验证 —— 我这边可以合并,对话框可达性的缺口作为先存问题单独跟踪。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review aborted with an API error before posting comments. See workflow logs.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully: Qwen review aborted with an API error before posting comments. See workflow logs.

@wenshao

wenshao commented Jun 16, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at 7b0ea82. Local ground truth is green — tsc --noEmit, ESLint and Prettier all clean; 232 core + 73 CLI workflow tests pass. The only red check is review-pr (the Qwen-review-bot aborting on an API error, not a code failure), so this is a Comment, not a block.

One net-new Suggestion inline below. Separately, the still-open finding at workflow-run-registry.ts:321abortAll() has no production caller — is unaddressed at this HEAD: Config.shutdown() (config.ts:2917-2919) calls abortAll() on the three sibling registries but not workflowRunRegistry, so a workflow still running at process shutdown is never aborted. reset() and hasRunningEntries() are both wired in; only abortAll() is dangling. (Largely inert today since hasBlockingBackgroundWork() gates /clear + resume, but the shutdown asymmetry with the siblings is real.)

中文

7b0ea82 上复核。本地基线全绿——tsc --noEmit、ESLint、Prettier 均干净;232 个 core + 73 个 CLI workflow 测试通过。唯一的红色检查是 review-pr(Qwen review 机器人因 API 错误中止,并非代码失败),因此判定为 Comment 而非阻断。

下方一条全新的 inline Suggestion。另外,workflow-run-registry.ts:321 处仍未解决的发现——abortAll() 没有生产调用方——在当前 HEAD 依旧存在:Config.shutdown()(config.ts:2917-2919)对三个兄弟 registry 调用了 abortAll(),唯独漏了 workflowRunRegistry,因此进程关闭时仍在运行的 workflow 永远不会被 abort。reset()hasRunningEntries() 都已接线;只有 abortAll() 悬空。(今天大体无害,因为 hasBlockingBackgroundWork() 拦住了 /clear 与 resume,但与兄弟 registry 在 shutdown 上的不对称是真实存在的。)

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

function buildLivePhaseTreeDisplay(entry: WorkflowTask): string {
const payload: Record<string, unknown> = {
runId: entry.runId,
...(entry.meta ? { meta: entry.meta } : {}),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] buildLivePhaseTreeDisplay spreads the entire entry.meta into the payload it JSON.stringifys on every emitter tick (phaseStarted / agentDispatched / agentCompletedsafeEmitUpdate). meta is immutable for the whole run, so re-serializing it on every event is redundant work that grows with the event count.

The amplifier: validateMeta copies meta.phases with no length capMAX_PHASE_ENTRIES only bounds the runtime phases array in safePhase, not meta.phases. So export const meta = { …, phases: [/* huge */] } makes each tick O(meta.phases). This is distinct from the declined per-emit thread at :300 (that was about entry.phases, which is capped); here it's the static meta object riding the same per-tick stringify, and its phases is uncapped.

The live snapshot only needs to identify the run — the terminal returnDisplay already carries full meta once. Keeping just the name (or dropping meta entirely) removes the per-tick cost:

Suggested change
...(entry.meta ? { meta: entry.meta } : {}),
...(entry.meta ? { meta: { name: entry.meta.name } } : {}),
中文

buildLivePhaseTreeDisplay 把整个 entry.meta 展开进每次 emitter 事件(phaseStarted/agentDispatched/agentCompletedsafeEmitUpdate)都会 JSON.stringify 的 payload。但 meta 在整个运行期间不变,每个事件都重新序列化它是冗余开销,且随事件数增长。

放大点:validateMeta 复制 meta.phases没有长度上限——MAX_PHASE_ENTRIES 只约束 safePhase 里的运行时 phases 数组,不约束 meta.phases。所以 export const meta = { …, phases: [/* 巨大 */] } 会让每次 tick 变成 O(meta.phases)。这与 :300 已被婉拒的线程不同(那个针对 entry.phases,它上限);这里是静态 meta 对象搭同一趟 per-tick stringify,而它的 phases 无上限。

实时快照只需标识运行身份——终态 returnDisplay 已完整携带一次 meta。只保留 name(或干脆去掉 meta)即可消除每 tick 的开销。

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

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM — P4a (meta extraction) + P4b (phase-tree UI + /workflows) landed cleanly with all R7 fixes verified. 348 tests pass, build clean, tmux deterministic paths confirmed. Ready to ship. ✅

@LaZzyMan LaZzyMan merged commit 72da112 into main Jun 16, 2026
32 of 33 checks passed
@LaZzyMan LaZzyMan deleted the lazzy/workflow-p4-meta-workflows-pill branch June 16, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants