feat(cli): extend non-blocking slash commands to more builtins - #9495
Conversation
QwenLM#8130 opted /about, /help, and /settings in to run immediately while a response streams. Apply the same criteria to eleven more builtins so local UI controls no longer wait for the active turn: - UI-preference commands whose saved changes apply through the existing settings hooks: /theme, /editor, /vim, /voice, and /terminal-setup. - Read-only status commands: /tools, /lsp, /tasks, /hooks, /docs, and /bug. Commands that submit model turns, mutate conversation state, or read state the active turn is writing remain serialized, as documented in the non-blocking slash commands design doc. Each opt-in is pinned by a unit test.
E2E test reportEnvironment: Steps:
Results:
Unit coverage: all 11 command test files (70 tests) plus |
|
✅ Qwen Triage finished — CI landed green on ✅ Qwen Triage 已完成 —— |
|
Thanks for the PR! Template looks good ✓ Problem: observed friction, not theory — since #8130 only Direction: aligned — this is a direct follow-up to merged #8130, extending the capability to more builtins under the same criteria the design doc already defines. No direct CHANGELOG entry, but the reference agent does run slash commands mid-response (claude-code changelog fixes "slash commands run while Claude is responding"), so the UX pattern is established. Size: not applicable — no core paths touched. 11 production lines (one flag per command), ~74 test lines, 13 doc lines. Approach: the scope feels right. Each command opts in with a single flag declaration pinned by a unit test, and the design doc records the extended set and criteria. A skim of each command against the flag contract (no model-turn submission, no mutation of active-turn state) matches the PR's grouping: the UI-preference commands persist through the same settings hooks Risk: no elevated risk signals — Stage 1e path check came back clean. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:是实际可观察到的使用摩擦,而非理论问题——自 #8130 以来只有 方向:对齐——这是对已合并 #8130 的直接跟进,按设计文档已定义的标准把该能力扩展到更多内置命令。CHANGELOG 无直接条目,但参考产品确实支持响应期间执行 slash command(claude-code changelog 有 "slash commands run while Claude is responding" 的修复记录),该 UX 模式已有先例。 规模:不适用——未触及核心路径。生产代码 11 行(每个命令一个标志位)、测试约 74 行、文档 13 行。 方案:范围合理。每个命令以单个标志位声明加入,并用单元测试锁定;设计文档记录了扩展集合与判定标准。按标志位契约(不提交模型轮次、不变更活跃轮次拥有的状态)快速核对每个命令,与 PR 的分组一致:UI 偏好类命令经由 风险:无升级风险信号——Stage 1e 高风险路径检查未命中。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewNo blockers found. My independent take before reading the diff was exactly what this PR does: audit each builtin against the streaming-safe contract from #8130, add the flag declaration per command, pin it with a test, and record the set in the design doc. The queue mechanism in AppContainer itself is untouched, so the change is purely additive (+101/−0). What I verified per command against the contract (no model-turn submission, no mutation of state the active turn owns):
One subtlety worth noting: the AppContainer bypass reads Style follows house conventions; the new Test evidence (PR's own CI, read via API — no PR code executed)Everything that has completed is green; the main Linux unit suite is still running. The macOS and Windows test jobs are skipped at this stage (they gate later), so cross-platform coverage for this commit comes from CI's Linux leg only. No failed checks, so no log excerpts to quote. The finalize job will refresh the table below once CI settles. Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 The unit tests pin the flag declaration on every command, and the AppContainer suite covers the queue-bypass mechanism — but that proves the declarations are wired, not the end-to-end behavior. The mid-stream claim ("these commands actually execute during a live stream, and the stream survives it") currently rests on the author's tmux capture on macOS only. Sandboxed verification would settle this: 中文说明代码审查未发现阻塞问题。我在看 diff 之前的独立思路与本 PR 完全一致:按 #8130 的流式安全契约逐个审查内置命令、为每个命令添加标志位声明、用测试锁定、并在设计文档中记录集合。AppContainer 的排队机制本身未改动,变更为纯增量(+101/−0)。 按契约(不提交模型轮次、不变更活跃轮次拥有的状态)逐一核实: 测试证据(通过 API 读取 PR 自身 CI——未执行任何 PR 代码)已完成的检查全部通过;Linux 主单测套件仍在运行。macOS/Windows 测试作业在此阶段被跳过,本提交的跨平台覆盖仅来自 CI 的 Linux 环节。无失败检查,故无日志摘录。finalize 作业会在 CI 结束后更新上表。 单元测试锁定了每个命令的标志位,AppContainer 套件覆盖了排队旁路机制——但这证明的是声明已接线,而非端到端行为。"流式期间命令确实立即执行且流式响应不受影响"这一主张目前仅有作者在 macOS 上的 tmux 截图支撑。可用沙箱验证收尾: — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 4/5 — clean, minimal change that does exactly what it says; the only reservation is evidentiary, not about the code. This is what a good follow-up PR looks like. The mechanism shipped in #8130; this PR applies it to eleven more builtins with one declarative line each, pins every one with a test, and updates the design doc so the criteria and the set live in one place. The diff matches my independent proposal exactly — I couldn't find a simpler path, and there's nothing in it that isn't needed. The thing to get right here was the safety judgment, so I audited all eleven against the flag contract rather than trusting the grouping: the dialogs are read-only or settings-scoped, the listings don't touch active-turn state, and the state-reading commands that could race a streaming turn were deliberately left serialized. The queue mechanism itself is untouched, which is why this feels low-risk despite changing behavior on eleven commands. Two honest reservations, neither blocking: the mid-stream end-to-end behavior rests on the author's tmux capture from macOS — the unit tests prove the wiring, not the live behavior (the 中文说明这是一个规范的跟进型 PR:机制在 #8130 中已落地,本 PR 用每个命令一行声明将其扩展到另外 11 个内置命令,每个都有测试锁定,设计文档也同步记录了标准与集合。diff 与我的独立方案完全一致——找不到更简单的路径,也没有任何多余的改动。 这里的关键是安全判断,因此我逐一按标志位契约核实了全部 11 个命令,而不是直接采信其分组:对话框要么只读要么仅涉及设置,列表类命令不触碰活跃轮次状态,而可能与流式轮次竞争的状态读取类命令被有意保留为串行。排队机制本身未改动,这正是改动覆盖 11 个命令但风险仍低的原因。 两点坦率的保留意见(均不阻塞):流式期间的端到端行为目前仅有作者在 macOS 上的 tmux 截图支撑——单元测试证明的是接线而非实际运行效果(如需收尾可用上面提到的 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
中文说明
已审查——无阻断问题。 建议见行内评论。
— qwen3.8-max via Qwen Code /review (v0.21.14)
…ng-slash-commands
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
中文说明
未发现问题。LGTM!✅
— qwen3.8-max via Qwen Code /review (v0.21.14)
yiliang114
left a comment
There was a problem hiding this comment.
LGTM — review found no blockers and CI is green on the latest head.
|
Released in v0.22.0. |
What this PR does
This PR extends the streaming-safe ("non-blocking") slash command capability introduced in #8130 to eleven more built-in commands. While a model response is streaming, these commands now execute immediately instead of waiting in the message queue for the active turn to finish:
/theme,/editor,/vim,/voice, and/terminal-setuponly manage UI preferences (their saved changes apply through the existing settings hooks), while/tools,/lsp,/tasks,/hooks,/docs, and/bugare read-only — they render local status information or open a browser, and never read state the active turn is writing. Each command declares the capability with a unit test pinning it, and the design doc records the extended set alongside the criteria used.Why it's needed
Since #8130, only
/about,/help, and/settingsbypass the streaming queue. Local UI controls like the theme picker or the tools listing neither submit a model turn nor touch conversation state owned by the active turn, so making them wait for a long response to finish only adds friction with no safety benefit. This narrows serialization to the commands that genuinely need it (model-turn submission, history mutation, runtime configuration that affects the in-flight turn), keeping the queue semantics exactly as the design doc defines them.Reviewer Test Plan
How to verify
npm run dev) and submit a prompt that streams for a while, such as asking for a long essay./theme: the theme picker should open immediately. Press Escape and confirm the original response keeps streaming and completes normally./toolsor/hooks: the output renders immediately while the stream continues./contextor/model— they should only run after the turn completes.cd packages/cli && npx vitest run src/ui/AppContainer.test.tsx src/ui/commands/themeCommand.test.ts src/ui/commands/toolsCommand.test.ts src/ui/commands/vimCommand.test.ts— the new assertions pincanRunDuringStreamingfor every opted-in command, and the AppContainer tests verify opted-in commands bypass the queue during a response while unmarked ones remain queued.Evidence (Before & After)
Before (main): typing
/themewhile a response streams queues it; the picker only opens after the turn completes (the default queue behavior established in #8130).After (this PR): captured via tmux during a live streaming response — the theme dialog opens on top of the still-streaming text:
And
/toolsrenders its listing while the footer shows the stream still in flight:Tested on
Environment
npm run devagainst ModelStudio (qwen3.8-max) for the tmux evidence; unit tests run with vitest.Risk & Scope
/settingshas used since feat(cli): run safe slash commands during streaming #8130, and/terminal-setuponly writes external IDE keybinding files./themeand/toolsas representatives of both groups); commands that read state the active turn mutates (/context,/stats,/copy,/diff,/export) intentionally remain serialized per the design doc.Linked Issues
Follow-up to #8130.
中文说明
这个 PR 做了什么
本 PR 将 #8130 引入的流式安全("非阻塞")slash command 能力扩展到另外 11 个内置命令。在模型流式响应期间,这些命令现在会立即执行,而不再在消息队列中等待活跃轮次结束:
/theme、/editor、/vim、/voice、/terminal-setup只管理 UI 偏好(保存的变更通过既有的 settings hooks 生效),而/tools、/lsp、/tasks、/hooks、/docs、/bug是纯只读的——它们只渲染本地状态信息或打开浏览器,从不读取活跃轮次正在写入的状态。每个命令都声明了该能力并用单元测试锁定,设计文档也记录了扩展后的集合及所用标准。为什么需要
自 #8130 以来,只有
/about、/help、/settings可以绕过流式队列。像主题选择器、工具列表这类本地 UI 控件,既不提交模型轮次,也不触碰活跃轮次拥有的会话状态,让它们等待一个长响应结束只会徒增阻塞而没有任何安全收益。本次改动把串行化收窄到真正需要它的命令(提交模型轮次、变更历史、变更影响进行中轮次的运行时配置),使队列语义与设计文档的定义完全一致。评审者测试计划
如何验证
npm run dev),提交一个会流式较久的 prompt(例如要求写一篇长文)。/theme:主题选择对话框应立即打开;按 Escape 关闭后确认原响应继续流式并正常完成。/tools或/hooks等只读命令重复验证:输出立即渲染,流式继续。/context或/model——它们应等轮次结束后才执行。cd packages/cli && npx vitest run src/ui/AppContainer.test.tsx src/ui/commands/themeCommand.test.ts src/ui/commands/toolsCommand.test.ts src/ui/commands/vimCommand.test.ts——新增断言为每个 opt-in 命令锁定canRunDuringStreaming,AppContainer 测试验证响应期间 opt-in 命令绕过队列、未标记命令仍被排队。证据(Before & After)
Before(main):流式期间输入
/theme会被排队,对话框要等轮次结束才打开(#8130 确立的默认排队行为)。After(本 PR):tmux 实时抓屏显示主题对话框在仍在流式输出的文本之上打开,以及/tools输出渲染时底部仍显示流式进行中状态(详见英文正文的代码块)。测试环境
macOS ✅ 已测试;Windows⚠️ 未测试;Linux ⚠️ 未测试
环境
tmux 证据使用
npm run dev+ ModelStudio(qwen3.8-max);单元测试使用 vitest。风险与范围
/settings自 feat(cli): run safe slash commands during streaming #8130 以来走的路径一致,且/terminal-setup只写外部 IDE 按键绑定文件。/theme和/tools作为两组的代表);读取活跃轮次正在变更的状态的命令(/context、/stats、/copy、/diff、/export)按设计文档有意保持串行。关联 Issue
#8130 的后续。