diff --git a/SYSTEM.md b/SYSTEM.md new file mode 100644 index 0000000..045c41a --- /dev/null +++ b/SYSTEM.md @@ -0,0 +1 @@ +You are a personal assistant named Kimiko. diff --git a/extensions/kimiko-ui.ts b/extensions/kimiko-ui.ts new file mode 100644 index 0000000..09b8b7d --- /dev/null +++ b/extensions/kimiko-ui.ts @@ -0,0 +1,68 @@ +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() {}, + })); + }); +} diff --git a/settings.json b/settings.json index a337c83..c66020a 100644 --- a/settings.json +++ b/settings.json @@ -3,7 +3,8 @@ "enableInstallTelemetry": false, "packages": [], "lastChangelogVersion": "0.81.1", - "theme": "dark", + "theme": "kimiko-sakura", + "quietStartup": true, "defaultProvider": "omlx", "defaultModel": "Ternary-Bonsai-27B-mlx-2bit" } diff --git a/themes/kimiko-sakura.json b/themes/kimiko-sakura.json new file mode 100644 index 0000000..7e40b74 --- /dev/null +++ b/themes/kimiko-sakura.json @@ -0,0 +1,98 @@ +{ + "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json", + "name": "kimiko-sakura", + "vars": { + "ink": "#210d1e", + "deepPlum": "#2d172a", + "plum": "#381d33", + "raisedPlum": "#41233a", + "softPlum": "#5f3550", + "mutedPlum": "#7a4b66", + "berry": "#ae3664", + "rose": "#ce507d", + "hotPink": "#e6679a", + "sakura": "#f174a8", + "blossom": "#f785b5", + "blush": "#fa9dc6", + "petal": "#fbb4d5", + "palePetal": "#fdc4de", + "whitePetal": "#fedeec", + "mutedText": "#c99ab3", + "lavender": "#d9a7e8", + "mint": "#9ed9bc", + "aqua": "#9ed9d5", + "gold": "#f3c987", + "coral": "#ff7185", + "selectedBg": "#5f3550", + "userMsgBg": "#381d33", + "customMsgBg": "#41233a", + "toolPendingBg": "#302039", + "toolSuccessBg": "#22352f", + "toolErrorBg": "#43202c" + }, + "colors": { + "accent": "sakura", + "border": "rose", + "borderAccent": "petal", + "borderMuted": "softPlum", + "success": "mint", + "error": "coral", + "warning": "gold", + "muted": "mutedText", + "dim": "mutedPlum", + "text": "whitePetal", + "thinkingText": "mutedText", + + "selectedBg": "selectedBg", + "userMessageBg": "userMsgBg", + "userMessageText": "whitePetal", + "customMessageBg": "customMsgBg", + "customMessageText": "whitePetal", + "customMessageLabel": "blossom", + "toolPendingBg": "toolPendingBg", + "toolSuccessBg": "toolSuccessBg", + "toolErrorBg": "toolErrorBg", + "toolTitle": "palePetal", + "toolOutput": "mutedText", + + "mdHeading": "petal", + "mdLink": "sakura", + "mdLinkUrl": "mutedPlum", + "mdCode": "blossom", + "mdCodeBlock": "palePetal", + "mdCodeBlockBorder": "berry", + "mdQuote": "mutedText", + "mdQuoteBorder": "rose", + "mdHr": "softPlum", + "mdListBullet": "hotPink", + + "toolDiffAdded": "mint", + "toolDiffRemoved": "coral", + "toolDiffContext": "mutedText", + + "syntaxComment": "#a77891", + "syntaxKeyword": "sakura", + "syntaxFunction": "palePetal", + "syntaxVariable": "blossom", + "syntaxString": "mint", + "syntaxNumber": "lavender", + "syntaxType": "gold", + "syntaxOperator": "blush", + "syntaxPunctuation": "mutedText", + + "thinkingOff": "softPlum", + "thinkingMinimal": "mutedPlum", + "thinkingLow": "berry", + "thinkingMedium": "rose", + "thinkingHigh": "hotPink", + "thinkingXhigh": "blossom", + "thinkingMax": "whitePetal", + + "bashMode": "gold" + }, + "export": { + "pageBg": "ink", + "cardBg": "deepPlum", + "infoBg": "raisedPlum" + } +}