Skip to content

fix(core): keep YOLO mode when the model calls enter_plan_mode - #6630

Merged
wenshao merged 6 commits into
QwenLM:mainfrom
Nas01010101:fix/enter-plan-mode-yolo-guard
Jul 10, 2026
Merged

fix(core): keep YOLO mode when the model calls enter_plan_mode#6630
wenshao merged 6 commits into
QwenLM:mainfrom
Nas01010101:fix/enter-plan-mode-yolo-guard

Conversation

@Nas01010101

Copy link
Copy Markdown
Contributor

What this PR does

When the session is in YOLO mode, a model-initiated enter_plan_mode tool call no longer switches the session into the read-only Plan mode. The tool now keeps the current mode and returns a message telling the model to continue investigating and presenting its plan without switching. Genuine user-driven plan-mode entries (Shift+Tab, /plan) are unaffected, and behavior in DEFAULT, AUTO_EDIT, and AUTO modes is unchanged.

Why it's needed

A user who starts with qwen -y has explicitly opted into low-friction execution. Today, if the model decides on its own to call enter_plan_mode, the session silently flips into the read-only Plan mode — which then blocks the file reads and writes the user expected to proceed, and can leave them stuck. This is a regression of #5428. The maintainer-confirmed direction (issue thread) is that a model-initiated plan-mode entry from YOLO should be a no-op that tells the model to keep planning in the current mode, rather than prompting or switching. enter_plan_mode.execute() is only ever reached for model-initiated entries — user actions call setApprovalMode directly and never route through the tool — so guarding here targets exactly the unwanted case.

Reviewer Test Plan

How to verify

  • Unit: npx vitest run packages/core/src/tools/enterPlanMode.test.ts — the should not switch from YOLO to PLAN (model-initiated entry is a no-op) case asserts that from YOLO, setApprovalMode is not called, the mode stays YOLO, and the result does not claim plan mode was entered. Reverting the guard makes this case fail (setApprovalMode called once).
  • Manual: start qwen -y, give a task that tempts the model to plan; confirm the session stays in YOLO and the model keeps working/planning inline instead of switching to Plan mode. Confirm Shift+Tab / /plan still enter Plan mode manually.

Evidence (Before & After)

N/A (non-user-visible control-flow change; verified via unit tests below).

Before (unpatched): AssertionError: expected "spy" to not be called at all, but actually been called 1 times.
After: Test Files 1 passed (1) / Tests 15 passed (15).
Full core suite: 14984 passed | 8 skipped (14992), 0 failed.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

Environment (optional)

Unit tests only (Node v22+). eslint --max-warnings 0, prettier --check, and tsc --noEmit (core) all clean.

Risk & Scope

  • Main risk or tradeoff: scoped to YOLO only — DEFAULT, AUTO_EDIT, and AUTO still allow model-initiated plan-mode entry. If maintainers prefer to also cover AUTO, that is a one-line extension of the same guard.
  • Not validated / out of scope: does not change the separate Plan Approval Gate flow, nor plan-content leakage (Plan Mode Content Leakage in Subsequent Responses #6237). No settings/schema changes.
  • Breaking changes / migration notes: none. Only model-initiated enter_plan_mode from YOLO changes behavior; user-driven entry and all other modes are unchanged.

Linked Issues

Fixes #5970

中文说明

这个 PR 做了什么

当会话处于 YOLO 模式时,模型主动调用 enter_plan_mode 工具将不再把会话切换到只读的 Plan 模式。该工具现在会保持当前模式,并返回一条消息,告诉模型在不切换模式的情况下继续调查并给出计划。用户主动进入 Plan 模式的方式(Shift+Tab、/plan)不受影响;DEFAULT、AUTO_EDIT、AUTO 模式下的行为也保持不变。

为什么需要

使用 qwen -y 启动的用户显式选择了低摩擦执行。目前,如果模型自行决定调用 enter_plan_mode,会话会静默切换到只读的 Plan 模式,从而阻止用户期望进行的文件读写,甚至让用户卡住。这是 #5428 的回归。issue 讨论中维护者确认的方向是:在 YOLO 下由模型发起的进入 Plan 模式应当是一个 no-op,告知模型在当前模式下继续规划,而不是弹窗或切换。enter_plan_mode.execute() 只会在模型发起时被触达——用户操作直接调用 setApprovalMode,从不经过该工具——因此在此加守卫正好只针对不希望发生的情况。

审阅者测试计划

如何验证

  • 单元测试:npx vitest run packages/core/src/tools/enterPlanMode.test.ts —— should not switch from YOLO to PLAN 用例断言:从 YOLO 出发不调用 setApprovalMode,模式仍为 YOLO,且结果不会声称已进入 Plan 模式。移除守卫会使该用例失败(setApprovalMode 被调用一次)。
  • 手动:qwen -y 启动,给一个会诱导模型规划的任务;确认会话保持 YOLO,模型继续内联工作/规划而不切换到 Plan 模式。确认 Shift+Tab / /plan 仍可手动进入 Plan 模式。

证据(前后对比)

N/A(非用户可见的控制流变更;通过单元测试验证)。修复前:expected "spy" to not be called at all, but actually been called 1 times;修复后:15/15 通过;核心测试套件 14984 通过、0 失败。

测试平台

macOS ✅;Windows ⚠️;Linux ⚠️

风险与范围

  • 主要风险:仅限 YOLO;DEFAULT/AUTO_EDIT/AUTO 仍允许模型发起进入 Plan 模式。若维护者希望也覆盖 AUTO,只需扩展同一守卫一行。
  • 不在范围内:不改变独立的 Plan Approval Gate 流程,也不涉及计划内容泄漏(Plan Mode Content Leakage in Subsequent Responses #6237);无设置/schema 变更。
  • 破坏性变更:无。

关联 Issue

Fixes #5970

A model-initiated enter_plan_mode call from YOLO silently switched the
session into the read-only Plan mode, surprising users who explicitly
chose YOLO for low-friction execution and then blocking the reads/writes
they expected to proceed. Genuine user-driven plan-mode entries
(Shift+Tab, /plan) call setApprovalMode directly and never route through
this tool, so guarding the tool only affects the model deciding to plan
on its own. From YOLO the tool now keeps the current mode and returns a
message telling the model to continue planning without switching.

Fixes QwenLM#5970

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

No review findings. Downgraded from Approve to Comment: CI failing: triage, Test (ubuntu-latest, Node 22.x).

— qwen3.7-max via Qwen Code /review

qqqys
qqqys previously requested changes Jul 10, 2026
// call config.setApprovalMode directly and never route through this tool, so
// gating here only affects the model deciding to plan on its own. Keep the
// current mode and tell the model to continue planning without switching.
if (this.config.getApprovalMode() === ApprovalMode.YOLO) {

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.

[Critical] This guard blocks every enter_plan_mode invocation while the current mode is YOLO, including the valid path where the user explicitly asks in chat or ACP to enter plan mode. The tool description still says to use this tool after the user asks for plan mode, but this branch returns before setApprovalMode(PLAN), and the returned message even tells the model to switch only if the user explicitly asks despite there being no different tool path to do that. In YOLO sessions, an explicit user request to lower privileges through enter_plan_mode now becomes impossible unless the UI has a separate /plan or shortcut path, which breaks the core approval-mode boundary for headless/ACP and natural-language mode switching.

Suggested fix: only suppress truly unsolicited model-initiated entries, or add an explicit invocation flag/context that distinguishes a user-requested plan-mode entry from an autonomous one; user-requested entries from YOLO should still call setApprovalMode(ApprovalMode.PLAN, { enteredByModel: true }) or an equivalent user-requested path.

— GPT-5 via Qwen Code /review

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

Reviewed with 10 parallel agents. Build passes, all 15 tests pass. Core logic correctly implements the maintainer-confirmed direction from issue #5970 — model-initiated enter_plan_mode from YOLO is now a no-op that preserves the user's chosen mode.

Three low-confidence items for human review: (1) no debug log on the new YOLO guard path — other early-return paths emit debugLogger calls; (2) no test for YOLO + non-interactive mode ordering; (3) test doesn't assert result.returnDisplay.

Note: the existing open comment at enterPlanMode.ts:86 raises a related concern about the guard blocking user-explicit chat requests — worth addressing in a follow-up.

— qwen3.7-max via Qwen Code /review

Addresses review feedback on QwenLM#6630.

The previous guard suppressed every enter_plan_mode invocation while the
session was in YOLO mode. That fixes the unsolicited switch reported in
QwenLM#5970, but it also blocks the legitimate path: the tool description tells
the model to call this tool only after the user explicitly asks, and
/plan is interactive-only (supportedModes: ['interactive']) with no
Shift+Tab equivalent. In a headless or ACP YOLO session the tool is the
only door into plan mode, so a blanket guard made an explicit user
request unreachable.

Add an optional userRequested flag to the tool schema and only no-op when
the entry is NOT user-requested. A user-requested entry still goes through
setApprovalMode(PLAN, { enteredByModel: true }) so the Plan Approval Gate
on exit continues to run for AUTO/YOLO sessions (QwenLM#5574).
@Nas01010101

Copy link
Copy Markdown
Contributor Author

Thanks for the review, the objection was correct. The tool description makes this tool the user-requested path, and since /plan is interactive-only, the tool is the only way into plan mode for headless and ACP sessions, so the blanket YOLO guard made an explicit user request unreachable there.

Pushed the suggested design in 5b16e74:

One honest caveat: the flag is model-attested, so a model that ignores the tool description could also set it incorrectly. For users who want a hard guarantee, tools.disabled: ["enter_plan_mode"] removes the tool entirely; I opened #6641 documenting that setting.

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

No issues found. LGTM! ✅

The userRequested flag correctly distinguishes model-initiated from user-requested plan-mode entries, preserving headless/ACP access while blocking unsolicited switches from YOLO. Guard ordering, test coverage (18/18 pass), and typecheck are all clean.

— qwen3.7-max via Qwen Code /review

@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 — no blockers. Suggestions are inline.

return {
llmContent:
'Plan mode was not entered: the session is in YOLO mode, which the user explicitly chose for low-friction execution. Continue investigating and presenting your plan in the current mode without switching. If the user explicitly asked for plan mode in this turn, retry this tool call with userRequested: true.',
returnDisplay: 'Stayed in YOLO mode (plan mode not entered).',

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] The YOLO guard's no-op return has no debugLogger call. Other early-return paths (subagent block via logger.warn, catch block via debugLogger.error) log — this one should too. When a user reports "I asked for plan mode and nothing happened," the oncall engineer grepping ENTER_PLAN_MODE finds zero evidence the guard fired.

Suggested change
returnDisplay: 'Stayed in YOLO mode (plan mode not entered).',
debugLogger.info(
'Blocked model-initiated plan entry from YOLO (userRequested=%s)',
this.params.userRequested,
);
return {
llmContent:

— qwen3.7-max via Qwen Code /review

// The tool description instructs the model to call this only after the
// user asks, and `/plan` is interactive-only — so this tool is the only
// door into plan mode for headless/ACP sessions. A blanket YOLO guard
// would make an explicit user request unreachable there.

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] This test only asserts setApprovalMode was not called and mode stayed YOLO, but does not verify the return value. The sibling "unsolicited" test asserts on llmContent (contains 'YOLO', not 'Plan mode is now active', contains 'userRequested: true'). Both paths share the same return object today, but the weaker test provides no regression safety on the user-facing message.

Suggested change
// would make an explicit user request unreachable there.
expect(mockConfig.setApprovalMode).not.toHaveBeenCalled();
expect(approvalMode).toBe(ApprovalMode.YOLO);
expect(result.llmContent).toContain('YOLO');
expect(result.returnDisplay).toContain('Stayed in YOLO');

— qwen3.7-max via Qwen Code /review

expect(approvalMode).toBe(ApprovalMode.PLAN);
expect(result.llmContent).not.toContain('non-interactive');
});

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] All userRequested: true tests start from ApprovalMode.YOLO. No test passes the flag from DEFAULT, AUTO, or AUTO_EDIT. The parameter is inert in non-YOLO modes (the guard never fires), but a defensive test would catch future regressions if the flag accidentally gained significance outside YOLO. Consider adding a test like tool.build({ userRequested: true }) from ApprovalMode.DEFAULT asserting normal plan-mode entry.

— qwen3.7-max via Qwen Code /review

- Log via debugLogger.info when the guard suppresses a model-initiated
  entry, so a "I asked for plan mode and nothing happened" report is
  diagnosable by grepping ENTER_PLAN_MODE (the other early-return paths
  already log).
- Strengthen the userRequested:false test to assert on the returned
  llmContent/returnDisplay, matching the unsolicited-entry sibling test.
- Add a defensive test pinning that userRequested is inert outside
  YOLO: DEFAULT with the flag set enters plan mode normally.

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

Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Suggestions — commit a94d4213b

File Issue Suggested fix
packages/core/src/tools/enterPlanMode.ts:110 debugLogger.info uses printf-style %s formatting, but formatArgs joins args with spaces (no substitution). Log output will contain literal %s. Use a template literal: debugLogger.info(`Blocked model-initiated plan entry from YOLO (userRequested=${this.params.userRequested})`)

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR @Nas01010101!

Template looks good ✓ — all required sections present, bilingual, test plan included.

Problem: Observed bug with clear evidence. Issue #5970 has a screenshot showing the model silently switching from YOLO to Plan mode and then failing to write files. This is a confirmed regression of #5428 — priority/P2, type/bug, labeled by maintainers. Not theoretical.

Direction: Aligned. The maintainer-confirmed direction in #5970's thread is exactly what this PR implements: model-initiated enter_plan_mode from YOLO should be a no-op. The userRequested flag is a smart addition over a blanket guard — it preserves the only path into plan mode for headless/ACP sessions where /plan and Shift+Tab aren't available.

Size: 45 production logic lines (43+2 in enterPlanMode.ts), 88 test lines (84+4 in enterPlanMode.test.ts). Well within safe limits for a core path fix. No maintainer escalation needed on size.

Approach: Scope is tight — one file changed in production, one in tests, doing exactly one thing. The userRequested parameter is the minimum surface needed to distinguish model-initiated from user-requested entries, and the tool description + parameter description give the model clear guidance. No scope creep, no drive-by refactors.

One thing worth noting: the CHANGES_REQUESTED review from @qqqys is on this PR (empty body) — worth checking if this pass addresses whatever motivated it.

Moving on to code review and testing. 🔍

中文说明

感谢贡献 @Nas01010101

模板完整 ✓ — 所有章节齐全,双语,测试计划完备。

问题: 已观测到的 bug,有明确证据。Issue #5970 附有截图,显示模型从 YOLO 静默切换到 Plan 模式后写入文件失败。这是 #5428 的回归——已被维护者标记为 priority/P2、type/bug。不是理论性问题。

方向: 对齐。#5970 讨论中维护者确认的方向正是此 PR 所实现的:YOLO 下模型主动调用 enter_plan_mode 应为 no-op。userRequested 标志比简单守卫更巧妙——保留了 headless/ACP 会话中进入 Plan 模式的唯一通道。

规模: 45 行生产代码(enterPlanMode.ts 中 43+2),88 行测试(enterPlanMode.test.ts 中 84+4)。作为核心路径的 fix,完全在安全范围内,无需维护者关注。

方案: 范围紧凑——生产改一个文件、测试改一个文件,只做一件事。userRequested 参数是区分模型发起与用户发起的最小界面,工具描述和参数描述给模型清晰指引。无范围蔓延,无顺手重构。

进入代码审查和测试阶段 🔍

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal (before reading diff): I'd add a guard in execute() that checks getApprovalMode() === YOLO and returns a no-op telling the model to keep planning inline. Simple, one conditional, no schema changes.

PR's approach vs mine: The PR is materially better. A blanket YOLO guard would break headless/ACP sessions where enter_plan_mode is the only path into plan mode (no /plan, no Shift+Tab). The userRequested parameter lets the model distinguish "user asked for this" from "I decided on my own" — solving the bug without closing that door. I didn't think of that.

Critical blockers: None.

AGENTS.md violations: None. Minimal change, focused scope, no over-abstraction.

Reuse check: No existing mechanism for distinguishing user-requested vs model-initiated tool calls in this codebase. The userRequested boolean on the tool params is the right primitive for this.

Testing

Unit tests

  • Before (main): 15/15 pass in enterPlanMode.test.ts
  • After (PR applied): 19/19 pass (4 new tests covering the YOLO guard, explicit user request, ACP, and cross-mode inertness)
  • Related: exitPlanMode.test.ts 42/42 pass — no regressions
  • TypeScript: tsc --noEmit clean across all packages
  • Lint: ESLint clean with PR applied

Real-scenario tmux test

Both the installed build (v0.19.8) and dev build (npm run dev) hit API auth failures on this CI runner — not a code issue. The PR's own description notes this is a "non-user-visible control-flow change; verified via unit tests" — and the unit tests comprehensively cover the behavior.

Before (installed build)

$ qwen -y -p 'Plan a careful approach to restructuring the config module'
Warning: QWEN_HOME points to "/home/github-runner/actions-runner-17/_work/_temp/qwen-home" but no settings.json was found there.
Warning: running headless with --yolo / approval-mode=yolo and no sandbox.
Error:

After (this PR via dev build)

$ npm run dev -- -y -p 'Plan a careful approach to restructuring the config module'
> node scripts/dev.js -y -p Plan a careful approach to restructuring the config module
Warning: QWEN_HOME points to "/home/github-runner/actions-runner-17/_work/_temp/qwen-home" but no settings.json was found there.
Warning: running headless with --yolo / approval-mode=yolo and no sandbox.
DEV is set to true, but the React DevTools server is not running.
Error:

Both runs exit at the same point (API auth) — the guard is never reached because the model call fails before tool selection. Unit tests are the correct verification surface for this change.

中文说明

代码审查

独立方案(读 diff 之前):execute() 中加一个守卫,检查 getApprovalMode() === YOLO,如果是则返回 no-op 告知模型继续在当前模式下规划。简单,一个条件判断,无需改 schema。

PR 方案 vs 我的方案: PR 更优。简单 YOLO 守卫会破坏 headless/ACP 会话——那里 enter_plan_mode 是进入 Plan 模式的唯一通道(没有 /plan、没有 Shift+Tab)。userRequested 参数让模型区分"用户要求的"和"我自主决定的"——修了 bug 又不堵死那条路。

阻断性问题: 无。

AGENTS.md 违规: 无。改动最小化,范围聚焦,无过度抽象。

测试

  • 修复前(main): 15/15 通过
  • 修复后(PR): 19/19 通过(4 个新测试覆盖 YOLO 守卫、显式用户请求、ACP、跨模式惰性)
  • 相关测试: exitPlanMode 42/42 通过,无回归
  • TypeScript: 全包 tsc --noEmit 通过
  • Lint: ESLint 通过

tmux 真实场景测试在此 CI 环境因 API 认证问题均未能完成(非代码问题)。PR 自身描述也注明此为非用户可见的控制流变更,单元测试是正确验证面。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

This is a clean bug fix. Let me say that plainly because it's worth saying: the userRequested parameter is a better solution than the obvious one (blanket YOLO guard), and I only realized that after comparing against my own proposal. The author thought about the headless/ACP edge case that I missed.

Issue #5970 is real — P2 bug with a screenshot, confirmed regression of #5428. The fix is 45 production lines doing exactly one thing: preventing YOLO sessions from silently flipping to read-only Plan mode when the model decides to plan on its own. Tests go from 15 to 19, all green, covering the guard, the escape hatch (userRequested: true), cross-mode inertness, and the ACP scenario. Typecheck and lint are clean.

The tmux testing couldn't run (CI auth), but the PR is upfront about this being a control-flow change best verified by unit tests — and the unit tests are thorough.

One note: @qqqys has a CHANGES_REQUESTED review with no body. If that was about something this revision should have addressed, the author may want to follow up.

Approving on the strength of the code review and test results. ✅

中文说明

这是一个干净的 bug 修复。直说:userRequested 参数比显而易见的方案(简单 YOLO 守卫)更优,我是在与自己的独立方案对比后才意识到的。作者考虑到了我遗漏的 headless/ACP 边缘情况。

Issue #5970 是真实的——P2 bug,附截图,#5428 的确认回归。修复用 45 行生产代码做一件事:阻止 YOLO 会话在模型自主决定规划时静默切换到只读 Plan 模式。测试从 15 增至 19,全部通过,覆盖守卫、逃生通道(userRequested: true)、跨模式惰性、ACP 场景。Typecheck 和 lint 均通过。

tmux 测试因 CI 认证问题未能运行,但 PR 已明确说明这是最适合通过单元测试验证的控制流变更——而单元测试是彻底的。

基于代码审查和测试结果,批准。✅

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

@wenshao

wenshao commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

✅ Maintainer local verification report

I built and ran a real local verification of this PR — not only the PR's own unit tests, but an independent test that drives the real EnterPlanModeTool against a real Config instance (no behavioral mocks), plus a regression reproduction and the full packages/core suite. Sharing here as a merge reference.

Item Value
Verified commit a94d4213b (PR head)
Base main @ f06e93226
Environment macOS 15.7.7 · Node v22.23.1
Diff under test enterPlanMode.ts, enterPlanMode.test.ts+127 / -6
Verdict ✅ Behaves as described. No regressions.

1) PR unit tests + independent real-Config verification — all pass

The PR's own suite (enterPlanMode.test.ts, 19 tests) passes. On top of it I added a throwaway, local-only test (enterPlanMode.maintainer-verify.test.ts, 7 tests) that does not reuse the author's mock Config: it constructs a real Config (only isTrustedFolder stubbed so YOLO is reachable in a temp dir, mirroring the existing "real Config + real tool" precedent in exitPlanMode.test.ts) and exercises the real setApprovalMode / prePlanMode / planGateState logic end-to-end. It prints the actually observed mode transition for each scenario:

PR tests + independent real-Config verification pass

Observed behavior matrix (from the real tool + real Config):

Start mode userRequested Result Note
YOLO unset stays YOLO (no switch) ⭐ the fix — #5970
YOLO false stays YOLO explicit opt-out honored
YOLO true enters PLAN, enteredByModel=true escape hatch for headless/ACP; Plan Approval Gate still runs on exit (#5574)
DEFAULT any enters PLAN unchanged
AUTO unset enters PLAN unchanged (fix is YOLO-scoped)
AUTO_EDIT unset enters PLAN unchanged

For the YOLO no-op path I also asserted getPrePlanMode() stays DEFAULT and getPlanGateState() stays undefined — i.e. plan mode was genuinely never entered, not just cosmetically suppressed.

2) Regression proof — the guard is load-bearing

I temporarily deleted the guard block and re-ran the PR suite. The session flips YOLO → PLAN again and the two guard tests fail with the exact #5970 symptom (setApprovalMode called once). Restoring the guard makes all 19 pass again.

Regression reproduced when the guard is removed

3) Full packages/core suite + static checks — 0 failed

Full core suite, typecheck, lint, prettier all clean

  • vitest run (full core): 15051 passed | 8 skipped, 0 failed (491 files)
  • tsc --noEmit (core): clean · eslint --max-warnings 0: clean · prettier --check: clean

Notes for merge

  • ✅ Correct and well-scoped: a model-initiated enter_plan_mode from YOLO is now a no-op that keeps the mode and tells the model to keep planning; user-driven entries (Shift+Tab, /plan) are untouched.
  • ✅ The userRequested: true escape hatch keeps the only plan-mode door reachable in headless/ACP sessions while still routing through the Plan Approval Gate on exit (exit_plan_mode auto-executes without confirmation when entering plan mode via Shift+Tab and prePlanMode appears to be yolo #5574) — good.
  • ℹ️ By design the fix is YOLO-only; AUTO / AUTO_EDIT still allow model-initiated plan entry. The PR description already calls this out as intentional and a one-line extension if maintainers later want AUTO covered. No change requested.
Reproduce locally
git fetch origin pull/6630/head:pr-6630 && git checkout pr-6630
npm ci
# PR's own tests
npx vitest run packages/core/src/tools/enterPlanMode.test.ts
# full core suite
cd packages/core && npx vitest run
# static checks
npx tsc --noEmit
npx eslint --max-warnings 0 src/tools/enterPlanMode.ts src/tools/enterPlanMode.test.ts
npx prettier --check src/tools/enterPlanMode.ts src/tools/enterPlanMode.test.ts

The independent real-Config test used above is a local-only helper (not part of this PR). Its core is:

function makeTrustedConfig(startMode: ApprovalMode): Config {
  const config = new Config({ targetDir: '.', cwd: '.', model: 'test-model', interactive: true });
  vi.spyOn(config, 'isTrustedFolder').mockReturnValue(true);
  if (startMode !== ApprovalMode.DEFAULT) config.setApprovalMode(startMode);
  return config;
}
// YOLO + {} -> tool.build({}).execute(): getApprovalMode() stays YOLO,
//   getPrePlanMode() === DEFAULT, getPlanGateState() === undefined
// YOLO + { userRequested: true } -> enters PLAN, planGateState.enteredByModel === true
🇨🇳 中文版本(点击展开)

✅ 维护者本地验证报告

我在本地对该 PR 做了真实验证——不仅跑了 PR 自带的单元测试,还额外写了一个**用真实 Config 驱动真实 EnterPlanModeTool(不使用行为 mock)**的独立测试,并复现了回归、跑了整个 packages/core 测试套件。结论供合并参考。

项目
验证 commit a94d4213b(PR head)
基线 main @ f06e93226
环境 macOS 15.7.7 · Node v22.23.1
受测改动 enterPlanMode.tsenterPlanMode.test.ts+127 / -6
结论 ✅ 行为与描述一致,无回归。

1) PR 单元测试 + 独立真实 Config 验证 — 全部通过。 PR 自带的 enterPlanMode.test.ts(19 个用例)通过。我另加了一个仅本地使用的测试(7 个用例),它不复用作者的 mock Config,而是构造真实 Config(仅 stub isTrustedFolder 以便在临时目录可进入 YOLO,沿用 exitPlanMode.test.ts 中已有的"真实 Config + 真实工具"先例),端到端地走真实的 setApprovalMode / prePlanMode / planGateState 逻辑,并打印每个场景实际观测到的模式切换(见上方第 1 张截图)。

行为矩阵:YOLO + 未设标志 → 保持 YOLO 不切换(即本次修复,#5970);YOLO + userRequested:false → 保持 YOLO;YOLO + userRequested:true → 进入 PLAN 且 enteredByModel=true(headless/ACP 下的逃生通道,退出时仍走 Plan Approval Gate,#5574);DEFAULT / AUTO / AUTO_EDIT → 照常进入 PLAN(不变)。对 YOLO no-op 路径,我还断言了 getPrePlanMode() 仍为 DEFAULTgetPlanGateState() 仍为 undefined,即确实从未进入 plan 模式,而非仅表面抑制。

2) 回归证明 — 该守卫是关键。 临时删除守卫代码块后重跑,会话再次 YOLO → PLAN,两个守卫用例以 #5970 的确切症状失败(setApprovalMode 被调用一次);恢复守卫后 19 个用例全部通过(见第 2 张截图)。

3) 完整 packages/core 套件 + 静态检查 — 0 失败。 vitest run(core 全量):15051 通过 | 8 跳过,0 失败(491 个文件);tsc --noEmiteslint --max-warnings 0prettier --check 均干净(见第 3 张截图)。

合并意见: 修复正确且范围收敛——YOLO 下模型主动 enter_plan_mode 现在为 no-op,保持当前模式并提示模型继续规划;用户主动进入(Shift+Tab、/plan)不受影响。userRequested:true 逃生通道在保证 headless/ACP 可进入 plan 的同时仍触发退出时的 Plan Approval Gate(#5574),设计良好。按设计本修复仅限 YOLO,AUTO/AUTO_EDIT 仍允许模型主动进入 plan——PR 描述已说明这是有意为之、如需覆盖 AUTO 只需一行扩展,无需改动。

截图为本地运行结果,托管在我个人 fork 的独立分支 wenshao/qwen-code@assets/pr-6630-verify,不影响上游仓库。

Verified locally by the maintainer. Screenshots are hosted on an isolated branch of a personal fork and can be removed later.

@wenshao
wenshao added this pull request to the merge queue Jul 10, 2026
Merged via the queue into QwenLM:main with commit 417fef2 Jul 10, 2026
52 checks passed
yuanyuanAli pushed a commit to yuanyuanAli/qwen-code that referenced this pull request Jul 11, 2026
…M#6630)

* fix(core): keep YOLO mode when the model calls enter_plan_mode

A model-initiated enter_plan_mode call from YOLO silently switched the
session into the read-only Plan mode, surprising users who explicitly
chose YOLO for low-friction execution and then blocking the reads/writes
they expected to proceed. Genuine user-driven plan-mode entries
(Shift+Tab, /plan) call setApprovalMode directly and never route through
this tool, so guarding the tool only affects the model deciding to plan
on its own. From YOLO the tool now keeps the current mode and returns a
message telling the model to continue planning without switching.

Fixes QwenLM#5970

* fix(core): gate the YOLO plan-mode guard on an explicit user request

Addresses review feedback on QwenLM#6630.

The previous guard suppressed every enter_plan_mode invocation while the
session was in YOLO mode. That fixes the unsolicited switch reported in
QwenLM#5970, but it also blocks the legitimate path: the tool description tells
the model to call this tool only after the user explicitly asks, and
/plan is interactive-only (supportedModes: ['interactive']) with no
Shift+Tab equivalent. In a headless or ACP YOLO session the tool is the
only door into plan mode, so a blanket guard made an explicit user
request unreachable.

Add an optional userRequested flag to the tool schema and only no-op when
the entry is NOT user-requested. A user-requested entry still goes through
setApprovalMode(PLAN, { enteredByModel: true }) so the Plan Approval Gate
on exit continues to run for AUTO/YOLO sessions (QwenLM#5574).

* fix(core): address review suggestions on the YOLO plan-mode guard

- Log via debugLogger.info when the guard suppresses a model-initiated
  entry, so a "I asked for plan mode and nothing happened" report is
  diagnosable by grepping ENTER_PLAN_MODE (the other early-return paths
  already log).
- Strengthen the userRequested:false test to assert on the returned
  llmContent/returnDisplay, matching the unsolicited-entry sibling test.
- Add a defensive test pinning that userRequested is inert outside
  YOLO: DEFAULT with the flag set enters plan mode normally.

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
JadeCong pushed a commit to CloudEngineHub/qwen-code that referenced this pull request Jul 11, 2026
* feat(web-shell): add mobile welcome composer slots

* refactor(web-shell): deduplicate MessageList JSX and remove dead CSS reference

- Extract ~80 lines of duplicated MessageList rendering into shared variables with conditional props and wrapper
- Remove dead chatPaneWithWelcomeMiddle className reference (CSS class never defined)
- Document mobileWelcomeFooterMiddle dependency on renderWelcomeFooter in JSDoc

* fix(web-shell): stabilize MessageList tree position and conditional customFooter wrapper

- Use stable outer wrapper div for IIFE to prevent MessageList unmount/remount when showMobileWelcomeFooterMiddle toggles
- Only wrap CustomFooter in styles.customFooter div when hasMobileComposerBottom is true, avoiding DOM depth change for non-mobile consumers

* fix(release): raise package size budget to 85 MiB (QwenLM#6688)

* fix(interactive): configure Docker sandbox networking for protocol tag retry test (QwenLM#6684) (QwenLM#6689)

The protocol-tags-interactive.test.ts started the fake OpenAI server
on 127.0.0.1 without Docker-aware host options, making it unreachable
from inside the Docker sandbox container. The CLI running in the
container tried to connect to 127.0.0.1 which resolved to the
container's own loopback, not the host where the test server listens.

Bind the fake server to 0.0.0.0 and advertise host.docker.internal
as the base URL host when QWEN_SANDBOX is docker or podman, matching
the established pattern in tool-control.test.ts. Also set NO_PROXY to
include host.docker.internal so the CLI does not route sandbox model
requests through an HTTP proxy.

Co-authored-by: qwen-autofix[bot] <qwen-autofix[bot]@users.noreply.github.com>

* fix(core): keep YOLO mode when the model calls enter_plan_mode (QwenLM#6630)

* fix(core): keep YOLO mode when the model calls enter_plan_mode

A model-initiated enter_plan_mode call from YOLO silently switched the
session into the read-only Plan mode, surprising users who explicitly
chose YOLO for low-friction execution and then blocking the reads/writes
they expected to proceed. Genuine user-driven plan-mode entries
(Shift+Tab, /plan) call setApprovalMode directly and never route through
this tool, so guarding the tool only affects the model deciding to plan
on its own. From YOLO the tool now keeps the current mode and returns a
message telling the model to continue planning without switching.

Fixes QwenLM#5970

* fix(core): gate the YOLO plan-mode guard on an explicit user request

Addresses review feedback on QwenLM#6630.

The previous guard suppressed every enter_plan_mode invocation while the
session was in YOLO mode. That fixes the unsolicited switch reported in
QwenLM#5970, but it also blocks the legitimate path: the tool description tells
the model to call this tool only after the user explicitly asks, and
/plan is interactive-only (supportedModes: ['interactive']) with no
Shift+Tab equivalent. In a headless or ACP YOLO session the tool is the
only door into plan mode, so a blanket guard made an explicit user
request unreachable.

Add an optional userRequested flag to the tool schema and only no-op when
the entry is NOT user-requested. A user-requested entry still goes through
setApprovalMode(PLAN, { enteredByModel: true }) so the Plan Approval Gate
on exit continues to run for AUTO/YOLO sessions (QwenLM#5574).

* fix(core): address review suggestions on the YOLO plan-mode guard

- Log via debugLogger.info when the guard suppresses a model-initiated
  entry, so a "I asked for plan mode and nothing happened" report is
  diagnosable by grepping ENTER_PLAN_MODE (the other early-return paths
  already log).
- Strengthen the userRequested:false test to assert on the returned
  llmContent/returnDisplay, matching the unsolicited-entry sibling test.
- Add a defensive test pinning that userRequested is inert outside
  YOLO: DEFAULT with the flag set enters plan mode normally.

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* feat(cli): forward ask_user_question answers from SDK can_use_tool (QwenLM#6655)

* feat(cli): forward ask_user_question answers from SDK can_use_tool

SDK-hosted agents could receive ask_user_question calls through the
can_use_tool callback and approve them, but the user's answers never
reached the tool: the CLI called onConfirm(ProceedOnce) with no payload,
so the tool read an empty answers map and the model never got the
decisions.

Route updatedInput.answers from the SDK's allow response into the tool
confirmation payload so the collected answers reach the tool. Reuses the
existing updatedInput channel — no new SDK API or types. Document the
pattern in the TypeScript and Python SDK READMEs.

* fix(cli): forward ask_user_question answers on teammate approval path

Address review feedback on QwenLM#6655:

- handleTeammateApproval now mirrors the leader path and promotes the
  user's answers from updatedInput into the confirmation payload, so
  ask_user_question calls approved through a teammate no longer drop the
  user's choices (wenshao).
- Extract a shared buildAllowConfirmationPayload helper used by both the
  leader and teammate paths, and only promote `answers` for
  ask_user_question so a same-named field on any other tool's input can't
  leak into the payload.
- Add tests for the teammate path and the defensive guards (array
  updatedInput, array/null/empty answers, foreign answers field).

* test(web-shell): stub Range client-rect methods to fix flaky CI

CodeMirror's async measure pass (scheduled via requestAnimationFrame)
calls getClientRects()/getBoundingClientRect() on a text Range. jsdom
implements these on Element but not on Range, so the call throws
"textRange(...).getClientRects is not a function" from a rAF callback
after the test completed. Vitest surfaces it as an unhandled error and
fails the whole run with exit code 1 even though every assertion passed
(seen intermittently in useComposerCore.dom.test.tsx).

Polyfill both methods on Range.prototype in the shared test setup,
mirroring the existing ResizeObserver/scrollIntoView stubs.

* refactor(cli): use ToolNames constant and broaden permission tests

Address review suggestions on QwenLM#6655:

- buildAllowConfirmationPayload now gates answers-promotion on the
  ToolNames.ASK_USER_QUESTION constant instead of a bare string literal,
  so a future rename of the tool name is a compile-time break rather than
  a silent regression.
- Add an it.each case for a non-object primitive updatedInput (string) to
  cover the `typeof updatedInput !== 'object'` guard branch.
- Assert the leader path overrides toolCall.request.args with the host's
  sanitized updatedInput before confirming.
- Add a teammate-path test for an allow response with no updatedInput,
  asserting respond is called with (ProceedOnce, undefined).

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>

* fix(cli): localize approval mode UI labels (QwenLM#6592)

* fix(cli): localize approval mode UI labels

* fix(cli): address approval mode i18n review

* fix(cli): stabilize approval mode i18n key

* test(cli): cover approval mode i18n follow-up

* test(cli): cover localized auto indicator

* test(cli): address approval i18n suggestions

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>

* feat(dingtalk): mention response senders (QwenLM#6679)

* docs: design DingTalk at-sender replies

* docs: plan DingTalk at-sender replies

* feat(channels): preserve session for response delivery

* feat(dingtalk): optionally mention response sender

* docs(dingtalk): explain response mentions

* fix(dingtalk): retain queued mention targets

* fix(dingtalk): bound mention target lifecycle

* fix(dingtalk): clear synthetic command mention target

* fix(dingtalk): clear buffered targets on session death

* debug(dingtalk): log mention delivery result

* fix(dingtalk): render response mentions

* fix(dingtalk): send visible response mentions

* feat(dingtalk): use text replies for mentions

* fix(dingtalk): preserve mentioned text replies

* feat(web-shell): add artifact right panel (QwenLM#6591)

* feat(web-shell): add artifact right panel

* fix(web-shell): address artifact panel review feedback

* fix(web-shell): handle artifact panel review edge cases

* fix(web-shell): tighten scheduled task parsing

* fix(web-shell): address artifact panel review followups

* fix(web-shell): guard large file diff stats

* fix(web-shell): address review panel suggestions

* test(webui): stabilize heartbeat prompt cleanup test

* fix(web-shell): address artifact review refresh issues

* test(web-shell): stabilize ChatPane artifact hook mock

* fix(web-shell): clear stale session artifacts while loading

* fix(web-shell): preserve artifact tabs during refresh

* fix(web-shell): address artifact review followups

* fix(web-shell): respect workspace cwd for artifact outputs

* fix(web-shell): scope artifact panel actions to pane

* fix(web-shell): resolve split pane merge conflict

* fix(web-shell): clear stale artifact panel state

* fix(web-shell): preserve leading turn outputs

* fix(web-shell): tighten turn output selectors

* fix(web-shell): harden artifact preview sanitizer

* fix(web-shell): address artifact panel review regressions

* fix(web-shell): reconcile split pane artifact snapshots

* fix(web-shell): clear pane artifacts on session switch

* fix(web-shell): clear stale right panel snapshots

* fix(web-shell): repair scheduled task hint string

---------

Co-authored-by: ytahdn <ytahdn@gmail.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>

* feat(cli): workspace-qualified ACP transport (daemon multi-workspace phase 4) (QwenLM#6621)

* docs(design): add daemon multi-workspace phase 4 (workspace-qualified ACP) design

* feat(cli): add workspace-qualified ACP transport (issue QwenLM#6378 phase 4)

Per-runtime ACP dispatcher at /workspaces/:workspace/acp (HTTP + WS) dispatched by URL path from the single upgrade listener; per-runtime device-flow + reverse client-MCP; owner-index via bridge lifecycle; untrusted/unknown rejected; legacy /acp unchanged; advertise workspace_qualified_acp for multi-workspace.

* fix(cli): keep per-runtime device-flow registry out of serve fast-path bundle

Phase 4 secondary-runtime device-flow statically imported createDeviceFlowRegistry into run-qwen-serve, pulling glob/@iarna/toml into the serve fast-path bundle and failing the closure check. Import it dynamically at the creation site; the check now passes and behavior is unchanged.

* refactor(cli): drop per-runtime device-flow for secondary workspaces

Follow-up to the fast-path fix: instead of dynamically importing createDeviceFlowRegistry for secondary runtimes, drop the per-runtime device-flow wiring entirely. Secondary ACP device-flow falls back to the dispatcher default, keeping the serve fast-path bundle closure clean without the dynamic-import indirection. WorkspaceRuntime.deviceFlowRegistry stays optional for a future per-runtime hook.

* fix(cli): share daemon-global device-flow across ACP mounts; harden WS path parsing

Secondary ACP mounts share the daemon-global device-flow registry (single instance per daemon) instead of a per-runtime one; the event sink fans out to every trusted runtime bridge so secondary ACP clients receive their own flow events, fixing the reviewer QwenLM#6621 Critical and the CI test failure. Drops WorkspaceRuntime.deviceFlowRegistry. WS upgrade path is parsed from the raw request-target instead of new URL().pathname, rejecting %2e%2e / backslash / dot-segment traversal.

* refactor(cli): gate CDP claim on primary mount; return plural ACP POST promise

Add a primary flag to RuntimeAcpMount so a secondary workspace's ACP connection cannot claim the CDP tunnel -- the claim is gated on activeMount.primary, matching the primary-only chrome-devtools MCP wiring. The plural /workspaces/:workspace/acp POST handler returns the dispatch promise instead of voiding it.

* refactor(cli): centralize ACP-HTTP enablement in resolveAcpHttpEnabled

Add resolveAcpHttpEnabled() as the single interpretation of the QWEN_SERVE_ACP_HTTP opt-out, replacing four independent env checks across mount, voice-WS advertisement, and CDP-MCP gating. Advertise workspace_qualified_acp only when the ACP HTTP surface is enabled AND multi-workspace sessions are active, so it is not announced when ACP HTTP is disabled.

* feat(cli): ACP dispose 503 gate + aggregate connection snapshot across mounts

After dispose() the shared ACP HTTP handlers (legacy /acp + workspace-qualified) return 503 server_disposed instead of racing torn-down registries during the shutdown drain. Add AcpHttpHandle.getSnapshot() aggregating connection and wsStream counts across the primary mount and every trusted secondary runtime, and switch the metrics sampler to it so daemon metrics report all workspaces' ACP connections rather than only the primary's.

* test(cli): cover ACP dispose 503, aggregate snapshot, and raw dot-segment WS reject

* docs(design): record Phase 4 ACP systematic rework (8-axis hardening)

Correct the Summary (the device-flow registry stays daemon-global and shared, not per-runtime) and add a section documenting the final architecture: runtime mount factory, routing/trust isolation, raw request-target WS parsing, daemon-global device-flow with event-sink fan-out, primary-only CDP, disposed 503 gate, aggregate getSnapshot, and resolveAcpHttpEnabled-gated capability advertisement.

* fix(cli): align /daemon/status ACP counts with the aggregate mount snapshot

Code review found a drift: the metrics sampler switched to the aggregate AcpHttpHandle.getSnapshot() (all mounts) while /daemon/status still read the primary-only registry snapshot, so the two observability surfaces diverged under multi-workspace. Extend AcpHttpSnapshot to aggregate all transport counters (connection/session/sse/ws streams + pending client requests) and feed the /daemon/status transport summary from it; per-connection diagnostics and the connection cap stay primary-scoped. Also refresh the device-flow-registry doc comment to the daemon-global shared model.

* test(cli): regression-test device-flow on a trusted secondary workspace

Locks in the reviewer Critical fix: a trusted secondary workspace's ACP now shares the daemon-global device-flow registry, so device_flow/start reaches provider resolution (an unsupported-provider error here) instead of erroring 'Device flow not configured'. Wires a shared DeviceFlowRegistry into the test harness and drives initialize + device_flow/start over the secondary WebSocket.

* docs(design): mark the superseded per-runtime device-flow section

Address PR QwenLM#6621 review: the pre-rework 'Per-runtime device-flow registry' section contradicted Systematic rework axis 4 (daemon-global shared registry + fan-out). Flag it as superseded design-history so readers don't build the wrong mental model.

* refactor(cli): mount ACP only for trusted secondary workspaces

Address PR QwenLM#6621 review suggestions: (1) skip creating a dispatcher/registry/remember-lane for untrusted non-primary workspaces (they are 403-rejected before any mount lookup), so they no longer appear as always-zero entries in the aggregate getSnapshot(); (2) test that a secondary workspace cannot claim the process-wide CDP tunnel (primary-only guard); (3) test that a WS upgrade to an unknown selector is rejected 400.

* test(cli): cover device-flow event fan-out across bridges

Address PR QwenLM#6621 review: the resolveEventBridges fan-out (the reviewer Critical fix's core delivery path) had zero test coverage. Add unit tests that a device-flow event reaches every resolved bridge, that one bridge throwing does not block the others (best-effort), and that it falls back to the single bridge when no resolver is provided.

* fix(cli): report ACP connection pressure across all mounts

Address PR QwenLM#6621 review: the connection_capacity_high warning read the primary mount's snapshot only, so a saturated secondary workspace was invisible. Compute the busiest mount from the aggregate snapshot (per-mount cap is uniform, opts.maxConnections) so any mount nearing capacity triggers the warning.

* test(cli): allow acp-http-enabled.ts in the serve process.env guard

Fix CI failure on PR QwenLM#6621: the serve process.env guard flagged the new acp-http-enabled.ts as a direct process.env reader. It is the QWEN_SERVE_ACP_HTTP interpreter extracted from index.ts and serve-features.ts (both already allow-listed); QWEN_SERVE_ACP_HTTP is a daemon-level process-global toggle, so the file inherits their allow-list entry.

* docs: harden workspace-qualified ACP design

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* docs: plan workspace-qualified ACP hardening

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): align workspace-qualified ACP routing

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): harden qualified ACP request errors

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* test(cli): cover unmarked URIError fallback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): make ACP disposal terminal

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): aggregate ACP connection diagnostics

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* chore: remove review process artifact

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): address workspace ACP review feedback

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

* fix(cli): finish ACP review follow-ups

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com>
Co-authored-by: qqqys <qys177@gmail.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: qwen-autofix[bot] <qwen-autofix[bot]@users.noreply.github.com>
Co-authored-by: nas <156536069+Nas01010101@users.noreply.github.com>
Co-authored-by: Tianyuan <2720711917@qq.com>
Co-authored-by: han <2992336417@qq.com>
Co-authored-by: ytahdn <1294726970@qq.com>
Co-authored-by: ytahdn <ytahdn@gmail.com>
Co-authored-by: jinye <djy1989418@126.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@Nas01010101
Nas01010101 deleted the fix/enter-plan-mode-yolo-guard branch July 13, 2026 22:29
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.

Auto enter Plan mode from Yolo mode is back in latest version?

4 participants