Skip to content

fix(cli): preserve slash command names in narrow terminals - #8657

Merged
carffuca merged 1 commit into
QwenLM:mainfrom
carffuca:fix/slash-command-name-truncation
Aug 7, 2026
Merged

fix(cli): preserve slash command names in narrow terminals#8657
carffuca merged 1 commit into
QwenLM:mainfrom
carffuca:fix/slash-command-name-truncation

Conversation

@carffuca

@carffuca carffuca commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Keeps slash-command names intact when the completion menu has limited horizontal space. Argument hints continue to yield space by wrapping, so the actionable command token remains trustworthy.

Why it's needed

The command name, argument hint, and source badge previously shared a shrinkable row. On narrower terminals this could render review as revie and doctor as docto, misleading users into typing a command that does not exist.

Reviewer Test Plan

How to verify

Open the interactive CLI in a narrow terminal, type /rev and /doc, and confirm the completion list always shows the complete review and doctor command names while long argument hints wrap onto following lines.

Evidence (Before & After)

Before: at width 120, review rendered as revie and doctor rendered as docto.
image

After: at width 120, both command names render completely and their argument hints wrap to preserve the names.
image

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

Environment (optional)

Node.js v24.14.0, Ink 7.0.3. Focused component tests pass 10/10; build, bundle, and targeted ESLint pass. Repository-wide typecheck remains blocked by pre-existing upstream Ink type errors involving selection APIs.

Risk & Scope

  • Main risk or tradeoff: Long argument hints may occupy additional lines in narrow terminals so command names remain complete.
  • Not validated / out of scope: Windows and Linux interactive terminal rendering.
  • Breaking changes / migration notes: None.

Linked Issues

N/A

中文说明

本 PR 的改动

在补全菜单横向空间不足时保持斜杠命令名称完整。参数提示仍可通过换行让出空间,确保用户看到的可执行命令名称可信。

改动原因

此前命令名称、参数提示和来源标识位于同一个可收缩布局中。在较窄的终端里,review 可能显示成 reviedoctor 可能显示成 docto,从而误导用户输入不存在的命令。

Reviewer Test Plan

验证方式

在较窄的终端中启动交互式 CLI,分别输入 /rev/doc,确认补全列表始终完整显示 reviewdoctor,较长的参数提示则换行显示。

前后对比证据

修复前:宽度为 120 时,review 显示为 reviedoctor 显示为 docto

修复后:宽度为 120 时,两个命令名称都完整显示,参数提示通过换行保留命令名称。

测试平台

OS 状态
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

环境(可选)

Node.js v24.14.0,Ink 7.0.3。定向组件测试 10/10 通过;构建、bundle 和目标 ESLint 均通过。仓库级 typecheck 仍被 upstream 已存在的 Ink selection API 类型错误阻塞。

风险与范围

  • 主要风险或权衡:为了保持命令名称完整,较长的参数提示可能在窄终端中占用额外行。
  • 未验证或不在范围内:Windows 和 Linux 的交互式终端渲染。
  • 破坏性变更或迁移说明:无。

关联 Issue

N/A

@carffuca
carffuca marked this pull request as ready for review August 7, 2026 02:30
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finished — CI landed green on 64bb8ed and the deferred approval was posted. finalize run

Qwen Triage 已完成 —— 64bb8ed 的 CI 全绿,延迟审批已提交。查看 finalize 运行

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

  • Template: complete, with before/after screenshots ✓
  • Problem: real, observed bug — reproduction is described (narrow terminal, /rev / /doc) and the before/after screenshots at width 120 show review rendering as revie. I confirmed the mechanism in the code: inside the fixed-width label column the name, argument hint, and badge are all shrinkable flex children, so the name itself genuinely truncates when a hint overflows.
  • Direction: aligned. A command name is an actionable token — a truncated name invites users to type a command that doesn't exist. No direct CHANGELOG reference, but the area is relevant (plenty of rendering/truncation fixes upstream).
  • Size: not core paths (packages/cli/src/ui/components/) — 2 production lines + 35 test lines.
  • Approach: minimal — making the label non-shrinkable so hints and badges yield by wrapping is the smallest change that achieves the stated goal, and the diff carries nothing unrelated. The new test pins exactly the reported scenario.
  • Risk: no elevated risk signals (no high-risk path matches).

Moving on to code review. 🔍

中文说明

感谢贡献!

  • 模板:完整,附 before/after 截图 ✓
  • 问题:真实可复现的 bug——给出了复现方式(窄终端下输入 /rev / /doc),宽度 120 的截图显示 review 被截成 revie。代码层面也确认了机制:固定宽度的标签列里,命令名、参数提示和来源标识都是可收缩的 flex 子元素,提示溢出时命令名确实会被截断。
  • 方向:对齐。命令名是可执行的 token——截断的名字会误导用户输入不存在的命令。CHANGELOG 无直接条目,但该领域相关(上游有不少渲染/截断类修复)。
  • 规模:非核心路径(packages/cli/src/ui/components/)——生产代码 2 行 + 测试 35 行。
  • 方案:最小改动——把标签设为不可收缩、让参数提示和标识通过换行让出空间,正是达成目标的最小改动,diff 中没有夹带无关内容。新增测试也固定了所报告的场景。
  • 风险:无升级风险信号(未命中高风险路径)。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at 64bb8ed64402e08c509f63bd5bf2dedd7b7a7d79 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Code review

My independent take on "keep command names intact while hints yield" was exactly this: make the label element non-shrinkable and let the hint/badge absorb the overflow by wrapping — a single edit in the suggestion row loop. That is what this PR does, in one production line.

What I checked:

  • PrepareLabel caps a rendered label at MAX_WIDTH (150) unless expanded, so the non-shrinkable label has a sane width bound; the argument hint and source badge keep their default wrapping, so overflowing content yields to following lines rather than disappearing — the stated intent.
  • The change is unconditional, so it applies to @-mention rows as well as slash mode — consistent with the existing intent there ("The reference takes the priority over its description, which truncates").
  • The new test pins the reported scenario (width 120, long [Skill] hint) and asserts both names survive; it matches the colocated suite's existing style.

Two non-blocking notes: rows with long hints can now span multiple lines, so a narrow-terminal menu can grow taller (MAX_SUGGESTIONS_TO_SHOW counts suggestions, not lines) — the tradeoff the PR documents in Risk & Scope. And a name that alone exceeds the column cap (~50% of width in slash mode) now overflows instead of truncating — which is the point of the change, and rare for real command names.

CI test evidence (the PR's own CI, fetched via the API — the gate does not run PR code)

The unit suite on this commit is still running on Linux; macOS/Windows/integration jobs are skipped at this point, and nothing is red so far: precheck and the Desktop Shell job completed green.

Final CI results for 64bb8ed (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Classify PR ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

Sandboxed verification would settle this: @qwen-code /tmux — whether the menu truly renders full review/doctor names at narrow widths is a real-terminal rendering claim that test-renderer frames alone don't settle.

Not verified: real-terminal rendering on Linux/Windows — CI is still in flight, and the author's Tested-on table covers macOS only (the author's claim, not independently re-run).

中文说明

代码审查:我对"保持命令名完整、让提示让出空间"的独立方案正是如此——把标签元素设为不可收缩,让参数提示/来源标识通过换行吸收溢出,即建议行渲染循环里的一处改动。这个 PR 正是这么做的,生产代码仅一行。

核对结论:

  • PrepareLabel 会把标签渲染宽度限制在 MAX_WIDTH(150)以内(除非展开),因此不可收缩的标签有合理的宽度上限;参数提示和来源标识保持默认换行行为,溢出内容换到后续行而不是消失——与 PR 声明的意图一致。
  • 该改动是无条件的,同样作用于 @-mention 行——与该处既有意图("引用优先于描述,描述被截断")一致。
  • 新增测试固定了所报告的场景(宽度 120、带 [Skill] 的长提示),断言两个命令名完整保留;风格与同目录既有测试一致。

两条非阻塞提醒:长提示的行现在可能占多行,窄终端下建议列表会变更高(MAX_SUGGESTIONS_TO_SHOW 按建议条数计,不按行数计)——这是 PR 在 Risk & Scope 中已说明的取舍;命令名单独超过列宽上限(slash 模式约为宽度一半)时会溢出而非截断——这正是本改动的目的,且对真实命令名很少见。

CI 测试证据(PR 自身 CI,通过 API 获取——按门禁规则不运行 PR 代码):该 commit 的 Linux 单元测试仍在运行,macOS/Windows/集成测试目前为 skipped,暂无红色项:precheck 与 Desktop Shell 任务已通过。详见上方表格(finalize 流程会在 CI 结束后原地更新)。沙盒验证可以定论:@qwen-code /tmux ——窄终端下菜单是否真的完整渲染命令名是真实终端渲染断言,仅靠测试渲染器帧不足以定论。未验证:Linux/Windows 的真实终端渲染——CI 仍在进行,作者测试矩阵仅覆盖 macOS(作者声明,非独立复跑)。

Qwen Code · qwen3.8-max

Reviewed at 64bb8ed64402e08c509f63bd5bf2dedd7b7a7d79 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — solid minimal fix with a load-bearing test; the only residual is that real-terminal rendering beyond the author's macOS run isn't independently settled yet.

This is what a good fork PR looks like. The problem is observed and reproduced (width 120, with screenshots), and the mechanism checks out in code — the command name, argument hint, and source badge shared one shrinkable flex row inside the fixed-width label column, so the name itself truncated. The fix is the smallest possible one: make the label non-shrinkable so hints wrap instead — which is also the approach I'd have taken independently. One production line, a colocated test pinning exactly the reported scenario, and nothing else in the diff. The tradeoff (long hints may take extra lines in narrow menus) is documented in the PR itself, and the unconditional application to @-mention rows is consistent with that row's existing intent.

Why not 5: the rendering claim currently rests on the test renderer and the author's macOS run, and the Linux unit suite is still in flight — hence the deferred approval below, and the /tmux lane named in my review comment for a maintainer who wants real-terminal evidence before merge.

CI is still running, so approval is deferred until CI lands green on 64bb8ed64402e08c509f63bd5bf2dedd7b7a7d79.

中文说明

Confidence: 4/5 —— 扎实的最小修复,测试切实固定了行为;唯一的遗留是除作者的 macOS 运行外,真实终端渲染尚未独立验证。

这是一个标准的优质 fork PR。问题可观测、可复现(宽度 120,附截图),机制在代码中得到确认——命令名、参数提示和来源标识共享固定宽度标签列内的一个可收缩 flex 行,因此命令名本身被截断。修复是最小可能的改动:让标签不可收缩、使提示改为换行——这也正是我独立会采用的方案。生产代码一行,同目录测试恰好固定所报告的场景,diff 中没有其他内容。代价(长提示在窄终端可能多占行)PR 本身已说明;对 @-mention 行无条件生效也与该行既有的意图一致。

为什么不是 5 分:渲染结论目前基于测试渲染器和作者的 macOS 运行,Linux 单元测试仍在进行——因此下面的延迟批准;若维护者想在合并前获得真实终端证据,我的审查评论中已给出 /tmux 通道。

CI 仍在运行,批准将等待 CI 在该 commit 上全绿后执行。

Qwen Code · qwen3.8-max

Reviewed at 64bb8ed64402e08c509f63bd5bf2dedd7b7a7d79 · re-run with @qwen-code /triage

@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 — CI landed green after the review. ✅

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

⚠️ Downgraded from Approve to Comment: CI still running. Reviewed.

中文说明

⚠️ 已从批准降级为评论:CI still running。 已审查。

— kimi-k3 via Qwen Code /review (v0.21.7)

@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. Suggestions are inline. Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

中文说明

已审查。 建议见行内评论。 未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

— qwen3.8-max via Qwen Code /review (v0.21.7)

Comment on lines +204 to +205
expect(lines).toContainEqual(expect.stringMatching(/^> review(?: |$)/));
expect(lines).toContainEqual(expect.stringMatching(/^ {2}doctor(?: |$)/));

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 new test pins only the name-survival half of the fix: it never asserts that the argument hint wraps and stays visible, which is this PR's second stated behavior ("Argument hints continue to yield space by wrapping"). The sibling reverse-mode test asserts both sides of its tradeoff (reference intact AND description truncated); this one asserts only one side. — Failure scenario: a future change that renders the hint with wrap="truncate-end" (or skips it when the column overflows) keeps the command names intact, so this test stays green while the wrap-instead-of-vanish behavior silently regresses. Verified by probe: under a simulated truncate mutation this test file still passed 10/10 while the frame no longer contained the hint tail ([--fix]).

Suggested change
expect(lines).toContainEqual(expect.stringMatching(/^> review(?: |$)/));
expect(lines).toContainEqual(expect.stringMatching(/^ {2}doctor(?: |$)/));
expect(lines).toContainEqual(expect.stringMatching(/^> review(?: |$)/));
expect(lines).toContainEqual(expect.stringMatching(/^ {2}doctor(?: |$)/));
expect(lastFrame()).toContain('[--fix]');
中文说明

新测试只固定了修复中"命令名存活"这一半:它没有断言参数提示换行后仍然可见——而这是本 PR 明确承诺的第二个行为("参数提示仍可通过换行让出空间")。同文件中 reverse 模式的姊妹测试同时断言了权衡的两个方面(引用完整保留且描述被截断),而本测试只断言了一方面。— 故障场景:未来若有改动把提示渲染为 wrap="truncate-end"(或在列溢出时直接跳过提示),命令名依然完整,本测试仍然通过,但"换行而不是消失"的行为会悄无声息地回归。已用探针验证:在模拟的截断变异下,整个测试文件仍 10/10 通过,而渲染帧中已不再包含提示尾部([--fix])。建议补充对换行后提示内容的断言,例如 expect(lastFrame()).toContain('[--fix]');——已验证在当前 HEAD 通过、在上述截断变异下失败。

— qwen3.8-max via Qwen Code /review (v0.21.7)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I agree this would strengthen a broader contract around hint visibility. This PR is intentionally scoped to the reported defect: the actionable command name must not lose characters. Argument hints are secondary and may legitimately be wrapped, truncated, or hidden by a future narrow-width policy, so asserting the full [--fix] tail would broaden the behavior guaranteed here. CI is green and the focused change has already received an approval, so I would prefer to keep this PR small and handle hint-visibility guarantees in a follow-up.

>
<Box>
{labelElement}
<Box flexShrink={0}>{labelElement}</Box>

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] With the label now wrapped in <Box flexShrink={0}>, the sibling argumentHint/sourceBadge Text nodes (default flexShrink: 1) absorb all remaining flex shrink. In very narrow terminals they collapse to ~1 column and wrap one character per line, inflating suggestion rows. — Failure scenario: a terminal ≤ ~40 columns (tmux split panes, side-by-side IDE windows) with slash commands carrying long argumentHints — measured on the real component: at width 20 the two-suggestion frame grows from 37 lines pre-fix to 88 lines post-fix (hint as 1-2-char vertical strips plus ~29 trailing blank lines); at width 30, an openwork-desktop-sync + [direction] row grows from 3 to 13 lines. With MAX_SUGGESTIONS_TO_SHOW = 8 the completion menu can balloon vertically and push the conversation off-screen (Ink bottom-anchors overflowing frames). Navigation and mouse hit-testing still work, and pre-fix rendering at these widths was already garbled, so this exacerbates a pre-existing edge case rather than regressing a working path. Suggested fix: skip the hint/badge or apply wrap="truncate-end" when the remaining label-column width after the command name is below a small threshold (e.g. < 8 columns), so narrow terminals degrade to "name only" instead of a one-character vertical strip.

中文说明

标签被包进 <Box flexShrink={0}> 之后,同级的 argumentHint/sourceBadge 文本节点(默认 flexShrink: 1)会吸收全部剩余 flex 收缩。在极窄终端里它们塌缩到约 1 列宽、按每行一个字符换行,使建议行高度暴涨。— 故障场景:终端宽度 ≤ 约 40 列(tmux 分屏、IDE 并排窗口)且命令带有较长 argumentHint 时,在真实组件上实测:宽度 20 时,两条建议的渲染帧从修复前 37 行涨到修复后 88 行(提示变成 1-2 个字符的竖条,另有约 29 行尾部空行);宽度 30 时,openwork-desktop-sync + [direction] 的行从 3 行涨到 13 行。MAX_SUGGESTIONS_TO_SHOW = 8 时,补全菜单可能纵向膨胀、把对话内容挤出屏幕(Ink 对溢出帧做底部对齐)。键盘导航和鼠标命中测试仍然正常,且这些宽度下修复前的渲染本来就是错乱的,因此这是既有边界情况的加剧,而非对原本正常路径的回归。建议:当命令名之后标签列剩余宽度低于某个较小阈值(例如 < 8 列)时,跳过提示/徽标或改用 wrap="truncate-end",让窄终端退化为"只显示名称",而不是出现每行一个字符的竖条。

— qwen3.8-max via Qwen Code /review (v0.21.7)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed measurements. I agree that long-name and extremely narrow terminal combinations deserve a bounded fallback. A robust solution likely needs an explicit remaining-width policy that truncates or hides hints and badges, plus a width-matrix test suite, rather than another isolated flex adjustment. That is broader than the focused command-name truncation fixed here, and rendering at those widths was already degraded before this change. With CI green and the focused fix already approved, I would prefer to defer that broader narrow-width policy to a follow-up.

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

@carffuca
carffuca added this pull request to the merge queue Aug 7, 2026
Merged via the queue into QwenLM:main with commit 43e422c Aug 7, 2026
132 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.8.

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.

4 participants