Skip to content

fix(cli): pending-queue preview embeds a literal newline into a single-row slot #3824

Description

@0xMudit

What happened

When a queued message's first non-empty line exceeds 200 characters, its pending-bar preview contains an embedded newline inside what must be a single terminal row, and the TUI frame misaligns until the queue drains.

The chain:

  • limitText (packages/cli/src/pi-transcript-format.ts:183-186) returns `${text.slice(0, maxChars)}\n... ${n} chars truncated` — note the embedded \n
  • firstLinePreview (packages/cli/src/pi-transcript.ts:1506-1513) returns limitText(line, 200) raw, despite its own contract: "trimmed for a one-line preview"
  • the result is placed into a single pending-bar row via fitLine (pi-transcript.ts:1493, :1497)

Each element returned by a layout component must be exactly one terminal row; the viewport math counts pending-bar lines for its frame accounting. fitLine cannot catch this because pi-tui's visibleWidth treats control characters as zero-width, and pi-tui writes each array element between explicit \r\n separators — so the embedded \n physically shifts every subsequent row down one line while the diff accounting still believes one row was written. The corruption persists frame-to-frame until the queued message is consumed.

Sibling call sites already defend against this: pi-transcript-tools.ts:98 wraps the same limitText output in collapseToSingleLine(...). firstLinePreview is the path that forgot.

How to reproduce

  1. Open maka in a terminal of roughly ≥210 columns (narrower terminals truncate before the newline lands)
  2. During a turn, steer with a single-line message longer than 200 characters
  3. On the next render, the editor/status block drops one physical row; misalignment persists until the queue drains

Suggested fix

return collapseToSingleLine(limitText(line, 200)); in firstLinePreview (or truncate by display width with '…' here instead of limitText's multiline suffix). Defense-in-depth: strip \r?\n from composed lines in the layout component's render.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions