import type { ExtensionAPI, Theme, ThemeColor } from "@earendil-works/pi-coding-agent"; import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui"; const KIMIKO_ART = [ "██╗ ██╗██╗███╗ ███╗██╗██╗ ██╗ ██████╗", "██║ ██╔╝██║████╗ ████║██║██║ ██╔╝██╔═══██╗", "█████╔╝ ██║██╔████╔██║██║█████╔╝ ██║ ██║", "██╔═██╗ ██║██║╚██╔╝██║██║██╔═██╗ ██║ ██║", "██║ ██╗██║██║ ╚═╝ ██║██║██║ ██╗╚██████╔╝", "╚═╝ ╚═╝╚═╝╚═╝ ╚═╝╚═╝╚═╝ ╚═╝ ╚═════╝", ] as const; const ART_COLORS: readonly ThemeColor[] = [ "borderAccent", "mdHeading", "accent", "accent", "customMessageLabel", "border", ]; const MIN_ART_WIDTH = Math.max(...KIMIKO_ART.map((line) => visibleWidth(line))); function center(line: string, width: number): string { if (width <= 0) return ""; const clipped = truncateToWidth(line, width, ""); const padding = Math.max(0, Math.floor((width - visibleWidth(clipped)) / 2)); return `${" ".repeat(padding)}${clipped}`; } function renderHeader(theme: Theme, width: number): string[] { const blossom = theme.fg("accent", "✿"); if (width < MIN_ART_WIDTH) { return [ "", center(`${blossom} ${theme.fg("accent", theme.bold("K I M I K O"))} ${blossom}`, width), center(theme.fg("muted", "personal assistant"), width), "", ]; } const ornament = theme.fg("dim", "· ── ") + blossom + theme.fg("dim", " ── ·"); const art = KIMIKO_ART.map((line, index) => center(theme.fg(ART_COLORS[index]!, theme.bold(line)), width), ); const subtitle = theme.fg("muted", "personal assistant") + theme.fg("dim", " • blooming locally"); return ["", center(ornament, width), ...art, center(subtitle, width), ""]; } export default function kimikoUi(pi: ExtensionAPI) { pi.on("session_start", (_event, ctx) => { if (ctx.mode !== "tui") return; // Replace Pi's built-in logo and keybinding hints. The separate loaded-resources // section is suppressed by quietStartup in this instance's settings.json. ctx.ui.setHeader((_tui, theme) => ({ render(width: number): string[] { return renderHeader(theme, width); }, invalidate() {}, })); }); }