From 4126df9d2b6d063eeb9fe277ee98ea94526bfb07 Mon Sep 17 00:00:00 2001 From: Artur Do Lago Date: Fri, 9 Jan 2026 21:39:44 +0100 Subject: [PATCH] fix(tui): show persona banners and remove OpenRouter warning - Replace AGENT-CORE logo with dynamic persona ASCII art - Logo now shows Zee, Stanley, or Johny based on active persona - Remove OpenRouter warning dialog (was promoting OpenCode Zen) - Update CLI logo to show Zee banner (default persona) Co-Authored-By: Claude Opus 4.5 --- packages/agent-core/src/cli/cmd/tui/app.tsx | 14 --- .../src/cli/cmd/tui/component/logo.tsx | 118 ++++++------------ packages/agent-core/src/cli/ui.ts | 19 +-- 3 files changed, 51 insertions(+), 100 deletions(-) diff --git a/packages/agent-core/src/cli/cmd/tui/app.tsx b/packages/agent-core/src/cli/cmd/tui/app.tsx index d68b312ec68..e7a3faf3f2d 100644 --- a/packages/agent-core/src/cli/cmd/tui/app.tsx +++ b/packages/agent-core/src/cli/cmd/tui/app.tsx @@ -576,20 +576,6 @@ function App() { }, ]) - createEffect(() => { - const currentModel = local.model.current() - if (!currentModel) return - if (currentModel.providerID === "openrouter" && !kv.get("openrouter_warning", false)) { - untrack(() => { - DialogAlert.show( - dialog, - "Warning", - "While openrouter is a convenient way to access LLMs your request will often be routed to subpar providers that do not work well in our testing.\n\nFor reliable access to models check out OpenCode Zen\nhttps://opencode.ai/zen", - ).then(() => kv.set("openrouter_warning", true)) - }) - } - }) - sdk.event.on(TuiEvent.CommandExecute.type, (evt) => { command.trigger(evt.properties.command) }) diff --git a/packages/agent-core/src/cli/cmd/tui/component/logo.tsx b/packages/agent-core/src/cli/cmd/tui/component/logo.tsx index a6bb81eaf96..308e48dce91 100644 --- a/packages/agent-core/src/cli/cmd/tui/component/logo.tsx +++ b/packages/agent-core/src/cli/cmd/tui/component/logo.tsx @@ -1,87 +1,49 @@ -import { TextAttributes, RGBA } from "@opentui/core" -import { For, type JSX } from "solid-js" -import { useTheme, tint } from "@tui/context/theme" +import { TextAttributes } from "@opentui/core" +import { For, createMemo } from "solid-js" +import { useLocal } from "@tui/context/local" -// Shadow markers (rendered chars in parens): -// _ = full shadow cell (space with bg=shadow) -// ^ = letter top, shadow bottom (▀ with fg=letter, bg=shadow) -// ~ = shadow top only (▀ with fg=shadow) -const SHADOW_MARKER = /[_^~]/ - -// agent-core logo (AGENT left dimmed, CORE right bold) -const LOGO_LEFT = [` `, `█▀▀█ █▀▀▀ █▀▀▀ █▀▀▄ ▀▀█▀▀`, `█▀▀█ █░░█ █▀▀▀ █░░█ █ `, `▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀ `] - -const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀▀`, `█░░░ █░░█ █▀▀▀ █▀▀▀`, `▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀`] +// Persona ASCII art banners +const PERSONA_ART: Record = { + zee: [ + "███████╗███████╗███████╗", + "╚══███╔╝██╔════╝██╔════╝", + " ███╔╝ █████╗ █████╗ ", + " ███╔╝ ██╔══╝ ██╔══╝ ", + "███████╗███████╗███████╗", + "╚══════╝╚══════╝╚══════╝", + ], + stanley: [ + "███████╗████████╗ █████╗ ███╗ ██╗██╗ ███████╗██╗ ██╗", + "██╔════╝╚══██╔══╝██╔══██╗████╗ ██║██║ ██╔════╝╚██╗ ██╔╝", + "███████╗ ██║ ███████║██╔██╗ ██║██║ █████╗ ╚████╔╝ ", + "╚════██║ ██║ ██╔══██║██║╚██╗██║██║ ██╔══╝ ╚██╔╝ ", + "███████║ ██║ ██║ ██║██║ ╚████║███████╗███████╗ ██║ ", + "╚══════╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ", + ], + johny: [ + " ██╗ ██████╗ ██╗ ██╗███╗ ██╗██╗ ██╗", + " ██║██╔═══██╗██║ ██║████╗ ██║╚██╗ ██╔╝", + " ██║██║ ██║███████║██╔██╗ ██║ ╚████╔╝ ", + "██ ██║██║ ██║██╔══██║██║╚██╗██║ ╚██╔╝ ", + "╚█████╔╝╚██████╔╝██║ ██║██║ ╚████║ ██║ ", + " ╚════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═╝ ", + ], +} export function Logo() { - const { theme } = useTheme() + const local = useLocal() - const renderLine = (line: string, fg: RGBA, bold: boolean): JSX.Element[] => { - const shadow = tint(theme.background, fg, 0.25) - const attrs = bold ? TextAttributes.BOLD : undefined - const elements: JSX.Element[] = [] - let i = 0 - - while (i < line.length) { - const rest = line.slice(i) - const markerIndex = rest.search(SHADOW_MARKER) - - if (markerIndex === -1) { - elements.push( - - {rest} - , - ) - break - } - - if (markerIndex > 0) { - elements.push( - - {rest.slice(0, markerIndex)} - , - ) - } - - const marker = rest[markerIndex] - switch (marker) { - case "_": - elements.push( - - {" "} - , - ) - break - case "^": - elements.push( - - ▀ - , - ) - break - case "~": - elements.push( - - ▀ - , - ) - break - } - - i += markerIndex + 1 - } - - return elements - } + const agent = createMemo(() => local.agent.current()) + const color = createMemo(() => local.agent.color(agent().name)) + const art = createMemo(() => PERSONA_ART[agent().name.toLowerCase()] || PERSONA_ART.zee) return ( - - - {(line, index) => ( - - {renderLine(line, theme.textMuted, false)} - {renderLine(LOGO_RIGHT[index()], theme.text, true)} - + + + {(line) => ( + + {line} + )} diff --git a/packages/agent-core/src/cli/ui.ts b/packages/agent-core/src/cli/ui.ts index 731a7071263..fd5ebbc2754 100644 --- a/packages/agent-core/src/cli/ui.ts +++ b/packages/agent-core/src/cli/ui.ts @@ -3,12 +3,14 @@ import { EOL } from "os" import { NamedError } from "@opencode-ai/util/error" export namespace UI { - // agent-core logo (AGENT left dimmed, CORE right bold) + // Default persona logo (Zee - the default gateway) const LOGO = [ - [` `, ` ▄ `], - [`█▀▀█ █▀▀▀ █▀▀▀ █▀▀▄ ▀▀█▀▀`, `█▀▀▀ █▀▀█ █▀▀█ █▀▀▀`], - [`█▀▀█ █░░█ █▀▀▀ █░░█ █ `, `█░░░ █░░█ █▀▀▀ █▀▀▀`], - [`▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀ `, `▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀`], + "███████╗███████╗███████╗", + "╚══███╔╝██╔════╝██╔════╝", + " ███╔╝ █████╗ █████╗ ", + " ███╔╝ ██╔══╝ ██╔══╝ ", + "███████╗███████╗███████╗", + "╚══════╝╚══════╝╚══════╝", ] export const CancelledError = NamedError.create("UICancelledError", z.void()) @@ -49,12 +51,13 @@ export namespace UI { export function logo(pad?: string) { const result = [] + // Zee blue color: #2563EB + const color = "\x1b[38;2;37;99;235m" for (const row of LOGO) { if (pad) result.push(pad) - result.push(Bun.color("gray", "ansi")) - result.push(row[0]) + result.push(color) + result.push(row) result.push("\x1b[0m") - result.push(row[1]) result.push(EOL) } return result.join("").trimEnd()