fix(cli): prevent input border overflow on resize - #8991
Conversation
E2E Test ReportResult: PASS Environment
Steps and observation
The displayed width is 11 terminal cells, with no stray Deterministic regression evidence
The focused component suite passed: 14/14 tests. CLI typecheck and build also passed. Preflight note
|
|
Thanks for the PR! Re-run at the second commit (
Moving on to code review. 🔍 中文说明感谢贡献!本次为第二个提交(
进入代码审查。🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewRe-run at the second commit. My independent proposal from the title and motivation alone: bound the label to the available width before the dash arithmetic (reserving one leading dash, two spaces, two trailing dashes), drop the label when that budget is non-positive, and reuse the repo's existing width-aware truncation helper rather than adding a new one. That is exactly what this PR does; the second commit then replaced the magic numbers with named constants and strengthened the tests. The arithmetic holds in every case — traced against
Dropping the
No blockers, no convention violations. Test evidenceUnattended run — I don't execute PR code; the evidence below is the PR's own CI on the reviewed commit, read via the API. All checks on CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Sandboxed verification would settle the remaining gap: 中文说明代码审查在第二个提交上重新审查。仅凭标题与动机,我的独立方案是:在横线计算之前先把标题限制在可用宽度内(预留 1 根前导横线、2 个空格、2 根尾部横线),预算非正时隐藏标题,并复用仓库现有的宽度感知截断工具而不是新写一个。这个 PR 的做法与此完全一致;第二个提交随后把魔法数字替换为具名常量并加强了测试。 对照
移除
无阻塞问题,无规范违规。 测试证据无人值守运行——我不执行 PR 代码;以下证据是通过 API 读取的该提交上的 PR 自身 CI。 沙盒验证可以补上剩余缺口: — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 4/5 — clean, minimal fix for a maintainer-confirmed root cause with fully green CI on the reviewed commit; the only residual is evidentiary — the live drag symptom is pinned by unit-level width invariants and the author's macOS-only PTY claim, not by cross-platform live testing. This is what a good fix in this area looks like. The problem is real — #8849 was filed by a maintainer and the off-by-one arithmetic re-derives cleanly from the base code — and the diff is the minimal shape of the solution: bound the label with the existing The reservations are evidentiary, not about the code: CI is now fully green on 中文说明置信度:4/5 —— 针对维护者已确认根因的干净、最小修复,所审提交上 CI 全绿;唯一的保留项在证据层面——拖窄窗口的实际抖动症状仅由单测层面的宽度不变式和作者仅在 macOS 上的 PTY 自述支撑,尚无跨平台实测。 这是该领域一个良好修复的样子。问题是真实的——#8849 由维护者提交,off-by-one 算术可以从 base 代码干净地重新推演出来——diff 也是解决方案的最小形态:先用现有的 保留意见在证据而非代码:CI 现已在 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed. Suggestions are inline.
Not explored to full depth (tool budget reached): This PR fixes the TUI input-box top border overflowing th...: running BaseTextInput.test.tsx to execute-verify the width invariant (analytic verification done instead)..
Test Plan (not a blocker): 14 tests should pass — this review observed 19138 passed.
中文说明
已审查。 建议见行内评论。
未探索到全部深度(达到工具调用预算):This PR fixes the TUI input-box top border overflowing th...:running BaseTextInput.test.tsx to execute-verify the width invariant (analytic verification done instead).。
Test Plan(非阻断):14 tests should pass — this review observed 19138 passed。
— qwen3.8-max via Qwen Code /review (v0.21.10)
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Not explored to full depth (tool budget reached): This PR fixes the TUI input-box top border overflowing th...: none — all planned checks completed within budget.; This PR fixes the TUI input-box top border overflowing th...: none — all checks I wanted to do are complete. About 16 tool calls used.I have completed a full walk of the PR. No new gaps found beyond the two existing findin….
中文说明
已审查。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
未探索到全部深度(达到工具调用预算):This PR fixes the TUI input-box top border overflowing th...:none — all planned checks completed within budget.;This PR fixes the TUI input-box top border overflowing th...:none — all checks I wanted to do are complete. About 16 tool calls used.I have completed a full walk of the PR. No new gaps found beyond the two existing findin…。
— qwen3.8-max via Qwen Code /review (v0.21.10)
doudouOUC
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
Not explored to full depth (tool budget reached): This PR fixes the TUI input-box top border overflowing th...: none. I completed all planned checks within the tool budget..
中文说明
未发现问题。LGTM!✅
未探索到全部深度(达到工具调用预算):This PR fixes the TUI input-box top border overflowing th...:none. I completed all planned checks within the tool budget.。
— deepseek-v4-flash via Qwen Code /review (v0.21.10)
doudouOUC
left a comment
There was a problem hiding this comment.
Reviewed.
Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.
Not explored to full depth (tool budget reached): PR #8991 fixes a TUI bug where the labelled input-box top...: none.**Verdict: no findings.**; PR #8991 fixes a TUI bug where the labelled input-box top...: run the PR's actual BaseTextInput.test.tsx via vitest (worktree node_modules incomplete; compensated by the simulation above plus the function's existing comm…; PR #8991 fixes a TUI bug where the labelled input-box top...: could not execute the new vitest cases to green in this worktree (environment-only vite resolution failure, unrelated to the diff); their expected values were v….
中文说明
已审查。
未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。
未探索到全部深度(达到工具调用预算):PR #8991 fixes a TUI bug where the labelled input-box top...:none.**Verdict: no findings.**;PR #8991 fixes a TUI bug where the labelled input-box top...:run the PR's actual BaseTextInput.test.tsx via vitest (worktree node_modules incomplete; compensated by the simulation above plus the function's existing comm…;PR #8991 fixes a TUI bug where the labelled input-box top...:could not execute the new vitest cases to green in this worktree (environment-only vite resolution failure, unrelated to the diff); their expected values were v…。
— qwen3.8-max via Qwen Code /review (v0.21.10)
|
@wenshao Hi, this PR has green CI, maintainer approval, and no findings in the latest review rounds. When you have a moment, could you please take a look and merge it if appropriate? Thanks! |
|
@qwen-code /triage |
|
Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 77 passed · 0 failed · 77 total Flakiness gate: ✅ 1 changed test file(s) x 5 identical rounds, no divergence 中文 — 判定:✅ 通过 · 可合入(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:77 通过 · 0 失败 · 77 总计 抖动门:✅ 1 changed test file(s) x 5 identical rounds, no divergence Verification reportPR #8991 — fix(cli): prevent input border overflow on resizeVerdict: 中文摘要
Central claim + A/BCentral claim: the labelled top border never emits more cells than the terminal width; when the label cannot fit it is truncated with Secondary claims: (1) the truncation holds for width-2 and multi-codepoint labels (CJK, emoji, ZWJ, combining, astral); (2) the four new tests pin the fix (non-vacuous). Harness:
Base overflows in 12/18 cells by exactly the predicted amount; the 6 cells where base fits are identical on both arms (validity controls). Head: 0/18 overflows. Resize recovery (test-plan step 2 shape): head @11 → LN-mode probe (ink layout width set equal to terminal width — the real-terminal shape): head emits ≤ columns; base's 12-cell line is clipped by ink's own Corrections to the description
Findings (informational, non-blocking)
Reviewer Test Plan walk-through
Vacuity + mutation matrixVacuity (full revert of Mutation matrix (each row: mutate → run suite → restore; witness
No survivors among PR-introduced guards; M7 proves the command collects tests that pin the mutated file. Not covered
MethodologyEnvironment: node v22.23.2, vitest 3.2.7, ink 7.0.3, ink-testing-library (layout fixed at 100 cols). A/B harness ( Flakiness gate logEvidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Maintainer local verification — ✅ merge-ready (16/16 assertions, 0 unexpected failures)Verified head Central claim — proven load-bearingFor any terminal width and label, the labelled input-box top border renders at exactly the terminal width (label truncated with
Real TUI (bundled CLI, tmux PTY, 11 columns,
|
| arm | top border row | cells |
|---|---|---|
| base | ─ session … — ink wrap="truncate-end" silently replaces the closing ── with its own ellipsis |
11 (damaged) |
| head | ─ sessi… ── — label truncated, border intact |
11 (exact) |
Widening 11 → 40 columns restores the full title (… session ──). Correction to the description: the static symptom at 11 columns is ink truncation (dashes lost), not a wrap — the wrap/jitter is the resize-transition symptom of the same one-cell overflow; root cause confirmed either way.
Vacuity + gates
Reverting only the source hunk turns 3/4 new test cases red (AssertionError: expected 12 to be 4); the 4th is a fitting-label regression guard. Restored: 16/16. Base pre-existing suite: 12/12. npm run typecheck (packages/cli): exit 0. Note: the reviewer plan says "14 tests"; the file runs 16 (12 pre-existing + 4 new) — doc drift only.
Findings (none blocking)
- [Low · pre-existing class] Zero-width chars (
U+200B, standaloneU+200D) keep the overflow door open under a different width table:packages/cliusesstring-width@7.2.0(counts them 0) while@5.1.2and some terminals count 1 — 21/169 head cells exceed under the v5 table. Not reproduced in a real terminal (tmux/utf8proc also counts 0); bounded to crafted session names. Suggested follow-up, not a merge condition. - [Info · intended] Labels hidden at ≤5 columns matches the stated tradeoff.
Not covered
Windows/Linux manual resize (PR marks
中文摘要
结论:可合并(merge-ready),16/16 断言通过。
- A/B 主张成立:169 格扫描中 base 溢出 68 格,head 0 格;head 边框宽度每格精确等于终端列数;≤5 列按设计隐藏标签。
- 真实终端:tmux 11 列下 base 边框被 ink 截断为
─ session …(收尾横线丢失),head 精确渲染─ sessi… ──;拉宽到 40 列完整标题恢复。勘误:静态症状是截断而非换行,换行抖动是缩放过渡症状,机制(多一格)与描述一致。 - 无回归:base 本就正确的 101 格中 head 100 格字节级一致;唯一差异是新"<6 列隐藏"语义(预期)。
- 测试有效:revert 源 hunk 后 3/4 新用例变红,恢复后 16/16 绿;base 旧套件 12/12;typecheck 通过。描述中"14 个测试"实为 16(文档小偏差)。
- 发现(不阻塞):零宽字符宽度表分歧(v7 记 0 宽、v5/部分终端记 1 格,21/169 格在 v5 表下仍溢出),tmux 实测未复现,建议后续处理。
- 未覆盖:Windows/Linux 缩放、Footer pill(另一 issue)、全仓库套件。
|
Released in v0.22.2. |






What this PR does
Constrains the labelled input-box top border to the current terminal width. When a session title cannot fit, it is truncated by terminal display width with an ellipsis while preserving the surrounding border; at extremely narrow widths, the label is hidden and the border remains width-safe.
Why it's needed
During terminal resize, the previous border arithmetic always kept at least one leading dash without first bounding the label. At the exact boundary where the label and decorations filled the viewport, the resulting row was one cell too wide, so the final dash could wrap and make the input box jitter down by one row.
Reviewer Test Plan
How to verify
/rename session, and resize the terminal to 11 columns. Confirm the top border remains a single row and reads─ sessi… ──.cd packages/cli && node ../../node_modules/vitest/vitest.mjs run src/ui/components/BaseTextInput.test.tsx --maxWorkers=1; all 14 tests should pass, including ASCII and CJK width boundaries.npm run typecheckandnpm run buildfrom the CLI package; both should pass.Evidence (Before & After)
─ session ──— 12 cells─ sessi… ──— 11 cells─ 会话标题 ──— 13 cells─ 会话标… ──— 12 cellsA real PTY run on macOS resumed the
sessionconversation at 11 columns and rendered─ sessi… ──on one row with no stray border fragment.Tested on
Environment (optional)
Node.js 22, local source checkout, an 11x30 PTY, safe and bare modes, and an isolated temporary Qwen home. No model request was sent.
The repository preflight was also executed. Formatting, lint, builds, and typechecks passed; the exhaustive test stage returned non-zero in unrelated existing concurrency, bundle-drift, UI timing, and proxy-environment tests. The focused regression suite passed after those failures were isolated and rerun.
Risk & Scope
Linked Issues
Fixes #8849
中文说明
本 PR 做了什么
将带标题的输入框上边框严格限制在当前终端宽度内。当会话标题放不下时,按终端显示宽度截断并添加省略号,同时保留两侧边框;终端极窄时隐藏标题,确保边框始终不会溢出。
为什么需要
终端缩放过程中,原先的边框计算会强制至少保留一个左侧横线,却没有先限制标题宽度。当标题与装饰恰好占满视口时,最终构造出的整行会多出一格,末尾横线可能自动换行,从而导致输入框向下抖动一行。
Reviewer 测试计划
如何验证
/rename session,把终端缩到 11 列。确认上边框保持单行并显示为─ sessi… ──。cd packages/cli && node ../../node_modules/vitest/vitest.mjs run src/ui/components/BaseTextInput.test.tsx --maxWorkers=1;14 个测试应全部通过,其中包括 ASCII 与 CJK 宽度边界。npm run typecheck和npm run build;两者都应通过。前后证据
─ session ──— 12 格─ sessi… ──— 11 格─ 会话标题 ──— 13 格─ 会话标… ──— 12 格在 macOS 真实 PTY 中,以 11 列恢复名为
session的会话后,上边框稳定地在一行内显示为─ sessi… ──,没有出现游离的边框碎片。已测试平台
环境(可选)
Node.js 22、本地源码、11x30 PTY、safe 与 bare 模式,以及隔离的临时 Qwen 主目录。未发送任何模型请求。
同时执行了仓库 preflight。格式化、lint、构建和类型检查均通过;全量测试阶段仅在与本改动无关的既有并发、bundle 漂移、UI 时序和代理环境测试中以非零状态结束。隔离并复跑这些失败后,本次修复的定向回归测试通过。
风险与范围
关联 Issue
Fixes #8849