fix(cli): preserve activity state during slash dispatch by dvd233 · Pull Request #12227 · QwenLM/qwen-code · GitHub
Skip to content

fix(cli): preserve activity state during slash dispatch - #12227

Open
dvd233 wants to merge 12 commits into
QwenLM:mainfrom
dvd233:fix/12224-slash-command-idle
Open

dvd233 wants to merge 12 commits into
QwenLM:mainfrom
dvd233:fix/12224-slash-command-idle

Conversation

@dvd233

@dvd233 dvd233 commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

Keep the app-wide stream state Responding while a local slash command is prepared. A separate command-facing idle ref lets idle-only commands run only when dispatch began from an idle session and no model stream is active. If asynchronous message logging is cancelled, the aborted submission returns before invoking the slash handler; the command-facing flag resets after success and exceptions.

Why it's needed

Fixes #12224. submitQuery marks a user submission as responding before prepareQueryForLlm invokes a UI-only slash handler, so /cd sees an active response and refuses to change directory. Making the app-wide state idle would also let cancellation, telemetry, and other activity-aware consumers treat preparation as finished. A dedicated command-facing ref preserves those app-wide behaviors while allowing the command-specific guard to admit the command.

Reviewer Test Plan

How to verify

  • Start an interactive session from idle, run /cd <directory>, and confirm the command changes the session directory.
  • Hold logger.logMessage during /cd, press Esc, and confirm the slash handler and model stream are not invoked.
  • Hold a local slash dispatch, start a detached ToolResult continuation, and confirm the command-facing idle signal becomes false as soon as the model stream starts, without forcing a rerender.
  • Start a main response, submit /btw, then finish the main stream while the side dispatch remains held; confirm the command-facing idle signal stays false.
  • Cancel slash dispatch A while its logger is held, start B, then release A and confirm B keeps the command-facing idle signal until B settles.
  • In YOLO mode, update history twice during a local slash command and confirm one conversation_finished event is emitted after settlement.

Evidence (Before & After)

Before: the Windows reproduction attached to #12224 shows /cd refused with “Cannot change directory while a response or tool call is in progress.” After: use-llm-stream.test.tsx and AppContainer.test.tsx cover synchronous stream-state reads, per-dispatch cleanup, cancellation, detached continuations, /btw, ordinary idle behavior, app-wide ref isolation, throw cleanup, and YOLO telemetry.

Tested on

OS Status
🍏 macOS N/A — not tested locally
🪟 Windows ✅ typecheck, 291 hook tests, 206 AppContainer tests, ESLint, and Prettier
🐧 Linux N/A — not tested locally

Environment (optional)

Windows 11, Node.js v24.15.0, Qwen Code worktree. The global qwen executable is not installed, so no live CLI smoke was run; the delayed-logger hook tests provide the deterministic reproduction. GitHub CI and review status are tracked against the latest PR head.

Risk & Scope

  • Main risk or tradeoff: slash-command guards see idle only during an idle-origin local dispatch with no active model stream; the app-wide activity state remains Responding.
  • Not validated / out of scope: live cross-platform TUI smoke on macOS or Linux.
  • Breaking changes / migration notes: none.

Linked Issues

Fixes #12224

中文说明

本 PR 在本地 slash command 准备期间让应用级流状态保持 Responding。独立的命令级 idle ref 只在派发从空闲会话开始、且没有模型流运行时允许只在空闲状态执行的命令。如果异步消息日志记录被取消,提交流程会在调用 slash handler 前响应 abort signal;命令级标志在成功和异常路径都会复位。

本 PR 修复 #12224。submitQuery 会在 prepareQueryForLlm 调用 UI-only slash handler 之前把用户提交标记为 responding,因此 /cd 会看到有活动响应并拒绝切换目录。把应用级状态改成 idle 也会让取消、遥测以及其他依赖活动状态的消费者误以为准备阶段已经结束。专用的命令级 ref 保留这些应用级行为,同时允许命令专属 guard 正确准入。

验证步骤

  • 从空闲状态启动交互会话,运行 /cd <directory>,确认会话目录已切换。
  • 在 /cd 的 logger.logMessage 期间按 Esc,确认 slash handler 与模型流都没有启动。
  • 挂起本地 slash 派发,再启动 detached ToolResult continuation;无需强制重新渲染,模型流启动后命令级 idle signal 就应变为 false。
  • 挂起派发 A 的 logger 并取消 A,再启动派发 B;释放 A 后,确认 B 的命令级 idle signal 保持有效直到 B 结算。
  • 启动主响应后提交 /btw,在 side dispatch 仍挂起时结束主流;命令级 idle signal 应保持 false。
  • 在普通空闲状态确认 slash processor 仍看到 idle;本地派发期间应用级 update ref 仍保持 non-idle。
  • 在 YOLO 模式下让本地 slash command 两次更新历史,确认结算后只发出一次 conversation_finished event。

前后证据

之前:#12224 附带的 Windows 复现视频显示 /cd 报错 “Cannot change directory while a response or tool call is in progress.” 之后:use-llm-stream.test.tsx 与 AppContainer.test.tsx 覆盖同步流状态读取、按派发归属复位、取消、detached continuation、/btw、普通 idle、应用级 ref 隔离、异常复位与 YOLO 遥测。

本地测试平台

系统 状态
🍏 macOS 本地未测试
🪟 Windows ✅ typecheck、291 项 hook 测试、206 项 AppContainer 测试、ESLint、Prettier
🐧 Linux 本地未测试

环境(可选)

Windows 11、Node.js v24.15.0、Qwen Code worktree。当前环境没有全局 qwen 命令,因此未运行实时 CLI smoke;延迟 logger 的 hook 测试提供了确定性复现。GitHub CI 与 review 状态以最新 PR head 为准。

风险与范围

  • 主要风险或取舍:只有从空闲状态发起且没有活动模型流时,slash-command guard 才会短暂看到 idle;应用级活动状态始终保持 Responding。
  • 未验证 / 范围外:macOS 或 Linux 上的实时 TUI smoke。
  • 破坏性变化 / 迁移说明:无。

@dvd233 dvd233 changed the title fix(cli): keep local slash commands idle during dispatch fix(cli): preserve activity state during slash dispatch Sep 24, 2026
@dvd233

dvd233 commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@qwen-code /review

@dvd233

dvd233 commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

@qwen-code /review

@yiliang114

Copy link
Copy Markdown
Collaborator

Rechecked the existing review feedback against 95a477b3c93a5ce6e5329286328c19fc6052d4b8. The earlier Critical mechanisms are addressed: slash dispatch leaves app-wide activity state intact, command guards read shared live state, stream-count updates are synchronous, and dispatch cleanup checks its owning token.

The remaining R4-1 and R5-1 threads are non-blocking Suggestions. The unused return getter no longer has a divergent formula, and the hook test helper now passes the shared ref. The missing WaitingForConfirmation test row is a regression-coverage gap; the current isCommandIdle predicate correctly rejects that state. Neither establishes a current runtime defect.

After five review rounds, I would defer those Suggestions rather than add another implementation cycle. The executed CI gates are green. A fresh reviewer can reconcile the historical changes-requested verdict with this head; I am not submitting a full approval here because this was a bounded recheck, and I did not run the live TUI smoke that the PR explicitly leaves unverified.

@dvd233

dvd233 commented Oct 1, 2026

Copy link
Copy Markdown
Contributor Author

This branch has not been deployed

No deployments
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.

bug: unable to change directory with /cd after v0.24.0 update

2 participants