fix(cli): restore colored help logo (#20592)

pull/20170/head^2
Kit Langton 2026-04-01 23:21:07 -04:00 committed by GitHub
parent 916afb5220
commit 336d28f112
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 78 additions and 9 deletions

View File

@ -1,6 +1,7 @@
import z from "zod" import z from "zod"
import { EOL } from "os" import { EOL } from "os"
import { NamedError } from "@opencode-ai/util/error" import { NamedError } from "@opencode-ai/util/error"
import { logo as glyphs } from "./logo"
export namespace UI { export namespace UI {
const wordmark = [ const wordmark = [
@ -47,12 +48,60 @@ export namespace UI {
} }
export function logo(pad?: string) { export function logo(pad?: string) {
const result = [] if (!process.stdout.isTTY && !process.stderr.isTTY) {
for (const row of wordmark) { const result = []
if (pad) result.push(pad) for (const row of wordmark) {
result.push(row) if (pad) result.push(pad)
result.push(EOL) result.push(row)
result.push(EOL)
}
return result.join("").trimEnd()
} }
const result: string[] = []
const reset = "\x1b[0m"
const left = {
fg: "\x1b[90m",
shadow: "\x1b[38;5;235m",
bg: "\x1b[48;5;235m",
}
const right = {
fg: reset,
shadow: "\x1b[38;5;238m",
bg: "\x1b[48;5;238m",
}
const gap = " "
const draw = (line: string, fg: string, shadow: string, bg: string) => {
const parts: string[] = []
for (const char of line) {
if (char === "_") {
parts.push(bg, " ", reset)
continue
}
if (char === "^") {
parts.push(fg, bg, "▀", reset)
continue
}
if (char === "~") {
parts.push(shadow, "▀", reset)
continue
}
if (char === " ") {
parts.push(" ")
continue
}
parts.push(fg, char, reset)
}
return parts.join("")
}
glyphs.left.forEach((row, index) => {
if (pad) result.push(pad)
result.push(draw(row, left.fg, left.shadow, left.bg))
result.push(gap)
const other = glyphs.right[index] ?? ""
result.push(draw(other, right.fg, right.shadow, right.bg))
result.push(EOL)
})
return result.join("").trimEnd() return result.join("").trimEnd()
} }

View File

@ -48,7 +48,19 @@ process.on("uncaughtException", (e) => {
}) })
}) })
const cli = yargs(hideBin(process.argv)) const args = hideBin(process.argv)
function show(out: string) {
const text = out.trimStart()
if (!text.startsWith("opencode ")) {
process.stderr.write(UI.logo() + EOL + EOL)
process.stderr.write(text)
return
}
process.stderr.write(out)
}
const cli = yargs(args)
.parserConfiguration({ "populate--": true }) .parserConfiguration({ "populate--": true })
.scriptName("opencode") .scriptName("opencode")
.wrap(100) .wrap(100)
@ -130,7 +142,7 @@ const cli = yargs(hideBin(process.argv))
process.stderr.write("Database migration complete." + EOL) process.stderr.write("Database migration complete." + EOL)
} }
}) })
.usage("\n" + UI.logo()) .usage("")
.completion("completion", "generate shell completion script") .completion("completion", "generate shell completion script")
.command(AcpCommand) .command(AcpCommand)
.command(McpCommand) .command(McpCommand)
@ -162,7 +174,7 @@ const cli = yargs(hideBin(process.argv))
msg?.startsWith("Invalid values:") msg?.startsWith("Invalid values:")
) { ) {
if (err) throw err if (err) throw err
cli.showHelp("log") cli.showHelp(show)
} }
if (err) throw err if (err) throw err
process.exit(1) process.exit(1)
@ -170,7 +182,15 @@ const cli = yargs(hideBin(process.argv))
.strict() .strict()
try { try {
await cli.parse() if (args.includes("-h") || args.includes("--help")) {
await cli.parse(args, (err: Error | undefined, _argv: unknown, out: string) => {
if (err) throw err
if (!out) return
show(out)
})
} else {
await cli.parse()
}
} catch (e) { } catch (e) {
let data: Record<string, any> = {} let data: Record<string, any> = {}
if (e instanceof NamedError) { if (e instanceof NamedError) {