Skip to content

fix(pi-tui): prevent crashes on very narrow terminals - #1303

Merged
liruifengv merged 19 commits into
mainfrom
fix/pi-tui-narrow-width
Jul 2, 2026
Merged

fix(pi-tui): prevent crashes on very narrow terminals#1303
liruifengv merged 19 commits into
mainfrom
fix/pi-tui-narrow-width

Conversation

@liruifengv

Copy link
Copy Markdown
Collaborator

Related Issue

No open issue for this crash. Related prior fix: #240 covered a narrow-terminal crash in the session picker; this PR fixes the remaining narrow-terminal crashes in the editor and the renderer core. The problem is explained below.

Problem

When the terminal is resized to a very narrow width (roughly ≤ 7 columns) while the input editor contains CJK or emoji text, the TUI crashes and the process exits. This is close to always reproducible for CJK users.

Root causes in the vendored packages/pi-tui:

  • The editor word-wrap re-wraps a single grapheme that is wider than the available width by recursing with unchanged arguments. At a 1-column layout width (which the editor reaches at ≤ 7 terminal columns due to horizontal padding), any wide grapheme causes infinite recursion and a stack overflow.
  • The renderer's differential path throws on any rendered line wider than the terminal (upstream fail-fast policy), so even a one-column overflow at narrow widths kills the process.
  • Width propagates from terminal.columns down the component tree with no lower bound, and several components call repeat() with widths that can go negative.

Narrow-width fixes existed once on an unmerged branch as a pnpm patch and were lost when pi-tui was re-vendored, so this PR also adds guard rails against losing them again.

What changed

Following the "never crash, degrade gracefully" approach (clamp + truncate instead of throw):

  • Word-wrap guard (root cause): an indivisible grapheme wider than the wrap width is kept as an overflow chunk instead of recursing. The guard is based on grapheme count, not code-unit length, so ZWJ emoji are handled correctly; multi-grapheme atomic segments (paste markers) still re-wrap.
  • Width clamp at the container boundary: Container.render clamps the incoming width to ≥ 1, so no component ever sees a non-positive width from the render tree.
  • Truncate instead of throw: before writing to the terminal, any rendered line wider than the terminal is truncated (ANSI-aware, style resets still appended afterwards), and the upstream crash-log-and-throw block is removed. To keep the per-frame scan cheap on long transcripts, an ANSI-aware ASCII fast path measures common lines without the segmenter, and the width cache is enlarged; a synthetic worst case (thousands of distinct non-ASCII lines) is documented as a known boundary for a future prepared-frame cache.
  • Negative-width repeat() guards for blank-line padding, markdown horizontal rules, and the editor's top/bottom borders.
  • Regression tests (19 new): word-wrap at width 1 (CJK, mixed, ZWJ emoji, paste markers), editor rendering at widths 1–8 with and without padding, history recall after a 1-column render, a 5-column end-to-end TUI test with exact viewport assertions, negative-width safety for the touched components, and unit tests for the fast path. Discriminating power was verified by reverting each fix and confirming the matching tests fail.
  • packages/pi-tui/AGENTS.md: documents each local divergence from upstream with its guarding tests, so future re-vendoring keeps these fixes.

Verification: pi-tui suite 709/709 passing plus a clean typecheck; full repo vitest run 9112 passed, 0 failed.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

@changeset-bot

changeset-bot Bot commented Jul 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9fb9da7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@moonshot-ai/kimi-code Patch
@moonshot-ai/pi-tui Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jul 2, 2026

Copy link
Copy Markdown
pnpm dlx https://pkg.pr.new/@moonshot-ai/kimi-code@b119c55
npx https://pkg.pr.new/@moonshot-ai/kimi-code@b119c55

commit: b119c55

@liruifengv
liruifengv merged commit 2639786 into main Jul 2, 2026
9 checks passed
@liruifengv
liruifengv deleted the fix/pi-tui-narrow-width branch July 2, 2026 09:14
@github-actions github-actions Bot mentioned this pull request Jul 2, 2026
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.

Kimi 在宽度极小的终端选择/Sessions 里会崩溃!!!!!

1 participant