summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorKit Langton <[email protected]>2026-04-01 23:21:07 -0400
committerGitHub <[email protected]>2026-04-02 03:21:07 +0000
commit336d28f112212efb970543b9995a853753e7d988 (patch)
tree77b530204da2fe918f3dfe84b0ef1c8fdfb7f150
parent916afb5220d064990d846f4080a683762069fa25 (diff)
downloadopencode-336d28f112212efb970543b9995a853753e7d988.tar.gz
opencode-336d28f112212efb970543b9995a853753e7d988.zip
fix(cli): restore colored help logo (#20592)
-rw-r--r--packages/opencode/src/cli/ui.ts57
-rw-r--r--packages/opencode/src/index.ts28
2 files changed, 77 insertions, 8 deletions
diff --git a/packages/opencode/src/cli/ui.ts b/packages/opencode/src/cli/ui.ts
index c592d4206..b24a2a2f4 100644
--- a/packages/opencode/src/cli/ui.ts
+++ b/packages/opencode/src/cli/ui.ts
@@ -1,6 +1,7 @@
import z from "zod"
import { EOL } from "os"
import { NamedError } from "@opencode-ai/util/error"
+import { logo as glyphs } from "./logo"
export namespace UI {
const wordmark = [
@@ -47,12 +48,60 @@ export namespace UI {
}
export function logo(pad?: string) {
- const result = []
- for (const row of wordmark) {
+ if (!process.stdout.isTTY && !process.stderr.isTTY) {
+ const result = []
+ for (const row of wordmark) {
+ if (pad) result.push(pad)
+ 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(row)
+ 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()
}
diff --git a/packages/opencode/src/index.ts b/packages/opencode/src/index.ts
index 2da35ace1..bb14e0588 100644
--- a/packages/opencode/src/index.ts
+++ b/packages/opencode/src/index.ts
@@ -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 })
.scriptName("opencode")
.wrap(100)
@@ -130,7 +142,7 @@ const cli = yargs(hideBin(process.argv))
process.stderr.write("Database migration complete." + EOL)
}
})
- .usage("\n" + UI.logo())
+ .usage("")
.completion("completion", "generate shell completion script")
.command(AcpCommand)
.command(McpCommand)
@@ -162,7 +174,7 @@ const cli = yargs(hideBin(process.argv))
msg?.startsWith("Invalid values:")
) {
if (err) throw err
- cli.showHelp("log")
+ cli.showHelp(show)
}
if (err) throw err
process.exit(1)
@@ -170,7 +182,15 @@ const cli = yargs(hideBin(process.argv))
.strict()
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) {
let data: Record<string, any> = {}
if (e instanceof NamedError) {