mirror of
https://github.com/anomalyco/opencode.git
synced 2026-07-23 18:55:37 -04:00
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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<string, string[]> = {
|
||||
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(
|
||||
<text fg={fg} attributes={attrs} selectable={false}>
|
||||
{rest}
|
||||
</text>,
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
if (markerIndex > 0) {
|
||||
elements.push(
|
||||
<text fg={fg} attributes={attrs} selectable={false}>
|
||||
{rest.slice(0, markerIndex)}
|
||||
</text>,
|
||||
)
|
||||
}
|
||||
|
||||
const marker = rest[markerIndex]
|
||||
switch (marker) {
|
||||
case "_":
|
||||
elements.push(
|
||||
<text fg={fg} bg={shadow} attributes={attrs} selectable={false}>
|
||||
{" "}
|
||||
</text>,
|
||||
)
|
||||
break
|
||||
case "^":
|
||||
elements.push(
|
||||
<text fg={fg} bg={shadow} attributes={attrs} selectable={false}>
|
||||
▀
|
||||
</text>,
|
||||
)
|
||||
break
|
||||
case "~":
|
||||
elements.push(
|
||||
<text fg={shadow} attributes={attrs} selectable={false}>
|
||||
▀
|
||||
</text>,
|
||||
)
|
||||
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 (
|
||||
<box>
|
||||
<For each={LOGO_LEFT}>
|
||||
{(line, index) => (
|
||||
<box flexDirection="row" gap={1}>
|
||||
<box flexDirection="row">{renderLine(line, theme.textMuted, false)}</box>
|
||||
<box flexDirection="row">{renderLine(LOGO_RIGHT[index()], theme.text, true)}</box>
|
||||
</box>
|
||||
<box flexDirection="column" alignItems="center">
|
||||
<For each={art()}>
|
||||
{(line) => (
|
||||
<text fg={color()} attributes={TextAttributes.BOLD} selectable={false}>
|
||||
{line}
|
||||
</text>
|
||||
)}
|
||||
</For>
|
||||
</box>
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user