Skip to content

pi TUI Stack Overflow on ANSI Control Sequences #5185

@bcurioous

Description

@bcurioous

What happened?

pi crashes with RangeError: Maximum call stack size exceeded when investigating bash command failures that output unrecognized ANSI escape sequences.

The stack trace shows infinite recursion in the text rendering pipeline:

RangeError: Maximum call stack size exceeded
    at wrapTextWithAnsi (pi-tui/dist/utils.js:607:16)
    at Text.render (pi-tui/dist/components/text.js:55:30)
    at truncateToVisualLines (visual-truncate.js:24:37)
    at Object.render (bash.js:141:41)
    at BashResultRenderComponent.render (pi-tui/dist/tui.js:85:38)
    ...

Root Cause: The extractAnsiCode() function in pi-tui/dist/utils.js has an incomplete CSI (Control Sequence Introducer) sequence parser. Line 249 only recognizes 5 CSI terminators:

// BEFORE (broken)
while (j < str.length && !/[mGKHJ]/.test(str[j]))

This misses 20+ valid CSI terminators including: A, B, C, D (cursor movement), f (position), r (scroll), s, u (cursor save/restore), h, l (modes), n (status), p (keyboard strings), etc.

When bash output contains unrecognized CSI sequences:

  1. extractAnsiCode() returns null
  2. Lone \x1b characters remain in parsed text
  3. Tokenization/wrapping logic enters infinite recursion
  4. Stack overflow crashes pi

Trigger: PyMuPDF PDF generation failures often output terminal control sequences that trigger this bug.

Steps to reproduce

  1. Open pi coding agent
  2. Run any bash command that produces ANSI escape codes with unrecognized CSI sequences
  3. Attempt to investigate/expand the failed command output
  4. Result: pi crashes with stack overflow

Example trigger:

# PyMuPDF failures often contain these sequences
echo -e '\x1b[1A\x1b[6n\x1b[H some text'

Expected behavior

pi should handle all valid ANSI escape sequences gracefully without crashing. The TUI should either:

  • Render unrecognized sequences correctly, or
  • Strip them silently without causing recursion

Fix Applied

Patched /opt/homebrew/lib/node_modules/@earendil-works/pi-tui/dist/utils.js line 249:

// AFTER (fixed)
while (j < str.length && !/[mGKHJfhnsuAHBCJDLSMRcXplW]/.test(str[j]))

Version

0.77.0

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinginprogressIssue is being worked on

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions