Download src/cli/banner.ts from SaylorTwift/openclaw: direct link, hf CLI and curl.
- Browser
- Download file 4.78 kB
-
https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/cli/banner.ts
- Command line
-
hf download hf://SaylorTwift/openclaw/src/cli/banner.ts
-
curl -L -o banner.ts https://huggingface.co/SaylorTwift/openclaw/resolve/main/src/cli/banner.ts
4.78 kB
| // CLI banner formatter and one-shot emitter. | |
| import { visibleWidth } from "../../packages/terminal-core/src/ansi.js"; | |
| import { | |
| decorativeEmoji, | |
| decorativePrefix, | |
| stripDecorativeEmojiForTerminal, | |
| type DecorativeEmojiOptions, | |
| } from "../../packages/terminal-core/src/decorative-emoji.js"; | |
| import { isRich, theme } from "../../packages/terminal-core/src/theme.js"; | |
| import { resolveCommitHash } from "../infra/git-commit.js"; | |
| import { hasRootVersionAlias } from "./argv.js"; | |
| import { parseTaglineMode } from "./banner-config-lite.js"; | |
| import { pickCliLobsterArt } from "./lobster-art.js"; | |
| import { pickTagline, type TaglineMode, type TaglineOptions } from "./tagline.js"; | |
| type BannerOptions = TaglineOptions & { | |
| argv?: string[]; | |
| commit?: string | null; | |
| columns?: number; | |
| isTty?: boolean; | |
| platform?: NodeJS.Platform; | |
| richTty?: boolean; | |
| }; | |
| let bannerEmitted = false; | |
| const hasJsonFlag = (argv: string[]) => | |
| argv.some((arg) => arg === "--json" || arg.startsWith("--json=")); | |
| const hasVersionFlag = (argv: string[]) => | |
| argv.some((arg) => arg === "--version" || arg === "-V") || hasRootVersionAlias(argv); | |
| function resolveTaglineMode(options: BannerOptions): TaglineMode | undefined { | |
| const explicit = parseTaglineMode(options.mode); | |
| if (explicit) { | |
| return explicit; | |
| } | |
| return undefined; | |
| } | |
| function resolveEmojiOptions(options: BannerOptions): DecorativeEmojiOptions { | |
| return { | |
| ...(options.env ? { env: options.env } : {}), | |
| ...(options.isTty === undefined ? {} : { isTty: options.isTty }), | |
| ...(options.platform ? { platform: options.platform } : {}), | |
| }; | |
| } | |
| /** Format the compact one-line CLI banner, wrapping tagline when terminal width requires it. */ | |
| export function formatCliBannerLine(version: string, options: BannerOptions = {}): string { | |
| const commit = | |
| options.commit ?? resolveCommitHash({ env: options.env, moduleUrl: import.meta.url }); | |
| const commitLabel = commit ?? "unknown"; | |
| const emojiOptions = resolveEmojiOptions(options); | |
| const tagline = stripDecorativeEmojiForTerminal( | |
| pickTagline({ ...options, mode: resolveTaglineMode(options) }), | |
| emojiOptions, | |
| ); | |
| const rich = options.richTty ?? isRich(); | |
| const title = decorativePrefix("🦞", "OpenClaw", emojiOptions); | |
| const prefix = decorativeEmoji("🦞", emojiOptions); | |
| const indent = prefix ? `${prefix} ` : ""; | |
| const columns = options.columns ?? process.stdout.columns ?? 120; | |
| const plainBaseLine = `${title} ${version} (${commitLabel})`; | |
| const plainFullLine = tagline ? `${plainBaseLine} — ${tagline}` : plainBaseLine; | |
| const fitsOnOneLine = visibleWidth(plainFullLine) <= columns; | |
| if (rich) { | |
| if (fitsOnOneLine) { | |
| if (!tagline) { | |
| return `${theme.heading(title)} ${theme.info(version)} ${theme.muted(`(${commitLabel})`)}`; | |
| } | |
| return `${theme.heading(title)} ${theme.info(version)} ${theme.muted( | |
| `(${commitLabel})`, | |
| )} ${theme.muted("—")} ${theme.accentDim(tagline)}`; | |
| } | |
| const line1 = `${theme.heading(title)} ${theme.info(version)} ${theme.muted( | |
| `(${commitLabel})`, | |
| )}`; | |
| if (!tagline) { | |
| return line1; | |
| } | |
| const line2 = `${" ".repeat(indent.length)}${theme.accentDim(tagline)}`; | |
| return `${line1}\n${line2}`; | |
| } | |
| if (fitsOnOneLine) { | |
| return plainFullLine; | |
| } | |
| const line1 = plainBaseLine; | |
| if (!tagline) { | |
| return line1; | |
| } | |
| const line2 = `${" ".repeat(indent.length)}${tagline}`; | |
| return `${line1}\n${line2}`; | |
| } | |
| // Rare day-seeded ASCII lobster above the banner: random-tagline mode only, | |
| // rich terminals only, never in CI (see lobster-art.ts for the odds). | |
| function resolveLobsterArt(options: BannerOptions): string | null { | |
| const mode = resolveTaglineMode(options); | |
| if (mode === "off" || mode === "default") { | |
| return null; | |
| } | |
| if (!(options.richTty ?? isRich())) { | |
| return null; | |
| } | |
| const now = options.now ? options.now() : new Date(); | |
| const art = pickCliLobsterArt(now, options.env ?? process.env); | |
| return art ? theme.accentDim(art) : null; | |
| } | |
| /** Emit the CLI banner once for interactive, non-JSON, non-version invocations. */ | |
| export function emitCliBanner(version: string, options: BannerOptions = {}) { | |
| if (bannerEmitted) { | |
| return; | |
| } | |
| const argv = options.argv ?? process.argv; | |
| const isTty = options.isTty ?? process.stdout.isTTY; | |
| if (!isTty) { | |
| return; | |
| } | |
| if (hasJsonFlag(argv)) { | |
| return; | |
| } | |
| if (hasVersionFlag(argv)) { | |
| return; | |
| } | |
| const line = formatCliBannerLine(version, options); | |
| const art = resolveLobsterArt(options); | |
| process.stdout.write(`\n${art ? `${art}\n` : ""}${line}\n\n`); | |
| bannerEmitted = true; | |
| } | |
| /** Return whether the current process already emitted the CLI banner. */ | |
| export function hasEmittedCliBanner(): boolean { | |
| return bannerEmitted; | |
| } | |