fix(cli): localize approval mode UI labels - #6592
Conversation
|
Thanks for the PR! Template looks good ✓ Problem: observed bug — issue #6582 reports mixed-language UI when cycling approval modes in Chinese locale. The PR provides before/after screenshots showing Direction: aligned. Localizing approval-mode UI labels is squarely within the i18n/localization scope. This is a focused bug fix, not scope creep. Size: not applicable — no core paths touched. All changes are in Approach: the scope feels right. Three targeted changes: (1) reuse existing Re-triage note: the author addressed all review suggestions from the previous round — added test coverage for the Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已观测到的 bug — issue #6582 报告了在中文环境下切换审批模式时出现中英文混杂。PR 提供了修改前后截图,显示 方向:对齐。审批模式 UI 标签的本地化属于 i18n/本地化的范畴,是聚焦的 bug 修复,没有超出范围。 规模:不适用 — 未触及核心路径。所有变更在 方案:范围合理。三个有针对性的改动:(1) 复用已有的 重新审查说明: 作者已处理了上轮审查的所有建议 —— 添加了 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewIndependent proposal: route all approval mode display names through The PR matches this approach closely. Clean, minimal set of changes — no scope creep. Correctness: verified that all new check-i18n.ts changes: The Downstream impact: Since last triage: the author addressed all review suggestions — added test coverage for No critical blockers. No AGENTS.md violations. TestingUnit tests (58 total, all pass): i18n consistency check: ✅ All checks passed Before (installed build — qwen v0.19.8, Chinese locale
|
|
This is a clean, well-scoped i18n bug fix. Issue #6582 clearly demonstrates the problem (mixed-language UI in Chinese locale), the root cause is verifiable ( The PR matches my independent proposal: reuse the existing Since the last triage, the author addressed all review suggestions: added test coverage for the semantic key exception mechanism, extended translations from 3 locales to all 9, and added a Chinese locale rendering test. The test suite is now comprehensive at 58 tests covering UI components, hooks, utilities, downstream consumers, and the i18n check script itself. The tmux capture confirms the bug reproduces on the installed build (English notice in a Chinese UI). The unit tests verify the fix programmatically — including the Chinese locale entry notice and the fallback behavior for unloaded locales. Maintainer @wenshao independently verified the full before/after on macOS with all checks green. Ships the fix cleanly. ✅ 中文说明这是一个干净、范围合理的 i18n bug 修复。Issue #6582 清楚地展示了问题(中文环境下的混合语言 UI),根本原因可验证( PR 的方案与我的独立方案一致:复用已有的 自上次审查以来,作者处理了所有审查建议:添加了语义 key 例外机制的测试覆盖,将翻译从 3 个语言扩展到全部 9 个,并添加了中文 locale 渲染测试。测试套件现在覆盖了 58 个测试,包括 UI 组件、hooks、工具函数、下游消费方和 i18n 检查脚本本身。 tmux 实测确认 bug 在已安装版本上复现(英文通知出现在中文 UI 中)。单元测试程序化地验证了修复 —— 包括中文 locale 的 entry notice 和未加载 locale 时的 fallback 行为。维护者 @wenshao 在 macOS 上独立验证了完整的修改前后效果,所有检查均通过。 可以合入。✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
| case ApprovalMode.YOLO: | ||
| return 'YOLO'; | ||
| return t('YOLO'); | ||
| default: |
There was a problem hiding this comment.
[Critical] t('YOLO') is inconsistent with AutoAcceptIndicator.tsx:44 which uses t('YOLO mode'). In zh.js, 'YOLO' maps to 'YOLO' (untranslated) while 'YOLO mode' maps to 'YOLO 模式'. Non-English users see untranslated "YOLO" in the approval mode picker but "YOLO 模式" in the status indicator.
| default: | |
| return t('YOLO mode'); |
— qwen3.7-max via Qwen Code /review
Suggestions — commit
|
| File | Issue | Suggested fix |
|---|---|---|
scripts/check-i18n.ts:422 |
The cross-validation of EN_SEMANTIC_KEY_EXCEPTIONS against MUST_TRANSLATE_KEYS uses the hardcoded import (new Set(MUST_TRANSLATE_KEYS)) instead of the parameterized mustTranslateKeySet built at line 413. This makes the cross-check untestable with fixture data and inconsistent with the rest of the function's parameter-driven design. |
Use mustTranslateKeySet (already computed from the parameter) instead of building a separate set from the hardcoded import: if (!mustTranslateKeySet.has(key)) |
packages/cli/src/ui/hooks/useAutoAcceptIndicator.ts:20-23 |
AUTO_MODE_FIRST_TIME_MESSAGE_FALLBACK is a character-for-character copy of en.js's auto_mode.entry_notice value with no sync mechanism. If the English copy is edited, the fallback silently diverges. |
Add a unit test that imports the en.js value and asserts equality with the fallback constant, or add a // Keep in sync with en.js 'auto_mode.entry_notice' comment. |
scripts/check-i18n.ts:293-295 |
The key-value mismatch error message does not mention EN_SEMANTIC_KEY_EXCEPTIONS or the resolution path. Developers must read the script source to discover the exceptions mechanism. |
Update the error to include remediation guidance: If this is an intentional semantic key, add it to EN_SEMANTIC_KEY_EXCEPTIONS in this file AND to MUST_TRANSLATE_KEYS. |
— qwen3.7-max via Qwen Code /review
| case ApprovalMode.DEFAULT: | ||
| return t('Ask permissions'); | ||
| case ApprovalMode.AUTO_EDIT: | ||
| return t('auto-accept edits'); |
There was a problem hiding this comment.
[Critical] formatApprovalModeName(ApprovalMode.AUTO_EDIT) now returns t('auto-accept edits') (→ 'auto-accept edits') instead of the previous raw enum value 'auto-edit'. The existing test in approvalModeCommand.test.ts:94 asserts expect(result.content).toContain('auto-edit'), which fails because 'auto-edit' is not a substring of 'auto-accept edits'.
Verified test failure output:
expected 'Approval mode set to "auto-accept edi…' to contain 'auto-edit'
Fix: update approvalModeCommand.test.ts:94 from toContain('auto-edit') to toContain('auto-accept edits').
— qwen3.7-max via Qwen Code /review
b60f0b5 to
cb3e52d
Compare
|
Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. 中文请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x). Suggestion-level recommendations are in the Suggestion summary comment below.
— qwen3.7-max via Qwen Code /review
doudouOUC
left a comment
There was a problem hiding this comment.
No blockers found. Downgraded from Approve to Comment: CI failing (route, Test (ubuntu-latest, Node 22.x)). The two prior Critical inline comments (YOLO inconsistency, AUTO_EDIT test assertion) appear resolved in this commit — independent verification confirmed both t('YOLO mode') consistency and updated test assertions. Suggestion-level recommendations are in the Suggestion summary comment below.
— qwen3.7-max via Qwen Code /review
Suggestions — commit
|
| File | Issue | Suggested fix |
|---|---|---|
scripts/check-i18n.ts:66-69 |
EN_SEMANTIC_KEY_EXCEPTIONS has no test coverage — the new exception branch in checkKeyValueConsistency() is untested. No test exercises a semantic key (key !== value in en.js). A future refactor could silently break the exception logic. |
Add a test in check-i18n.test.ts with a fixture containing a semantic key: verify that a key in the exceptions set does NOT produce an error, and a key NOT in the set DOES produce a "Key-value mismatch" error. |
— qwen3.7-max via Qwen Code /review
| expect(result.type).toBe('message'); | ||
| expect(result.messageType).toBe('info'); | ||
| expect(result.content).toContain('auto-edit'); | ||
| expect(result.content).toContain('auto-accept edits'); |
There was a problem hiding this comment.
[Critical] The PR adds emitAutoModeEntryNotices() in approvalModeCommand.ts when switching to AUTO mode via the slash command, but this test file has no test case for the auto argument. Tests exist for plan, yolo, auto-edit, and default, but the new auto code path (the only place where the slash command triggers notice emission) is untested.
Add a test case similar to the existing mode tests:
it('should set approval mode to "auto" and emit entry notices', async () => {
const result = (await approvalModeCommand.action?.(mockContext, 'auto')) as MessageActionReturn;
expect(result.type).toBe('message');
expect(result.messageType).toBe('info');
expect(result.content).toContain('Auto mode');
expect(mockSetApprovalMode).toHaveBeenCalledWith('auto');
// Verify addItem was called with the auto-mode entry notice
});— qwen3.7-max via Qwen Code /review
wenshao
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline.
| @@ -19,6 +19,8 @@ export default { | |||
| 'Shell mode': 'シェルモード', | |||
| 'YOLO mode': 'YOLOモード', | |||
| 'Auto mode': 'Autoモード', | |||
There was a problem hiding this comment.
[Suggestion] 'Auto mode' is translated as 'Autoモード' (Latin "Auto") here, but the auto_mode.entry_notice at line 23 uses '自動モードが有効です' (native Japanese 自動モード). This is the same class of mixed-language inconsistency that this PR fixed for Chinese ('Auto 模式' → '自动模式'). Consider aligning the Japanese locale to use '自動モード' consistently.
| 'Auto mode': 'Autoモード', | |
| 'Auto mode': '自動モード', |
— qwen3.7-max via Qwen Code /review
| ' An LLM classifier evaluates each tool call — safe actions auto-approve,\n' + | ||
| ' An LLM classifier evaluates each tool call - safe actions auto-approve,\n' + | ||
| ' risky ones are blocked. Exit: Shift+Tab or /approval-mode default.'; | ||
|
|
There was a problem hiding this comment.
[Suggestion] The fallback branch of getAutoModeFirstTimeMessage() (when t() returns the raw key because the locale is missing) is never exercised by tests. All four emitAutoModeEntryNotices test cases call setLanguageAsync('en') or setLanguageAsync('zh') first, so they always hit the translated path. A single test asserting the fallback text when i18n is uninitialized (or using a locale without the key) would close this coverage gap.
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No review findings. Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x).
— qwen3.7-max via Qwen Code /review
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestion-level recommendations are in the Suggestion summary comment below.
✅ Maintainer local verification (macOS) — all greenI built and ran this PR from a clean isolated checkout to validate it before merge. Everything passes, and the localization fix behaves exactly as described. This run also covers the macOS gap the PR marked as "not tested". Environment
Results
Behavioral evidence (real component render, Chinese UI)Rendered the actual Footer indicator — AUTO mode,
Notes for the reviewer
Verdict: LGTM — safe to merge. Scope is tight (UI labels + i18n keys), fully covered by tests, and green on macOS in addition to the author's Windows testing. 中文版本(点击展开)✅ 维护者本地验证(macOS)— 全部通过我在一个干净、隔离的 checkout 中构建并运行了本 PR,以便在合并前进行验证。所有检查均通过,本地化修复的行为与描述完全一致。本次验证同时补齐了 PR 中标记为「未测试」的 macOS 平台。 环境
结果
行为证据(真实组件渲染,中文界面)通过真实 i18n 引擎渲染了实际的 底部状态栏 — AUTO 模式,
给 Reviewer 的说明
结论:LGTM —— 可以安全合并。 改动范围很小(UI 标签 + i18n key),已被测试完全覆盖,且在作者的 Windows 测试之外,在 macOS 上同样全绿。 |
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
* 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(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>
What this PR does
Localizes approval-mode switching UI labels so AUTO mode no longer falls back to raw English text in localized sessions. The footer indicator now uses the existing localized
Auto modelabel, approval-mode display names now go through the i18n helper instead of returning raw enum values, and the first-time AUTO mode notice is translated for English, Simplified Chinese, and Traditional Chinese.Why it's needed
When the UI language resolves to Chinese, cycling approval modes with Shift+Tab can show mixed-language output such as
auto mode (classifier-evaluated)while the surrounding UI is localized. This makes the approval-mode switching experience inconsistent.Reviewer Test Plan
How to verify
Run the focused tests for the approval-mode indicator, display helper, and AUTO mode notice:
Run the i18n check:
Optionally start the CLI in a Chinese UI environment and cycle approval modes with Shift+Tab. AUTO mode should show localized labels/notices instead of
auto mode (classifier-evaluated).Evidence (Before & After)
Before: In the released
qwenv0.19.8, Chinese UI still showsauto mode (classifier-evaluated)in the approval-mode indicator.Before screenshot:

After: In the local source checkout on this branch, AUTO mode is displayed as
自动模式.After screenshot:

Tested on
Environment (optional)
Tested with Node.js v24.14.0 in the local source checkout. Manual before/after verification was done on Windows PowerShell.
Risk & Scope
Linked Issues
Fixes #6582
中文说明
这个 PR 做了什么
本 PR 对审批模式切换 UI 做了本地化修复,使 AUTO 模式在中文等本地化界面中不再回退显示原始英文文案。底部状态栏现在复用已有的
Auto mode翻译,审批模式显示名称现在统一通过 i18n helper 返回,而不是直接返回枚举值;首次进入 AUTO 模式的提示也补充了英文、简体中文、繁体中文翻译。为什么需要
当 UI 语言解析为中文时,使用 Shift+Tab 切换审批模式可能会出现混合语言输出,例如
auto mode (classifier-evaluated),而周围 UI 已经是中文。这会导致审批模式切换体验不一致。Reviewer Test Plan
如何验证
运行 approval-mode indicator、display helper 和 AUTO mode notice 的 focused tests:
运行 i18n 检查:
也可以在中文 UI 环境中启动 CLI,并使用 Shift+Tab 循环切换审批模式。AUTO 模式应显示本地化后的标签和提示,而不是
auto mode (classifier-evaluated)。证据(修改前后)
修改前:在发布版
qwenv0.19.8 中,中文 UI 的审批模式状态栏仍显示auto mode (classifier-evaluated)。修改前截图:

修改后:在本分支的本地源码 checkout 中,AUTO 模式显示为
自动模式。修改后截图:

测试平台
环境(可选)
在本地源码 checkout 中使用 Node.js v24.14.0 测试。修改前后手动验证在 Windows PowerShell 中完成。
风险和范围
关联 Issue
Fixes #6582