feat(ink): auto compat mode for legacy pre-ConPTY Windows consoles#1299
Conversation
Windows 10 build < 17763(1709/LTSC 等无 ConPTY 的内网机器)上, 老 conhost 的 VT 解析器对增量渲染的行尾 pending-wrap 语义处理有误, 真实光标与虚拟光标漂移,花屏残渣持续累积,直到一次全量重绘才消除。 该问题影响此类机器上的所有终端(VS Code/mintty 走 winpty 抓取的 是同一份损坏的 conhost buffer)。 - 新增 legacyConsole.ts:按 os.release() build 号自动检测, CLAUDE_CODE_LEGACY_CONSOLE=1/0 可强制开/关 - log-update.ts:命中时每约 1 秒用一次全量重绘替换增量 diff, 屏幕持续自愈;非老控制台环境完全不走此路径 - 6 个单元测试(检测逻辑 + 环境变量覆盖 + 缓存行为)
📝 WalkthroughWalkthroughAdds cached legacy Windows console detection, environment-controlled modes and reset intervals, legacy-aware terminal sizing, and periodic or always-on full resets in Ink rendering. Tests cover parsing, clamping, caching, and width behavior; architecture documentation describes the configuration. ChangesLegacy console compatibility
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant Ink
participant effectiveColumns
participant LogUpdate.render
participant fullResetSequence_CAUSES_FLICKER
Ink->>effectiveColumns: calculate legacy-aware terminal width
LogUpdate.render->>fullResetSequence_CAUSES_FLICKER: generate clear reset when mode and cadence allow
fullResetSequence_CAUSES_FLICKER-->>LogUpdate.render: return full reset sequence
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
真机(1709/build 16299)第一轮验证反馈周期性自愈可能不足, 增加两个调节旋钮: - CLAUDE_CODE_LEGACY_CONSOLE=2(或 always):每帧全量重绘, 用于增量 diff 立即花屏、1 秒自愈不够的机器 - CLAUDE_CODE_LEGACY_CONSOLE_RESET_MS:周期模式的重绘间隔, 钳制在 [100, 10000],默认 1000 不变 默认行为不变(自动检测 → periodic 1s)。新增 9 个单元测试 (模式解析、间隔钳制、空串回退、缓存行为)。
真机(1709/build 16299)第二轮反馈:周期性全量重绘在跑(可见闪烁) 但花屏范围随重绘扩大。定位到真正根因:老 conhost 对 pending-wrap 的处理是「写满最后一列立即换行」(现代终端为挂起等待),任何顶满 行宽的输出(分隔线、满行文本)都会把真实光标多推一行——增量 diff 和全量重绘同样受害,且每次重绘还把缓冲区多滚几行,旧帧残渣上移, 表现为「越闪越花」。 修复:legacy 模式下 effectiveColumns() 把渲染宽度收窄 1 列 (下限 20),任何一行都不再触碰最后一列,pending-wrap 缺陷路径 从源头绕开;周期重绘保留作为兜底自愈。非 legacy 环境行为完全不变。 新增 effectiveColumns 单元测试;ink.tsx 三处宽度读取统一走该函数。
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/`@ant/ink/src/core/ink.tsx:
- Line 96: Update the effectiveColumns import in ink.tsx to use the configured
src/* alias and explicit .ts extension instead of the relative .js specifier.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 36240f42-a599-4600-9f39-5fb99cd2fd57
📒 Files selected for processing (3)
packages/@ant/ink/src/core/__tests__/legacyConsole.test.tspackages/@ant/ink/src/core/ink.tsxpackages/@ant/ink/src/core/legacyConsole.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/@ant/ink/src/core/legacyConsole.ts
- packages/@ant/ink/src/core/tests/legacyConsole.test.ts
| wrapForMultiplexer, | ||
| } from './termio/osc.js'; | ||
| import { TerminalWriteProvider } from '../hooks/useTerminalNotification.js'; | ||
| import { effectiveColumns } from './legacyConsole.js'; |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use the configured src/* alias and .ts extension.
This import uses a relative .js specifier, but the repository guidelines require TypeScript source imports under src to use the src/* alias and .ts extensions.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/`@ant/ink/src/core/ink.tsx at line 96, Update the effectiveColumns
import in ink.tsx to use the configured src/* alias and explicit .ts extension
instead of the relative .js specifier.
Source: Coding guidelines
|
真机验证结果(Windows 10 1709 / build 16299,内网机器,cmd 窗口):宽度收窄修复(515cf9a5)验证通过,花屏消除、无明显闪烁。 排查中的关键反证记录:仅靠周期性全量重绘(初版方案)在该机器上花屏范围会随重绘扩大——原因是重画整帧的过程中,满宽行同样触发老 conhost 的 pending-wrap 立即换行缺陷,每次重绘还会把缓冲区多滚几行、旧残渣上移。宽度收窄 1 列后任何行都不触碰最后一列,增量与全量路径同时被根治;周期重绘保留为兜底。 |
Summary
Windows 10 build < 17763(1809 之前,无 ConPTY——1709、各类 LTSC/LTSB 内网机器)上,老 conhost 对 pending-wrap 的处理是"写满最后一列立即换行"(现代终端为挂起等待下一字符)。任何顶满行宽的输出(分隔线、满行文本)都会让真实光标比渲染器认为的位置多走一行——增量 diff 持续漂移产生花屏,全量重绘在重画过程中同样触发该缺陷、且每次多滚几行使旧残渣上移。这类机器上所有终端都受影响:VS Code 集成终端和 mintty 走 winpty,抓的是同一份损坏的 conhost buffer。
本 PR 增加「老控制台自动兼容模式」,根治手段是渲染宽度收窄 1 列:任何一行永远不写到最后一列,缺陷路径从源头绕开;周期性全量重绘保留作为兜底自愈。非老控制台环境完全不走此分支,零影响。
Changes
packages/@ant/ink/src/core/legacyConsole.tsos.release()build < 17763 时自动判定为老控制台(进程内缓存)effectiveColumns():legacy 模式下渲染宽度收窄 1 列(下限 20)——根治花屏CLAUDE_CODE_LEGACY_CONSOLE=0/1/2|always(关 / 周期重绘 / 每帧全量重绘)、CLAUDE_CODE_LEGACY_CONSOLE_RESET_MS(周期间隔,钳制 100–10000ms,默认 1000)packages/@ant/ink/src/core/ink.tsxeffectiveColumns()packages/@ant/ink/src/core/log-update.tsfullResetSequence_CAUSES_FLICKER路径),作为兜底自愈排查历程(真机)
问题在一台 Windows 10 1709(build 16299)内网机器上定位与验证,三轮迭代:
Testing
effectiveColumns收窄与下限、检测结果缓存行为tsc/biome零错误;非 Windows 及 build ≥ 17763 环境不进入该分支,行为不变