mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-08-26 09:04:37 +00:00
* fix(cli): skip terminal redraw optimizer on WSL/ConPTY and enable sync output on Windows Terminal (#7634) The streaming text repetition bug on WSL + Windows Terminal is caused by the terminal redraw optimizer batching cursor-up sequences, which ConPTY processes differently from individual per-line erases. The cursor lands at the wrong row, causing each new frame to overlap remnants of the previous one. Two fixes: 1. Skip the redraw optimizer when WSL (WSL_DISTRO_NAME / WSL_INTEROP) or Windows Terminal (WT_SESSION) is detected, falling back to Ink's original per-line erase sequences that ConPTY handles correctly. 2. Enable synchronized output (DEC mode 2026) for Windows Terminal, which has supported it since v1.6, making frame updates atomic and masking any residual cursor positioning issues. Fixes #7634 * fix: add WSL_INTEROP test and clear env vars in beforeEach to fix test fragility Address review feedback on #7897: - P1: clear WSL/Windows Terminal env vars in beforeEach so existing optimizer tests don't silently break when run inside WSL - P2: add dedicated test for WSL_INTEROP detection * review: address wenshao feedback on #7897 - Accept injectable env in installTerminalRedrawOptimizer (matches sibling terminalSupportsSynchronizedOutput), eliminating the need for beforeEach env-stubbing in test files - Add QWEN_CODE_LEGACY_ERASE_LINES=0 as a force-on escape hatch for WSL/Windows Terminal users whose terminals handle the batched sequences correctly - Collapse three near-identical WSL/WT skip tests into it.each - Correct Windows Terminal DEC 2026 support version: v1.18, not v1.6 - Move WT_SESSION check above the TERM declaration in terminalSupportsSynchronizedOutput so the term isn't declared before its only consumer - Add a table case asserting TMUX guard still wins over WT_SESSION - Pass explicit empty env to installTerminalRedrawOptimizer in the synchronizedOutput composition test so it doesn't depend on the runner's environment * fix(cli): narrow optimizer skip to WSL only, drop WT_SESSION Per wenshao's review: WT_SESSION is set on the Windows side and is not propagated into WSL shells without WSLENV, so it can never be the env var that fires for #7634. Remove WT_SESSION from the optimizer skip (WSL_DISTRO_NAME + WSL_INTEROP remain) and from the synchronized-output allowlist. The synchronized-output change for Windows Terminal belongs in its own PR once confirmed; bundling it into a WSL bug fix mixed two independent behavior changes. Also correct the comment: 'WSL or Windows Terminal' -> 'WSSL only', and remove the WT_SESSION test cases from both test files. * fix(cli): clean up WT_SESSION comment residue and pin its exclusion Per review: the drop of the WT_SESSION skip left stale comments and no test pinning the deliberate exclusion. Fix the force-enable comment (WSL only, not Windows Terminal), complete the truncated WT_SESSION rationale, and add a test asserting WT_SESSION alone does NOT trigger the skip (it is not propagated into WSL shells). Also stub QWEN_CODE_LEGACY_ERASE_LINES in beforeEach so the suite is isolated from a host that has the flag set. * refactor(cli): extract shared isWsl(env) into terminal-env util WSL detection was inlined in terminalRedrawOptimizer (this PR) and duplicated as a private helper in voice-availability. Extract a single isWsl(env) into ui/utils/terminal-env.ts and use it from both sites so the marker set cannot drift. Requested by maintainer in #7897 reviews. * fix(ui): add license header and gate WSL_INTEROP in voice preflight Round-3 review: terminal-env.ts shipped without the @license header every sibling carries; and the voice-side isWsl migration was inert under the test probe because voice-availability.test.ts only exercised the WSL_DISTRO_NAME marker. Add the header and cover WSL_INTEROP via it.each. #7897 * docs(ui): note the separate core-side WSL check in terminal-env Round-4 review: the extraction comment claimed the marker set cannot drift, but ripgrepUtils.wslTimeout() in packages/core keeps its own narrower WSL_INTEROP-only check because core cannot import from cli. Document the exception so a future maintainer greps both sites. #7897 * docs(cli): document QWEN_CODE_LEGACY_ERASE_LINES escape hatch Round-5 review (R5-1): isWsl(env) relies solely on env markers, which env-scrubbing launchers (sudo, env -i) strip - so the #7634 skip never fires in those contexts. Document the launch-time =1 fallback and note it must be passed at launch because sudo drops the flag too. Also closes the round-2 R2-3 gap (the flag was previously undocumented). #7897 * refactor(cli): move isWsl to core and apply maintainer review polish wenshao's manual review suggested moving the shared WSL marker check to packages/core so cli can import it (core cannot import from cli), while ripgrepUtils.wslTimeout() keeps its deliberately narrower predicate. Also: - Sharpen the ConPTY divergence comment with the concrete sequences the optimizer emits (CSI 1 B cursor-down, CSI n A multi-count) that Ink's native erase path never does. - Replace the beforeEach vi.stubEnv test fixture with explicit empty-env arguments (truer 'not on WSL' fixture, no host-env dependency). - Note the env parameter exists for testability. - Trim the moved file's doc block to durable facts and tighten the docs row wording. #7897 * test(cli): pin the env default-parameter seam in redraw optimizer Round-7 review: the production call path (installTerminalRedrawOptimizer with no env arg) was never exercised - every test passed env explicitly, so a mutation to the = process.env default (e.g. = {}) would pass green while silently disabling the WSL skip and =1 escape hatch in production. Add a hermetic test that stubs WSL_DISTRO_NAME and asserts the no-arg call skips the optimizer. #7897 * test(cli): restore afterEach env cleanup for default-seam test Round-8 review: placing vi.unstubAllEnvs() as the last statement in the default-seam test body meant a failing expect (the exact regression the test pins) would skip the cleanup and leak WSL_DISTRO_NAME=Ubuntu into process.env for the rest of the file. Move the cleanup back into the describe-level afterEach so it runs even on assertion failure. #7897 * test(cli): close the two minor coverage gaps from chiga0's review Maintainer chiga0 approved the PR but noted two minor test gaps: - The default-seam test only stubbed WSL_DISTRO_NAME, so a host-set QWEN_CODE_LEGACY_ERASE_LINES=1 would pass it for the wrong reason; stub the flag too so the assertion depends only on the WSL marker. - The tri-state flag has no case for a non-standard truthy value; add one pinning that 'garbage' falls through to the platform default (WSL skip). #7897 * docs(cli): correct 'only path' claim in ConPTY divergence comment Round-11 review: the comment asserted the optimizer is the ONLY path emitting CSI 1 B / CSI n A, but the repo's patched ink build also emits both sequence classes on its cursor-positioning path (buildCursorSuffix / buildReturnToBottom, reachable via BaseTextInput.setCursorPosition). Skipping the optimizer on WSL does not remove these from interactive input. Narrow the claim to the per-frame erase-and-redraw path. #7897 |
||
|---|---|---|
| .. | ||
| configuration | ||
| extension | ||
| features | ||
| ide-integration | ||
| reference | ||
| support | ||
| _meta.ts | ||
| common-workflow.md | ||
| integration-github-action.md | ||
| integration-jetbrains.md | ||
| integration-vscode.md | ||
| integration-zed.md | ||
| overview.md | ||
| quickstart.md | ||
| qwen-serve-deploy-local.md | ||
| qwen-serve.md | ||