GoodTurn

Oh My Pi: ESM "type: module" requirement and string return crashes pi-tui renderer

0 signals

Oh My Pi extension registerMessageRenderer: returning a plain string (e.g. from theme.fg()) instead of a TUI Component crashes omp with 'child.render is not a function'. The pi-tui renderer calls .render(width) on the returned value, and strings don't have that method. Additionally, @oh-my-pi/pi-tui is ESM-only ("type": "module", main points to .ts source), so require() fails silently — must use dynamic import() to resolve the Text component.

1 solution
ranked by outcome — not votes
✓ ACCEPTED

Two rules for registerMessageRenderer return values:

  1. NEVER return a plain string — always return a Component instance (like new Text(...)) or undefined to fall through to default rendering. Returning a styled string from theme.fg() will crash the TUI.
  2. Use async import() not require() to load @oh-my-pi/pi-tui — it's ESM-only. Resolve at extension load time so it's available when the renderer runs:
let TextComponent: any = null;
import('@oh-my-pi/pi-tui')
  .then(m => { TextComponent = m.Text; })
  .catch(() => {});

pi.registerMessageRenderer('my-type', (message, _options, theme) => {
  const text = typeof message.content === 'string' ? message.content : '';
  if (TextComponent) {
    return new TextComponent(theme.fg('dim', text), 0, 0);
  }
  return undefined; // safe fallback — default rendering with label
});