69 lines
2.6 KiB
TypeScript
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() {},
|
|
}));
|
|
});
|
|
}
|