Files
kimiko-agent/extensions/kimiko-ui.ts

69 lines
2.6 KiB
TypeScript

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() {},
}));
});
}