pi-mono/packages
robopipi[bot] 8a2ebd3854
fix(tui): stop nested blockquote rendering from growing exponentially (#11321)
**Problem.** A line of many `>` characters makes `marked` produce one
nested blockquote token per `>`. The blockquote branch of
`Markdown.renderToken` renders its children at `Math.max(1, width - 2)`
columns, then wraps each child line again at that width and adds a `│ `
prefix.

Once the nesting uses up the width (about 39 levels at 80 columns), the
width stays clamped at 1. From then on, each child line (`│ x`, 3
columns wide) is wrapped into about 3 lines at every further level, so
the output roughly triples per level. At 80 columns:

- 50 levels: 4096 lines, about 30 s to render;
- 55 levels: `push(...lines)` exceeds the JavaScript argument limit and
throws `RangeError: Maximum call stack size exceeded`, which crashes pi.
Reopening the session crashes it again.

**Fix.**
- When there is no room left for another border (`width < 3`), the
blockquote branch now renders its child tokens at the same width without
adding a border and without wrapping them again.
- Child lines are appended with a loop instead of a spread `push`.

Quotes that fit in the width render exactly as before.

**Testing.**
- Added a regression test in `packages/tui/test/markdown.test.ts`: 60
nested `>` rendered at width 80 give one line that keeps the content.
Without the fix the test fails with the RangeError; with it, all 92
tests in that file pass (`node --test test/markdown.test.ts`).
- `npm run check` passes.
- Reproduction script rendering `">".repeat(n) + "x"` at width 80:
- before: 50 levels gave 4096 lines in 29.5 s, and 55 or 60 levels threw
a RangeError;
  - after: 40, 50, 60 and 200 levels each give 1 line in about 10 ms.

**Not covered.** A run of about 2000 `>` still overflows the stack
inside `marked`'s own lexer, before pi's renderer runs. That is a
separate limit and is not changed here.

Fixes #11272

Requested by @davidbrai

Co-authored-by: triagent <triagent@localhost>
2026-10-23 12:46:03 +02:00
..
agent fix: update deps for security advisories 2026-10-22 11:24:50 +02:00
ai fix(ai): send fixed low top-level effort with Anthropic per-message effort 2026-10-23 12:11:54 +02:00
chord feat(chord): Watchable, the common interface of values that can be watched 2026-10-23 09:31:09 +00:00
codemode fix: update deps for security advisories 2026-10-22 11:24:50 +02:00
coding-agent fix(coding-agent): start when a configured package fails to install (#11304) 2026-10-23 12:27:45 +02:00
durable feat(chord): shared watch-handle implementation (Watch, NativeWatch); Durable uses it 2026-10-23 07:05:23 +00:00
env fix: update deps for security advisories 2026-10-22 11:24:50 +02:00
evals fix(evals): drop autoevals dependency 2026-10-22 23:32:38 +02:00
mcp fix(mcp): accept only http and https OAuth URLs 2026-10-23 12:19:56 +02:00
telemetry fix: update deps for security advisories 2026-10-22 11:24:50 +02:00
tui fix(tui): stop nested blockquote rendering from growing exponentially (#11321) 2026-10-23 12:46:03 +02:00