Files
oh-my-pi/packages/coding-agent/src/modes/components/dynamic-border.ts
T
roboomp 83ed5eef1f fix(tui): guarded DynamicBorder against uninitialized module-level theme
Extensions importing legacy pi UI components (e.g. DynamicBorder from
@earendil-works/pi-coding-agent) receive a second src module graph in
npm-package installs. Host startup assigns the module-level `theme` only
inside the bundled dist copy, so the src-graph copy stays undefined and
DynamicBorder.render dereferenced `theme.boxRound` unconditionally,
throwing "undefined is not an object" and taking down the whole TUI.

Route the default color through the existing `fgOrPlain` guard and fall
back to the default rounded glyph when `theme` is undefined, matching the
`typeof theme === "undefined"` degradation already used by fgOrPlain and
getSettingsListTheme.

Fixes #5366
2026-07-14 19:14:16 +00:00

38 lines
1.2 KiB
TypeScript

import type { Component } from "@oh-my-pi/pi-tui";
import { fgOrPlain, theme } from "../../modes/theme/theme";
/**
* Dynamic border component that adjusts to viewport width.
*
* Note: the module-level `theme` may be `undefined` — when loaded through jiti
* (separate module cache) or from a second `src` module graph in npm-package
* installs, where the host bundle assigns `theme` but this copy never sees it
* (issue #5366). Both the default color and `render()` degrade to plain,
* unstyled output instead of crashing the TUI.
*/
export class DynamicBorder implements Component {
#color: (str: string) => string;
#cachedWidth = -1;
#cachedLines: string[] | undefined;
constructor(color: (str: string) => string = str => fgOrPlain("border", str)) {
this.#color = color;
}
invalidate(): void {
this.#cachedWidth = -1;
this.#cachedLines = undefined;
}
render(width: number): readonly string[] {
if (this.#cachedLines && this.#cachedWidth === width) {
return this.#cachedLines;
}
const horizontal = typeof theme === "undefined" ? "─" : theme.boxRound.horizontal;
const lines = [this.#color(horizontal.repeat(Math.max(1, width)))];
this.#cachedWidth = width;
this.#cachedLines = lines;
return lines;
}
}