fix(cli): show full plan for gate failures#5077
Conversation
wenshao
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅ — qwen3.7-max via Qwen Code /review
| case 'unavailable': | ||
| case 'unavailable': { | ||
| const llmContent = formatUnavailableResponse(decision); | ||
| const message = `Plan gate: unavailable - ${decision.reason}`; |
There was a problem hiding this comment.
[Suggestion] The unavailable message uses a plain hyphen (-, U+002D) where the original code used an em-dash (—, U+2014). The old returnDisplay was `Plan gate: unavailable — ${decision.reason}` and formatUnavailableResponse() in planApprovalGate.ts still uses **unavailable** — ${decision.reason} with an em-dash, so the header and body now disagree on punctuation.
| const message = `Plan gate: unavailable - ${decision.reason}`; | |
| const message = `Plan gate: unavailable — ${decision.reason}`; |
Also update the test expectation for the unavailable case from 'Plan gate: unavailable - review model timed out' to 'Plan gate: unavailable — review model timed out'.
— qwen3.7-max via Qwen Code /review
|
@qwen-code /triage |
|
Thanks for the PR! Template looks good ✓ — all required headings present, bilingual body included. On direction: this fixes a clear UX gap — when the plan gate blocks execution, the user is left staring at a one-liner with no way to read the plan that was just rejected. Directly aligned with the CLI's core experience. Linked issue #5075 confirms it's a real user problem. On approach: scope is tight — 2 files, one extracted helper ( Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ — 所有必需标题齐全,包含中英双语正文。 方向:修复了一个明确的 UX 缺陷——plan gate 阻止执行后,用户只能看到一行摘要,无法阅读刚被拒绝的完整 plan。与 CLI 核心体验直接相关,关联 issue #5075 确认了这是真实用户问题。 方案:范围紧凑——2 个文件,提取一个 helper( 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewClean, focused change. Two files, one extracted helper, four call sites updated uniformly. What I verified:
One minor observation (not a blocker): the Real-Scenario TestingAttempted to exercise the plan gate path via tmux with Plan mode is also unavailable in headless/non-interactive mode, which rules out What we can confirm from tests instead: The PR author acknowledged this limitation: "no live TUI screenshot was captured; this PR validates the tool result shape at the core layer." Given that the change is purely at the data layer (structuring 中文说明代码审查简洁、聚焦的改动。两个文件,提取一个 helper,四个调用点统一更新。 已验证:
一个非阻塞的小观察: 真实场景测试尝试通过 tmux 在 Plan mode 在 headless/非交互模式下也不可用,排除了 PR 作者也承认了这个限制:"没有录制真实 TUI 截图;本 PR 在 core 层验证 tool result shape。" 鉴于改动纯粹在数据层(构造 — Qwen Code · qwen3.7-max |
|
This is a clean, well-scoped fix. Here's what I'm thinking after reviewing everything: The PR's approach matches what I would have done independently — extract a helper, update four call sites, keep the change at the data layer. No surprises. What convinces me:
The only thing I couldn't do is live tmux testing of a gate failure — the plan gate requires AI review model decisions that can't be forced deterministically. But the unit test coverage is thorough and the rendering layer was already prepared for this data shape. The risk of this change breaking something in production is very low. Approving. ✅ 中文说明这是一个干净、范围合理的修复。 PR 的方案和我独立提出的方案一致——提取 helper、更新四个调用点、把改动限制在数据层。没有意外。 让我确信的原因:
唯一没能做的是 gate 失败的真实 tmux 测试——plan gate 需要 AI 审查模型的决策,无法确定性触发。但单元测试覆盖充分,渲染层已经为这个数据形状做好了准备。这个改动在生产环境出问题的风险很低。 批准 ✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
✅ Local verification report — real TUI render via tmuxVerdict: safe to merge. I reproduced the fix end-to-end on a real terminal, filling the exact gap the PR description flagged as out of scope ("no live TUI screenshot was captured; this PR validates the tool result shape at the core layer"). The core layer was already proven by the unit tests; what was missing was proof that the TUI consumer actually renders the new Environment
Method
Evidence1) Real render — Before the PR the user saw only the first line; now the full plan + 2) 3) Tests + before/after regression proof.
4) No string→object regression in other consumers. 5) Convention consistency. The 6) Static checks on macOS: Minor, non-blocking nits
Neither affects correctness. LGTM. 中文版✅ 本地验证报告 —— 用 tmux 做真实 TUI 渲染结论:可以合并。 我在真实终端里端到端复现了这个修复,补上了 PR 描述中明确标注的盲区("没有录制真实 TUI 截图;本 PR 在 core 层验证 tool result shape")。core 层已由单测证明,缺的是证明 TUI 消费端真的能把新的 环境
方法
证据1) 真实渲染 —— 2) 3) 单测 + before/after 回归证明。
4) 其它消费方无 string→object 回归。 5) 约定一致性。 6) macOS 静态检查: 次要、不阻塞的小问题
两点都不影响正确性。LGTM。 |
What this PR does
Keeps the submitted plan visible when the autonomous plan approval gate does not approve execution. The
blocked,needs_user,cap_escalation, andunavailableoutcomes now return the same structuredplan_summarydisplay shape used by approved plans, withrejected: trueand the gate details appended after the original plan.Why it's needed
Fixes #5075. The approved path already sends
{ type: 'plan_summary', message, plan }, so the TUI can render the full plan. The non-approved gate paths returned only a short string such asPlan gate: blocked (1 finding(s)), which left users unable to read the plan that had just been rejected or blocked.Reviewer Test Plan
How to verify
Trigger
exit_plan_modefrom an AUTO or YOLO pre-plan session where the plan gate returns a non-approved outcome. The CLI should still show the submitted plan body, followed by the gate findings or questions, instead of only showing a one-line gate status.Evidence (Before & After)
Before:
exitPlanMode.tsreturned plain stringreturnDisplayvalues for gateblocked,needs_user,cap_escalation, andunavailable, soPlanSummaryDisplaynever received the plan. After:exitPlanMode.test.tscovers all four non-approved gate outcomes and asserts thatreturnDisplayis a rejectedplan_summarycontaining both the original plan text and the gate details.Tested on
Environment (optional)
Windows PowerShell, Node/npm from the repository dev setup. Validation commands:
npm run test --workspace=packages/core -- src/tools/exitPlanMode.test.ts;npx prettier --check packages/core/src/tools/exitPlanMode.ts packages/core/src/tools/exitPlanMode.test.ts;npx eslint packages/core/src/tools/exitPlanMode.ts packages/core/src/tools/exitPlanMode.test.ts;npm run typecheck --workspace=packages/core;npm run build --workspace=packages/core.Risk & Scope
Linked Issues
Fixes #5075
中文说明
这个 PR 做了什么
当自动 plan approval gate 没有批准执行时,仍然保留并展示用户刚提交的完整 plan。
blocked、needs_user、cap_escalation、unavailable四种结果现在都会返回和 approved 路径一致的结构化plan_summary,并设置rejected: true,同时把 gate 的发现或问题追加在原 plan 后面。为什么需要
修复 #5075。approved 路径已经返回
{ type: 'plan_summary', message, plan },所以 TUI 能渲染完整 plan。但 gate 非批准路径之前只返回一行字符串,例如Plan gate: blocked (1 finding(s)),导致用户看不到刚被阻止的完整 plan。Reviewer Test Plan
如何验证
在 AUTO 或 YOLO pre-plan session 中触发
exit_plan_mode,并让 plan gate 返回非批准结果。CLI 应该展示完整 plan,并在后面展示 gate findings 或 questions,而不是只显示一行 gate 状态。Before / After 证据
Before:
exitPlanMode.ts对blocked、needs_user、cap_escalation、unavailable返回纯字符串returnDisplay,PlanSummaryDisplay收不到 plan。After:exitPlanMode.test.ts覆盖四种非批准 gate 结果,断言returnDisplay是 rejectedplan_summary,且包含原始 plan 和 gate 细节。测试环境
Windows PowerShell,本地 Node/npm 开发环境。已运行:
npm run test --workspace=packages/core -- src/tools/exitPlanMode.test.ts;npx prettier --check packages/core/src/tools/exitPlanMode.ts packages/core/src/tools/exitPlanMode.test.ts;npx eslint packages/core/src/tools/exitPlanMode.ts packages/core/src/tools/exitPlanMode.test.ts;npm run typecheck --workspace=packages/core;npm run build --workspace=packages/core。风险与范围