diff --git a/src/components/LogoV2/WelcomeV2.tsx b/src/components/LogoV2/WelcomeV2.tsx index ba6cf82127..54b7064dc8 100644 --- a/src/components/LogoV2/WelcomeV2.tsx +++ b/src/components/LogoV2/WelcomeV2.tsx @@ -1,433 +1,21 @@ -import { c as _c } from "react-compiler-runtime"; -import React from 'react'; -import { Box, Text, useTheme } from 'src/ink.js'; -import { env } from '../../utils/env.js'; -const WELCOME_V2_WIDTH = 58; -export function WelcomeV2() { - const $ = _c(35); - const [theme] = useTheme(); - if (env.terminal === "Apple_Terminal") { - let t0; - if ($[0] !== theme) { - // VERBOO-BRAND: welcome message - t0 = ; - $[0] = theme; - $[1] = t0; - } else { - t0 = $[1]; - } - return t0; - } - if (["light", "light-daltonized", "light-ansi"].includes(theme)) { - let t0; - let t1; - let t2; - let t3; - let t4; - let t5; - let t6; - let t7; - let t8; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t0 = {"Welcome to Verboo Code"} v{MACRO.DISPLAY_VERSION ?? MACRO.VERSION} ; - t1 = {"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}; - t2 = {" "}; - t3 = {" "}; - t4 = {" "}; - t5 = {" \u2591\u2591\u2591\u2591\u2591\u2591 "}; - t6 = {" \u2591\u2591\u2591 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - t7 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - t8 = {" "}; - $[2] = t0; - $[3] = t1; - $[4] = t2; - $[5] = t3; - $[6] = t4; - $[7] = t5; - $[8] = t6; - $[9] = t7; - $[10] = t8; - } else { - t0 = $[2]; - t1 = $[3]; - t2 = $[4]; - t3 = $[5]; - t4 = $[6]; - t5 = $[7]; - t6 = $[8]; - t7 = $[9]; - t8 = $[10]; - } - let t9; - if ($[11] === Symbol.for("react.memo_cache_sentinel")) { - t9 = {" \u2591\u2591\u2591\u2591"}{" \u2588\u2588 "}; - $[11] = t9; - } else { - t9 = $[11]; - } - let t10; - let t11; - if ($[12] === Symbol.for("react.memo_cache_sentinel")) { - t10 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591"}{" \u2588\u2588\u2592\u2592\u2588\u2588 "}; - t11 = {" \u2592\u2592 \u2588\u2588 \u2592"}; - $[12] = t10; - $[13] = t11; - } else { - t10 = $[12]; - t11 = $[13]; - } - let t12; - if ($[14] === Symbol.for("react.memo_cache_sentinel")) { - t12 = {" "}{" "}{" \u2592\u2592\u2591\u2591\u2592\u2592 \u2592 \u2592\u2592"}; - $[14] = t12; - } else { - t12 = $[14]; - } - let t13; - if ($[15] === Symbol.for("react.memo_cache_sentinel")) { - t13 = {" "}{" πŸ‘» "}{" \u2592\u2592 \u2592\u2592 "}; - $[15] = t13; - } else { - t13 = $[15]; - } - let t14; - if ($[16] === Symbol.for("react.memo_cache_sentinel")) { - t14 = {" "}{" "}{" \u2591 \u2592 "}; - $[16] = t14; - } else { - t14 = $[16]; - } - let t15; - if ($[17] === Symbol.for("react.memo_cache_sentinel")) { - t15 = {t0}{t1}{t2}{t3}{t4}{t5}{t6}{t7}{t8}{t9}{t10}{t11}{t12}{t13}{t14}{"\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}{" "}{"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2591\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2592\u2026\u2026\u2026\u2026"}; - $[17] = t15; - } else { - t15 = $[17]; - } - return t15; - } - let t0; - let t1; - let t2; - let t3; - let t4; - let t5; - let t6; - if ($[18] === Symbol.for("react.memo_cache_sentinel")) { - t0 = {"Welcome to Verboo Code"} v{MACRO.DISPLAY_VERSION ?? MACRO.VERSION} ; - t1 = {"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}; - t2 = {" "}; - t3 = {" * \u2588\u2588\u2588\u2588\u2588\u2593\u2593\u2591 "}; - t4 = {" * \u2588\u2588\u2588\u2593\u2591 \u2591\u2591 "}; - t5 = {" \u2591\u2591\u2591\u2591\u2591\u2591 \u2588\u2588\u2588\u2593\u2591 "}; - t6 = {" \u2591\u2591\u2591 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2588\u2588\u2588\u2593\u2591 "}; - $[18] = t0; - $[19] = t1; - $[20] = t2; - $[21] = t3; - $[22] = t4; - $[23] = t5; - $[24] = t6; - } else { - t0 = $[18]; - t1 = $[19]; - t2 = $[20]; - t3 = $[21]; - t4 = $[22]; - t5 = $[23]; - t6 = $[24]; - } - let t10; - let t11; - let t7; - let t8; - let t9; - if ($[25] === Symbol.for("react.memo_cache_sentinel")) { - t7 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}*{" \u2588\u2588\u2593\u2591\u2591 \u2593 "}; - t8 = {" \u2591\u2593\u2593\u2588\u2588\u2588\u2593\u2593\u2591 "}; - t9 = {" * \u2591\u2591\u2591\u2591 "}; - t10 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - t11 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - $[25] = t10; - $[26] = t11; - $[27] = t7; - $[28] = t8; - $[29] = t9; - } else { - t10 = $[25]; - t11 = $[26]; - t7 = $[27]; - t8 = $[28]; - t9 = $[29]; - } - let t12; - if ($[30] === Symbol.for("react.memo_cache_sentinel")) { - t12 = {" πŸ‘» "}; - $[30] = t12; - } else { - t12 = $[30]; - } - let t13; - if ($[31] === Symbol.for("react.memo_cache_sentinel")) { - t13 = {" "}{t12}{" "}* ; - $[31] = t13; - } else { - t13 = $[31]; - } - let t14; - if ($[32] === Symbol.for("react.memo_cache_sentinel")) { - t14 = {" "}{" "}{" "}*{" "}; - $[32] = t14; - } else { - t14 = $[32]; - } - let t15; - if ($[33] === Symbol.for("react.memo_cache_sentinel")) { - t15 = {" "}{" "}{" * "}; - $[33] = t15; - } else { - t15 = $[33]; - } - let t16; - if ($[34] === Symbol.for("react.memo_cache_sentinel")) { - t16 = {t0}{t1}{t2}{t3}{t4}{t5}{t6}{t7}{t8}{t9}{t10}{t11}{t13}{t14}{t15}{"\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}{" "}{"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}; - $[34] = t16; - } else { - t16 = $[34]; - } - return t16; -} -type AppleTerminalWelcomeV2Props = { - theme: string; - welcomeMessage: string; -}; -function AppleTerminalWelcomeV2(t0) { - const $ = _c(44); - const { - theme, - welcomeMessage - } = t0; - const isLightTheme = ["light", "light-daltonized", "light-ansi"].includes(theme); - if (isLightTheme) { - let t1; - if ($[0] !== welcomeMessage) { - t1 = {welcomeMessage} ; - $[0] = welcomeMessage; - $[1] = t1; - } else { - t1 = $[1]; - } - let t2; - if ($[2] === Symbol.for("react.memo_cache_sentinel")) { - t2 = v{MACRO.DISPLAY_VERSION ?? MACRO.VERSION} ; - $[2] = t2; - } else { - t2 = $[2]; - } - let t3; - if ($[3] !== t1) { - t3 = {t1}{t2}; - $[3] = t1; - $[4] = t3; - } else { - t3 = $[4]; - } - let t10; - let t11; - let t4; - let t5; - let t6; - let t7; - let t8; - let t9; - if ($[5] === Symbol.for("react.memo_cache_sentinel")) { - t4 = {"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}; - t5 = {" "}; - t6 = {" "}; - t7 = {" "}; - t8 = {" \u2591\u2591\u2591\u2591\u2591\u2591 "}; - t9 = {" \u2591\u2591\u2591 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - t10 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - t11 = {" "}; - $[5] = t10; - $[6] = t11; - $[7] = t4; - $[8] = t5; - $[9] = t6; - $[10] = t7; - $[11] = t8; - $[12] = t9; - } else { - t10 = $[5]; - t11 = $[6]; - t4 = $[7]; - t5 = $[8]; - t6 = $[9]; - t7 = $[10]; - t8 = $[11]; - t9 = $[12]; - } - let t12; - if ($[13] === Symbol.for("react.memo_cache_sentinel")) { - t12 = {" \u2591\u2591\u2591\u2591"}{" \u2588\u2588 "}; - $[13] = t12; - } else { - t12 = $[13]; - } - let t13; - let t14; - let t15; - if ($[14] === Symbol.for("react.memo_cache_sentinel")) { - t13 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591"}{" \u2588\u2588\u2592\u2592\u2588\u2588 "}; - t14 = {" \u2592\u2592 \u2588\u2588 \u2592"}; - t15 = {" \u2592\u2592\u2591\u2591\u2592\u2592 \u2592 \u2592\u2592"}; - $[14] = t13; - $[15] = t14; - $[16] = t15; - } else { - t13 = $[14]; - t14 = $[15]; - t15 = $[16]; - } - let t16; - if ($[17] === Symbol.for("react.memo_cache_sentinel")) { - t16 = {" "}{" πŸ‘» "}{" \u2592\u2592 \u2592\u2592 "}; - $[17] = t16; - } else { - t16 = $[17]; - } - let t17; - if ($[18] === Symbol.for("react.memo_cache_sentinel")) { - t17 = {" "}{" "}{" \u2591 \u2592 "}; - $[18] = t17; - } else { - t17 = $[18]; - } - let t18; - if ($[19] === Symbol.for("react.memo_cache_sentinel")) { - t18 = {"\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}{" "}{"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2591\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2592\u2026\u2026\u2026\u2026"}; - $[19] = t18; - } else { - t18 = $[19]; - } - let t19; - if ($[20] !== t3) { - t19 = {t3}{t4}{t5}{t6}{t7}{t8}{t9}{t10}{t11}{t12}{t13}{t14}{t15}{t16}{t17}{t18}; - $[20] = t3; - $[21] = t19; - } else { - t19 = $[21]; - } - return t19; - } - let t1; - if ($[22] !== welcomeMessage) { - t1 = {welcomeMessage} ; - $[22] = welcomeMessage; - $[23] = t1; - } else { - t1 = $[23]; - } - let t2; - if ($[24] === Symbol.for("react.memo_cache_sentinel")) { - t2 = v{MACRO.DISPLAY_VERSION ?? MACRO.VERSION} ; - $[24] = t2; - } else { - t2 = $[24]; - } - let t3; - if ($[25] !== t1) { - t3 = {t1}{t2}; - $[25] = t1; - $[26] = t3; - } else { - t3 = $[26]; - } - let t4; - let t5; - let t6; - let t7; - let t8; - let t9; - if ($[27] === Symbol.for("react.memo_cache_sentinel")) { - t4 = {"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}; - t5 = {" "}; - t6 = {" * \u2588\u2588\u2588\u2588\u2588\u2593\u2593\u2591 "}; - t7 = {" * \u2588\u2588\u2588\u2593\u2591 \u2591\u2591 "}; - t8 = {" \u2591\u2591\u2591\u2591\u2591\u2591 \u2588\u2588\u2588\u2593\u2591 "}; - t9 = {" \u2591\u2591\u2591 \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 \u2588\u2588\u2588\u2593\u2591 "}; - $[27] = t4; - $[28] = t5; - $[29] = t6; - $[30] = t7; - $[31] = t8; - $[32] = t9; - } else { - t4 = $[27]; - t5 = $[28]; - t6 = $[29]; - t7 = $[30]; - t8 = $[31]; - t9 = $[32]; - } - let t10; - let t11; - let t12; - let t13; - let t14; - if ($[33] === Symbol.for("react.memo_cache_sentinel")) { - t10 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}*{" \u2588\u2588\u2593\u2591\u2591 \u2593 "}; - t11 = {" \u2591\u2593\u2593\u2588\u2588\u2588\u2593\u2593\u2591 "}; - t12 = {" * \u2591\u2591\u2591\u2591 "}; - t13 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - t14 = {" \u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591\u2591 "}; - $[33] = t10; - $[34] = t11; - $[35] = t12; - $[36] = t13; - $[37] = t14; - } else { - t10 = $[33]; - t11 = $[34]; - t12 = $[35]; - t13 = $[36]; - t14 = $[37]; - } - let t15; - if ($[38] === Symbol.for("react.memo_cache_sentinel")) { - t15 = {" "}* ; - $[38] = t15; - } else { - t15 = $[38]; - } - let t16; - if ($[39] === Symbol.for("react.memo_cache_sentinel")) { - t16 = {" "}{" πŸ‘» "}{" "}*{" "}; - $[39] = t16; - } else { - t16 = $[39]; - } - let t17; - if ($[40] === Symbol.for("react.memo_cache_sentinel")) { - t17 = {" "}{" "}{" * "}; - $[40] = t17; - } else { - t17 = $[40]; - } - let t18; - if ($[41] === Symbol.for("react.memo_cache_sentinel")) { - t18 = {"\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}{" "}{"\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026"}; - $[41] = t18; - } else { - t18 = $[41]; - } - let t19; - if ($[42] !== t3) { - t19 = {t3}{t4}{t5}{t6}{t7}{t8}{t9}{t10}{t11}{t12}{t13}{t14}{t15}{t16}{t17}{t18}; - $[42] = t3; - $[43] = t19; - } else { - t19 = $[43]; - } - return t19; +import * as React from 'react' +import { Box, Text } from 'src/ink.js' + +export function WelcomeV2(): React.ReactElement { + const version = MACRO.DISPLAY_VERSION ?? MACRO.VERSION + + return ( + + + πŸ‘» + + Verboo Code + + v{version} + + + Build, debug, and ship from your terminal. + + + ) } diff --git a/src/components/PromptInput/PromptInput.tsx b/src/components/PromptInput/PromptInput.tsx index 8d298ddc91..70cf9010e7 100644 --- a/src/components/PromptInput/PromptInput.tsx +++ b/src/components/PromptInput/PromptInput.tsx @@ -1,5 +1,4 @@ import { feature } from 'bun:bundle'; -import chalk from 'chalk'; import * as path from 'path'; import * as React from 'react'; import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'; @@ -2283,7 +2282,7 @@ function PromptInput({ Waiting for permission… } - + {mode === 'prompt' && !exitMessage.show && !isPasting ? : } {swarmBanner ? <> @@ -2305,7 +2304,7 @@ function PromptInput({ {'─'.repeat(columns)} : - + {showFastIcon && {' '}{getFastIconString(true, fastModeCooldown)}{' '}{showFastIconHint && /fast}} @@ -2369,14 +2368,12 @@ function getInitialPasteId(messages: Message[]): number { } return maxId + 1; } -function buildBorderText(showFastIcon: boolean, showFastIconHint: boolean, fastModeCooldown: boolean): BorderTextOptions | undefined { - if (!showFastIcon) return undefined; - const fastSeg = showFastIconHint ? `${getFastIconString(true, fastModeCooldown)} ${chalk.dim('/fast')}` : getFastIconString(true, fastModeCooldown); +function buildPromptBorderText(mode: PromptInputMode): BorderTextOptions { return { - content: ` ${fastSeg} `, + content: mode === 'bash' ? ' shell ' : ' πŸ‘» ', position: 'top', - align: 'end', - offset: 0 + align: 'start', + offset: 1 }; } export default React.memo(PromptInput); diff --git a/src/components/PromptInput/usePromptInputPlaceholder.ts b/src/components/PromptInput/usePromptInputPlaceholder.ts index 36d8d362b9..99bfbfea9b 100644 --- a/src/components/PromptInput/usePromptInputPlaceholder.ts +++ b/src/components/PromptInput/usePromptInputPlaceholder.ts @@ -62,8 +62,10 @@ export function usePromptInputPlaceholder({ promptSuggestionEnabled && !proactiveModule?.isProactiveActive() ) { - return getExampleCommandFromCache() + return getExampleCommandFromCache() ?? 'Ask Verboo to build, fix, or explain…' } + + return 'Ask Verboo to build, fix, or explain…' }, [ input, queuedCommands, diff --git a/src/components/StartupScreen.test.ts b/src/components/StartupScreen.test.ts index f9eabd0aa0..991f5a6870 100644 --- a/src/components/StartupScreen.test.ts +++ b/src/components/StartupScreen.test.ts @@ -193,18 +193,20 @@ describe('renderStartupScreen', () => { isLocal: false, } - test('renders the mascot layout safely in a wide terminal', () => { + test('uses the compact ghost identity in a wide terminal', () => { const output = renderStartupScreen(provider, '0.14.5', '~/project', 120) const plainOutput = stripAnsi(output) - expect(plainOutput).toContain('β–„β–€β–€β–€β–€β–€β–€β–€β–„') + expect(plainOutput).toContain('πŸ‘»') expect(plainOutput).toContain('Verboo Code') + expect(plainOutput).not.toContain('β–„β–€β–€β–€β–€β–€β–€β–€β–„') + expect(plainOutput).not.toContain('Tokens ilimitados') expect(output).toContain('\x1b[0m') expect(output).not.toContain('undefined') expect(plainOutput.split('\n').every(line => line.length <= 120)).toBe(true) }) - test('uses the compact header in a narrow terminal', () => { + test('keeps the compact identity in a narrow terminal', () => { const output = stripAnsi( renderStartupScreen( { diff --git a/src/components/StartupScreen.ts b/src/components/StartupScreen.ts index 2afdfc1cb9..867caf96c2 100644 --- a/src/components/StartupScreen.ts +++ b/src/components/StartupScreen.ts @@ -1,9 +1,6 @@ /** - * VERBOO-BRAND: Verboo Code startup screen β€” filled-block text logo with - * Verboo purple gradient. Called once at CLI startup before the Ink UI renders. - * - * NOTE: cores aqui sΓ£o RGB hardcoded (NΓƒO usam theme.ts) β€” toda mudanΓ§a - * de marca neste arquivo Γ© manual. + * Minimal Verboo Code identity printed once before the Ink UI renders. + * Keep this compact: the terminal is a workspace, not a splash screen. */ import { VERBOO_ROUTER_URL, isVerbooMode } from '../constants/oauth.js' @@ -19,89 +16,11 @@ const ESC = '\x1b[' const RESET = `${ESC}0m` const DIM = `${ESC}2m` -type RGB = [number, number, number] const rgb = (r: number, g: number, b: number) => `${ESC}38;2;${r};${g};${b}m` -function lerp(a: RGB, b: RGB, t: number): RGB { - return [ - Math.round(a[0] + (b[0] - a[0]) * t), - Math.round(a[1] + (b[1] - a[1]) * t), - Math.round(a[2] + (b[2] - a[2]) * t), - ] -} - -function gradAt(stops: RGB[], t: number): RGB { - const c = Math.max(0, Math.min(1, t)) - const s = c * (stops.length - 1) - const i = Math.floor(s) - if (i >= stops.length - 1) return stops[stops.length - 1] - return lerp(stops[i], stops[i + 1], s - i) -} - -function paintLine(text: string, stops: RGB[], lineT: number): string { - let out = '' - for (let i = 0; i < text.length; i++) { - const t = text.length > 1 ? lineT * 0.5 + (i / (text.length - 1)) * 0.5 : lineT - const [r, g, b] = gradAt(stops, t) - out += `${rgb(r, g, b)}${text[i]}` - } - return out + RESET -} - -// ─── Colors ─────────────────────────────────────────────────────────────────── - -// VERBOO-BRAND: purple gradient for the logo (was sunset orange) -const SUNSET_GRAD: RGB[] = [ - [213, 142, 255], // light purple - [193, 92, 255], - [173, 52, 254], // brand #AD34FE - [146, 1, 243], - [110, 0, 200], - [80, 0, 150], -] - -const ACCENT: RGB = [173, 52, 254] // VERBOO-BRAND: brand purple -const CREAM: RGB = [220, 200, 240] // VERBOO-BRAND: soft lavender -const DIMCOL: RGB = [120, 100, 140] // VERBOO-BRAND: muted cool gray -const BORDER: RGB = [80, 65, 100] // VERBOO-BRAND: dark cool gray - -// ─── Filled Block Text Logo ─────────────────────────────────────────────────── - -// VERBOO-BRAND: "VERBOO CODE" em uma linha, estilo rounded (cantos \u256d\u256e\u2570\u256f, tra\u00e7os \u2500) -const LOGO_VERBOO_CODE = [ - ` \u2588\u2588\u256e \u2588\u2588\u256e\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u256e\u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u256e`, - ` \u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u256d\u2500\u2500\u2500\u2500\u256f\u2588\u2588\u256d\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u256d\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u256d\u2500\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u256d\u2500\u2500\u2500\u2588\u2588\u256e \u2588\u2588\u256d\u2500\u2500\u2500\u2500\u256f\u2588\u2588\u256d\u2500\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u256d\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u256d\u2500\u2500\u2500\u2500\u256f`, - ` \u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2588\u2588\u2588\u256e \u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f\u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f\u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2502 \u2588\u2588\u2502 \u2588\u2588\u2502 \u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2588\u2588\u2588\u256e `, - ` \u2570\u2588\u2588\u256e \u2588\u2588\u256d\u256f\u2588\u2588\u256d\u2500\u2500\u256f \u2588\u2588\u256d\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u256d\u2500\u2500\u2588\u2588\u256e\u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2502 \u2588\u2588\u2502 \u2588\u2588\u2502 \u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u256d\u2500\u2500\u256f `, - ` \u2570\u2588\u2588\u2588\u2588\u256d\u256f \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u256e\u2588\u2588\u2502 \u2588\u2588\u2502\u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f\u2570\u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f\u2570\u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f \u2570\u2588\u2588\u2588\u2588\u2588\u2588\u256e\u2570\u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f\u2588\u2588\u2588\u2588\u2588\u2588\u256d\u256f\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u256e`, - ` \u2570\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u256f\u2570\u2500\u256f \u2570\u2500\u256f\u2570\u2500\u2500\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u256f \u2570\u2500\u2500\u2500\u2500\u2500\u2500\u256f`, -] - -// ─── Verboo ASCII Logo ──────────────────────────────────────────────────────── - -const VERBOO_LOGO = [ - ` β–„β–€β–€β–€β–€β–€β–€β–€β–„ `, - `β–„β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–„`, - `β–€β–€β–€ β–€β–€β–€β–€β–€ β–€β–€β–€`, - `β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€`, - `β–€β–€β–€β–€β–€β–„β–„β–„β–€β–€β–€β–€β–€`, - ` β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€β–€ `, - `β–„β–€β–€ β–€β–€β–€β–€β–€ β–€β–€β–„`, -] - -// MΓ‘scara 1:1 com VERBOO_LOGO β€” 1 = bg roxo (bloco cheio), 0 = fg sΓ³ (meio-bloco) -// Edite os 1/0 para escolher quais caracteres ficam totalmente preenchidos -const VERBOO_LOGO_MASK = [ - ` 011111110 `, - `0111111111110`, - `1110111110111`, - `1111011101111`, - `1111100011111`, - ` 11111111111 `, - `110 01110 011`, -] - -const STARTUP_LOGO_MIN_COLUMNS = 80 +const ACCENT = [173, 52, 254] as const +const DIMCOL = [120, 100, 140] as const +const STARTUP_DEFAULT_COLUMNS = 80 // ─── Provider detection ─────────────────────────────────────────────────────── @@ -232,13 +151,6 @@ export function detectProvider(modelOverride?: string): { name: string; model: s return { name: 'Verboo', model: resolvedModel, baseUrl, isLocal } } -// ─── Box drawing ────────────────────────────────────────────────────────────── - -function boxRow(content: string, width: number, rawLen: number): string { - const pad = Math.max(0, width - 2 - rawLen) - return `${rgb(...BORDER)}\u2502${RESET}${content}${' '.repeat(pad)}${rgb(...BORDER)}\u2502${RESET}` -} - // ─── Main ───────────────────────────────────────────────────────────────────── function truncateStartupText(text: string, maxLength: number): string { @@ -254,88 +166,30 @@ export function renderStartupScreen( displayCwd: string, columns: number, ): string { - const out: string[] = [] + const out: string[] = [''] const bold = `${ESC}1m` const PURPLE = rgb(...ACCENT) - const PURPLE_FILL = `${rgb(...ACCENT)}${ESC}48;2;${ACCENT[0]};${ACCENT[1]};${ACCENT[2]}m` - const SOFT = rgb(...CREAM) const DIMP = `${DIM}${rgb(...DIMCOL)}` const STATUS_C = p.isLocal ? rgb(130, 200, 140) : PURPLE const statusLabel = p.isLocal ? 'local' : 'cloud' - const LOGO_TEXT_PADDING = 2 - - out.push('') - - if (columns < STARTUP_LOGO_MIN_COLUMNS) { - const compactTextWidth = Math.max(1, columns - 6) - const provider = truncateStartupText(`${p.name} \u00b7 ${p.model}`, compactTextWidth) - const endpoint = truncateStartupText(p.baseUrl, compactTextWidth) - const cwd = truncateStartupText(displayCwd, compactTextWidth) - - out.push(` ${PURPLE}\ud83d\udc7b${RESET} ${bold}${SOFT}Verboo Code${RESET} ${DIMP}v${version}${RESET}`) - out.push(` ${DIMP}Tokens ilimitados \u00b7 Privacidade \u00b7 Velocidade${RESET}`) - out.push(` ${DIMP}${provider}${RESET}`) - out.push(` ${DIMP}${endpoint}${RESET}`) - out.push(` ${DIMP}${cwd}${RESET}`) - } else { - const maxLogoWidth = Math.max(...VERBOO_LOGO.map(line => line.trimEnd().length)) - const rightTextWidth = Math.max( - 1, - columns - 2 - maxLogoWidth - LOGO_TEXT_PADDING, - ) - const provider = truncateStartupText(`${p.name} \u00b7 ${p.model}`, rightTextWidth) - const endpoint = truncateStartupText(p.baseUrl, rightTextWidth) - const cwd = truncateStartupText(displayCwd, rightTextWidth) - const rightCol = [ - ``, - `${bold}${SOFT}Verboo Code${RESET} ${DIMP}v${version}${RESET}`, - `${DIMP}Tokens ilimitados \u00b7 Privacidade \u00b7 Velocidade${RESET}`, - `${DIMP}${provider}${RESET}`, - `${DIMP}${endpoint}${RESET}`, - `${DIMP}${cwd}${RESET}`, - ``, - ] - - const paintedLogo: { text: string; visualWidth: number }[] = [] - for (let i = 0; i < VERBOO_LOGO.length; i++) { - const line = (VERBOO_LOGO[i] ?? '').trimEnd() - const mask = VERBOO_LOGO_MASK[i] ?? '' - let painted = '' - for (let j = 0; j < line.length; j++) { - const ch = line[j] ?? '' - const isBlock = ch === '\u2580' || ch === '\u2584' - if (isBlock && mask[j] === '1') { - painted += `${PURPLE_FILL}${ch}${RESET}` - } else if (isBlock) { - painted += `${PURPLE}${ch}${RESET}` - } else { - painted += ch - } - } - paintedLogo.push({ text: painted, visualWidth: line.length }) - } - - for (let i = 0; i < paintedLogo.length; i++) { - const { text, visualWidth } = paintedLogo[i] ?? { - text: '', - visualWidth: 0, - } - const gap = ' '.repeat( - Math.max(0, maxLogoWidth - visualWidth + LOGO_TEXT_PADDING), - ) - out.push(` ${text}${gap}${rightCol[i] ?? ''}`) - } - } - + const detailWidth = Math.max(1, columns - 8) + const providerAndModel = p.name === 'Verboo' ? p.model : `${p.name} Β· ${p.model}` + const model = truncateStartupText(providerAndModel, Math.max(1, detailWidth - statusLabel.length - 4)) + const cwd = truncateStartupText(displayCwd, detailWidth) + const hint = truncateStartupText('Type a request, or use /help for commands', detailWidth) + const shownVersion = truncateStartupText(version, Math.max(1, columns - 24)) + + out.push(` πŸ‘» ${bold}${PURPLE}Verboo Code${RESET} ${DIMP}v${shownVersion}${RESET}`) + out.push(` ${STATUS_C}●${RESET} ${DIMP}${model} Β· ${statusLabel}${RESET}`) + out.push(` ${DIMP}${cwd}${RESET}`) out.push('') - out.push(` ${STATUS_C}\u25cf${RESET} ${DIMP}${statusLabel}${RESET} ${DIMP}Ready \u2014 type ${RESET}${PURPLE}/help${RESET}${DIMP} to begin${RESET}`) + out.push(` ${DIMP}${hint}${RESET}`) out.push('') return `${out.join('\n')}\n` } -// VERBOO-BRAND: compact rounded header (replaces giant ASCII splash). -// Layout inspired by the V2 logo style \u2014 logo + name + meta on the right. +// VERBOO-BRAND: compact identity shared by every interactive startup. export function printStartupScreen(modelOverride?: string): void { // Skip in non-interactive / CI / print mode if (process.env.CI || !process.stdout.isTTY) return @@ -348,6 +202,6 @@ export function printStartupScreen(modelOverride?: string): void { const displayCwd = home && cwd.startsWith(home) ? `~${cwd.slice(home.length)}` : cwd const version = MACRO.DISPLAY_VERSION ?? MACRO.VERSION - const columns = process.stdout.columns ?? STARTUP_LOGO_MIN_COLUMNS + const columns = process.stdout.columns ?? STARTUP_DEFAULT_COLUMNS process.stdout.write(renderStartupScreen(p, version, displayCwd, columns)) }