diff options
| author | Taylor Mullen <[email protected]> | 2025-04-19 12:38:09 -0400 |
|---|---|---|
| committer | N. Taylor Mullen <[email protected]> | 2025-04-19 17:10:06 -0400 |
| commit | f7edf711906ed8492fc65f3c1cfad1ccd7ede187 (patch) | |
| tree | fcf6e6152cdddfee91c12316cab906d5e31d0e75 | |
| parent | 3fce6cea27d3e6129d6c06e528b62e1b11bf7094 (diff) | |
Give Gemini Code a face lift.
- This utilizes `ink-gradient` to render GEMINI CODE in amazing colors.
- Added a shared color configuration for UX (should this be in config?). It's very possible that we shouldn't be talking about the specific colors and instead be mentioning "foreground"/"background"/inlineCode etc. type colors.
- Updated existing color usages to utilize `Colors.*`
Fixes https://b.corp.google.com/issues/411385593
18 files changed, 223 insertions, 109 deletions
diff --git a/package-lock.json b/package-lock.json index 3f29fdbf..a3fa1b2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1062,6 +1062,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/gradient-string": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@types/gradient-string/-/gradient-string-1.1.6.tgz", + "integrity": "sha512-LkaYxluY4G5wR1M4AKQUal2q61Di1yVVCw42ImFTuaIoQVgmV0WP1xUaLB8zwb47mp82vWTpePI9JmrjEnJ7nQ==", + "license": "MIT", + "dependencies": { + "@types/tinycolor2": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -1096,6 +1105,12 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/tinycolor2": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz", + "integrity": "sha512-iEN8J0BoMnsWBqjVbWH/c0G0Hh7O21lpR2/+PrvAVgWdzL7eexIFm4JN/Wn10PTcmNdtS6U67r499mlWMXOxNw==", + "license": "MIT" + }, "node_modules/@types/yargs": { "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", @@ -1777,9 +1792,9 @@ "license": "MIT" }, "node_modules/bignumber.js": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.2.1.tgz", - "integrity": "sha512-+NzaKgOUvInq9TIUZ1+DRspzf/HApkCwD4btfuasFTdrfnOxqx853TgDpMolp+uv4RpRp7bPcEU2zKr9+fRmyw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", + "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", "license": "MIT", "engines": { "node": "*" @@ -1905,7 +1920,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -3364,6 +3378,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gradient-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/gradient-string/-/gradient-string-2.0.2.tgz", + "integrity": "sha512-rEDCuqUQ4tbD78TpzsMtt5OIf0cBCSDWSJtUDaF6JsAh+k0v9r++NzxNEG87oDZx9ZwGhD8DaezR2L/yrw0Jdw==", + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "tinygradient": "^1.1.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3401,7 +3428,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3588,6 +3614,27 @@ } } }, + "node_modules/ink-gradient": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ink-gradient/-/ink-gradient-3.0.0.tgz", + "integrity": "sha512-OVyPBovBxE1tFcBhSamb+P1puqDP6pG3xFe2W9NiLgwUZd9RbcjBeR7twLbliUT9navrUstEf1ZcPKKvx71BsQ==", + "license": "MIT", + "dependencies": { + "@types/gradient-string": "^1.1.2", + "gradient-string": "^2.0.2", + "prop-types": "^15.8.1", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + }, + "peerDependencies": { + "ink": ">=4" + } + }, "node_modules/ink-select-input": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/ink-select-input/-/ink-select-input-6.1.0.tgz", @@ -4442,7 +4489,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4798,7 +4844,6 @@ "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.4.0", @@ -4852,7 +4897,6 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, "node_modules/react-reconciler": { @@ -5544,7 +5588,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5573,6 +5616,12 @@ "dev": true, "license": "MIT" }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" + }, "node_modules/tinyexec": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", @@ -5581,13 +5630,13 @@ "license": "MIT" }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -5625,6 +5674,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinygradient": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/tinygradient/-/tinygradient-1.1.5.tgz", + "integrity": "sha512-8nIfc2vgQ4TeLnk2lFj4tRLvvJwEfQuabdsmvDdQPT0xlk9TaNtpGd6nNRxXoK6vQhN6RSzj+Cnp5tTQmpxmbw==", + "license": "MIT", + "dependencies": { + "@types/tinycolor2": "^1.4.0", + "tinycolor2": "^1.0.0" + } + }, "node_modules/tinypool": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", @@ -6424,6 +6483,7 @@ "dotenv": "^16.4.7", "fast-glob": "^3.3.3", "ink": "^5.2.0", + "ink-gradient": "^3.0.0", "ink-select-input": "^6.0.0", "ink-spinner": "^5.0.0", "ink-text-input": "^6.0.0", @@ -6446,7 +6506,15 @@ "packages/server": { "name": "@gemini-code/server", "version": "1.0.0", + "dependencies": { + "@google/genai": "^0.8.0", + "diff": "^7.0.0", + "dotenv": "^16.4.7", + "fast-glob": "^3.3.3" + }, "devDependencies": { + "@types/diff": "^7.0.2", + "@types/dotenv": "^6.1.1", "typescript": "^5.3.3", "vitest": "^3.1.1" }, diff --git a/packages/cli/package.json b/packages/cli/package.json index 8ead685a..3ccdc410 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -23,6 +23,7 @@ "dotenv": "^16.4.7", "fast-glob": "^3.3.3", "ink": "^5.2.0", + "ink-gradient": "^3.0.0", "ink-select-input": "^6.0.0", "ink-spinner": "^5.0.0", "ink-text-input": "^6.0.0", diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index fa9b6f9b..14b76c8f 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -11,7 +11,6 @@ import { useGeminiStream } from './hooks/useGeminiStream.js'; import { useLoadingIndicator } from './hooks/useLoadingIndicator.js'; import { useInputHistory } from './hooks/useInputHistory.js'; import { Header } from './components/Header.js'; -import { Tips } from './components/Tips.js'; import { HistoryDisplay } from './components/HistoryDisplay.js'; import { LoadingIndicator } from './components/LoadingIndicator.js'; import { InputPrompt } from './components/InputPrompt.js'; @@ -22,7 +21,8 @@ import { useStartupWarnings, useInitializationErrorEffect, } from './hooks/useAppEffects.js'; -import type { Config } from '@gemini-code/server'; +import { shortenPath, type Config } from '@gemini-code/server'; +import { Colors } from './colors.js'; interface AppProps { config: Config; @@ -73,39 +73,37 @@ export const App = ({ config }: AppProps) => { return ( <Box flexDirection="column" padding={1} marginBottom={1} width="100%"> - <Header cwd={config.getTargetDir()} /> + <Header /> {startupWarnings.length > 0 && ( <Box borderStyle="round" - borderColor="yellow" + borderColor={Colors.AccentYellow} paddingX={1} marginY={1} flexDirection="column" > {startupWarnings.map((warning, index) => ( - <Text key={index} color="yellow"> + <Text key={index} color={Colors.AccentYellow}> {warning} </Text> ))} </Box> )} - <Tips /> - {initError && streamingState !== StreamingState.Responding && !isWaitingForToolConfirmation && ( <Box borderStyle="round" - borderColor="red" + borderColor={Colors.AccentRed} paddingX={1} marginBottom={1} > {history.find( (item) => item.type === 'error' && item.text?.includes(initError), )?.text ? ( - <Text color="red"> + <Text color={Colors.AccentRed}> { history.find( (item) => @@ -115,8 +113,10 @@ export const App = ({ config }: AppProps) => { </Text> ) : ( <> - <Text color="red">Initialization Error: {initError}</Text> - <Text color="red"> + <Text color={Colors.AccentRed}> + Initialization Error: {initError} + </Text> + <Text color={Colors.AccentRed}> {' '} Please check API key and configuration. </Text> @@ -134,7 +134,18 @@ export const App = ({ config }: AppProps) => { /> </Box> - {isInputActive && <InputPrompt onSubmit={handleHistorySubmit} />} + {isInputActive && ( + <> + <Box> + <Text color={Colors.SubtleComment}>cwd: </Text> + <Text color={Colors.LightBlue}> + {shortenPath(config.getTargetDir(), /*maxLength*/ 70)} + </Text> + </Box> + + <InputPrompt onSubmit={handleHistorySubmit} /> + </> + )} <Footer queryLength={query.length} /> <ITermDetectionWarning /> diff --git a/packages/cli/src/ui/colors.ts b/packages/cli/src/ui/colors.ts new file mode 100644 index 00000000..be8dac19 --- /dev/null +++ b/packages/cli/src/ui/colors.ts @@ -0,0 +1,12 @@ +export const Colors = { + Background: '#1E1E2E', + Foreground: 'white', + LightBlue: '#CDD6F4', + AccentBlue: '#89B4FA', + AccentPurple: '#CBA6F7', + AccentCyan: '#89DCEB', + AccentGreen: '#A6E3A1', + AccentYellow: '#F9E2AF', + AccentRed: '#F38BA8', + SubtleComment: '#6C7086', +}; diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx index 45167ab3..3b4e197b 100644 --- a/packages/cli/src/ui/components/Footer.tsx +++ b/packages/cli/src/ui/components/Footer.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { Box, Text } from 'ink'; +import { Colors } from '../colors.js'; interface FooterProps { queryLength: number; @@ -14,8 +15,10 @@ interface FooterProps { export const Footer: React.FC<FooterProps> = ({ queryLength }) => ( <Box marginTop={1} justifyContent="space-between"> <Box minWidth={15}> - <Text color="gray">{queryLength === 0 ? '? for shortcuts' : ''}</Text> + <Text color={Colors.SubtleComment}> + {queryLength === 0 ? '? for shortcuts' : ''} + </Text> </Box> - <Text color="blue">Gemini</Text> + <Text color={Colors.AccentBlue}>Gemini</Text> </Box> ); diff --git a/packages/cli/src/ui/components/Header.tsx b/packages/cli/src/ui/components/Header.tsx index 62649996..8861389b 100644 --- a/packages/cli/src/ui/components/Header.tsx +++ b/packages/cli/src/ui/components/Header.tsx @@ -6,37 +6,32 @@ import React from 'react'; import { Box, Text } from 'ink'; -import { UI_WIDTH, BOX_PADDING_X } from '../constants.js'; -import { shortenPath } from '@gemini-code/server'; +import Gradient from 'ink-gradient'; +import { Tips } from './Tips.js'; -interface HeaderProps { - cwd: string; -} +const gradientColors = ['#4796E4', '#847ACE', '#C3677F']; -export const Header: React.FC<HeaderProps> = ({ cwd }) => ( +export const Header: React.FC = () => ( <> - {/* Static Header Art */} - <Box marginBottom={1}> - <Text color="blue">{` - ______ ________ ____ ____ _____ ____ _____ _____ - .' ___ ||_ __ ||_ \\ / _||_ _||_ \\|_ _||_ _| -/ .' \\_| | |_ \\_| | \\/ | | | | \\ | | | | -| | ____ | _| _ | |\\ /| | | | | |\\ \\| | | | -\\ \`.___] |_| |__/ | _| |_\\/_| |_ _| |_ _| |_\\ |_ _| |_ - \`._____.'|________||_____||_____||_____||_____|\\____||_____|`}</Text> - </Box> - {/* CWD Display */} - <Box - borderStyle="round" - borderColor="blue" - paddingX={BOX_PADDING_X} - flexDirection="column" - marginBottom={1} - width={UI_WIDTH} - > - <Box paddingLeft={2}> - <Text color="gray">cwd: {shortenPath(cwd, /*maxLength*/ 70)}</Text> - </Box> + <Box marginBottom={1} alignItems="flex-start"> + <Gradient colors={gradientColors}> + <Text>{` + ██████╗ ███████╗███╗ ███╗██╗███╗ ██╗██╗ +██╔════╝ ██╔════╝████╗ ████║██║████╗ ██║██║ +██║ ███╗█████╗ ██╔████╔██║██║██╔██╗ ██║██║ +██║ ██║██╔══╝ ██║╚██╔╝██║██║██║╚██╗██║██║ +╚██████╔╝███████╗██║ ╚═╝ ██║██║██║ ╚████║██║ + ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝╚═╝ + + ██████╗ ██████╗ ██████╗ ███████╗ +██╔════╝██╔═══██╗██╔══██╗██╔════╝ +██║ ██║ ██║██║ ██║█████╗ +██║ ██║ ██║██║ ██║██╔══╝ +╚██████╗╚██████╔╝██████╔╝███████╗ + ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ +`}</Text> + </Gradient> </Box> + <Tips /> </> ); diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx index 86e760ee..b5c3cc7d 100644 --- a/packages/cli/src/ui/components/InputPrompt.tsx +++ b/packages/cli/src/ui/components/InputPrompt.tsx @@ -5,8 +5,9 @@ */ import React from 'react'; -import { Box, useInput, useFocus } from 'ink'; +import { Text, Box, useInput, useFocus } from 'ink'; import TextInput from 'ink-text-input'; +import { Colors } from '../colors.js'; interface InputPromptProps { onSubmit: (value: string) => void; @@ -29,19 +30,18 @@ export const InputPrompt: React.FC<InputPromptProps> = ({ onSubmit }) => { ); return ( - <Box - borderStyle="round" - borderColor={isFocused ? 'blue' : 'gray'} - paddingX={1} - > - <TextInput - value={value} - onChange={setValue} - placeholder="Enter your message or use tools..." - onSubmit={() => { - /* Empty to prevent double submission */ - }} - /> + <Box borderStyle="round" borderColor={Colors.AccentBlue} paddingX={1}> + <Text color={Colors.AccentPurple}>> </Text> + <Box flexGrow={1}> + <TextInput + value={value} + onChange={setValue} + placeholder="Enter your message or use tools..." + onSubmit={() => { + /* Empty to prevent double submission */ + }} + /> + </Box> </Box> ); }; diff --git a/packages/cli/src/ui/components/LoadingIndicator.tsx b/packages/cli/src/ui/components/LoadingIndicator.tsx index be7f0fdd..ca5fb5de 100644 --- a/packages/cli/src/ui/components/LoadingIndicator.tsx +++ b/packages/cli/src/ui/components/LoadingIndicator.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { Box, Text } from 'ink'; import Spinner from 'ink-spinner'; +import { Colors } from '../colors.js'; interface LoadingIndicatorProps { isLoading: boolean; @@ -28,11 +29,11 @@ export const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({ <Box marginRight={1}> <Spinner type="dots" /> </Box> - <Text color="cyan"> + <Text color={Colors.AccentPurple}> {currentLoadingPhrase} ({elapsedTime}s) </Text> <Box flexGrow={1}>{/* Spacer */}</Box> - <Text color="gray">(ESC to cancel)</Text> + <Text color={Colors.SubtleComment}>(ESC to cancel)</Text> </Box> ); }; diff --git a/packages/cli/src/ui/components/Tips.tsx b/packages/cli/src/ui/components/Tips.tsx index bb4aa5e6..21d95966 100644 --- a/packages/cli/src/ui/components/Tips.tsx +++ b/packages/cli/src/ui/components/Tips.tsx @@ -6,19 +6,28 @@ import React from 'react'; import { Box, Text } from 'ink'; -import { UI_WIDTH } from '../constants.js'; +import { Colors } from '../colors.js'; export const Tips: React.FC = () => ( - <Box flexDirection="column" marginBottom={1} width={UI_WIDTH}> - <Text>Tips for getting started:</Text> - <Text> - 1. <Text bold>/help</Text> for more information. + <Box flexDirection="column" marginBottom={1}> + <Text color={Colors.Foreground}>Tips for getting started:</Text> + <Text color={Colors.Foreground}> + 1.{' '} + <Text bold color={Colors.AccentPurple}> + /help + </Text>{' '} + for more information. </Text> - <Text> - 2. <Text bold>/init</Text> to create a GEMINI.md for instructions & - context. + <Text color={Colors.Foreground}> + 2.{' '} + <Text bold color={Colors.AccentPurple}> + /init + </Text>{' '} + to create a GEMINI.md for instructions & context. </Text> - <Text>3. Ask coding questions, edit code or run commands.</Text> - <Text>4. Be specific for the best results.</Text> + <Text color={Colors.Foreground}> + 3. Ask coding questions, edit code or run commands. + </Text> + <Text color={Colors.Foreground}>4. Be specific for the best results.</Text> </Box> ); diff --git a/packages/cli/src/ui/components/messages/DiffRenderer.tsx b/packages/cli/src/ui/components/messages/DiffRenderer.tsx index b16a2561..01cc4938 100644 --- a/packages/cli/src/ui/components/messages/DiffRenderer.tsx +++ b/packages/cli/src/ui/components/messages/DiffRenderer.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { Box, Text } from 'ink'; +import { Colors } from '../../colors.js'; interface DiffLine { type: 'add' | 'del' | 'context' | 'hunk' | 'other'; @@ -96,7 +97,7 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({ tabWidth = DEFAULT_TAB_WIDTH, }) => { if (!diffContent || typeof diffContent !== 'string') { - return <Text color="yellow">No diff content.</Text>; + return <Text color={Colors.AccentYellow}>No diff content.</Text>; } const parsedLines = parseDiffWithLineNumbers(diffContent); @@ -114,7 +115,7 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({ if (displayableLines.length === 0) { return ( - <Box borderStyle="round" borderColor="gray" padding={1}> + <Box borderStyle="round" borderColor={Colors.SubtleComment} padding={1}> <Text dimColor>No changes detected.</Text> </Box> ); @@ -137,7 +138,11 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({ // --- End Modification --- return ( - <Box borderStyle="round" borderColor="gray" flexDirection="column"> + <Box + borderStyle="round" + borderColor={Colors.SubtleComment} + flexDirection="column" + > {/* Iterate over the lines that should be displayed (already normalized) */} {displayableLines.map((line, index) => { const key = `diff-line-${index}`; @@ -165,7 +170,6 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({ break; default: throw new Error(`Unknown line type: ${line.type}`); - break; } // Render the line content *after* stripping the calculated *minimum* baseIndentation. @@ -175,7 +179,7 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({ return ( // Using your original rendering structure <Box key={key} flexDirection="row"> - <Text color="gray">{gutterNumStr} </Text> + <Text color={Colors.SubtleComment}>{gutterNumStr} </Text> <Text color={color} dimColor={dim}> {prefixSymbol}{' '} </Text> diff --git a/packages/cli/src/ui/components/messages/ErrorMessage.tsx b/packages/cli/src/ui/components/messages/ErrorMessage.tsx index fc770dc0..22d82465 100644 --- a/packages/cli/src/ui/components/messages/ErrorMessage.tsx +++ b/packages/cli/src/ui/components/messages/ErrorMessage.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { Text, Box } from 'ink'; +import { Colors } from '../../colors.js'; interface ErrorMessageProps { text: string; @@ -18,10 +19,10 @@ export const ErrorMessage: React.FC<ErrorMessageProps> = ({ text }) => { return ( <Box flexDirection="row"> <Box width={prefixWidth}> - <Text color="red">{prefix}</Text> + <Text color={Colors.AccentRed}>{prefix}</Text> </Box> <Box flexGrow={1}> - <Text wrap="wrap" color="red"> + <Text wrap="wrap" color={Colors.AccentRed}> {text} </Text> </Box> diff --git a/packages/cli/src/ui/components/messages/GeminiMessage.tsx b/packages/cli/src/ui/components/messages/GeminiMessage.tsx index 08f6cc68..3319dd63 100644 --- a/packages/cli/src/ui/components/messages/GeminiMessage.tsx +++ b/packages/cli/src/ui/components/messages/GeminiMessage.tsx @@ -7,6 +7,7 @@ import React from 'react'; import { Text, Box } from 'ink'; import { MarkdownRenderer } from '../../utils/MarkdownRenderer.js'; +import { Colors } from '../../colors.js'; interface GeminiMessageProps { text: string; @@ -28,7 +29,7 @@ export const GeminiMessage: React.FC<GeminiMessageProps> = ({ text }) => { return ( <Box flexDirection="row"> <Box width={prefixWidth}> - <Text color="blue">{prefix}</Text> + <Text color={Colors.AccentPurple}>{prefix}</Text> </Box> <Box flexGrow={1}></Box> </Box> @@ -38,7 +39,7 @@ export const GeminiMessage: React.FC<GeminiMessageProps> = ({ text }) => { return ( <Box flexDirection="row"> <Box width={prefixWidth}> - <Text color="blue">{prefix}</Text> + <Text color={Colors.AccentPurple}>{prefix}</Text> </Box> <Box flexGrow={1} flexDirection="column"> {renderedBlocks} diff --git a/packages/cli/src/ui/components/messages/InfoMessage.tsx b/packages/cli/src/ui/components/messages/InfoMessage.tsx index 95f49522..b30e4473 100644 --- a/packages/cli/src/ui/components/messages/InfoMessage.tsx +++ b/packages/cli/src/ui/components/messages/InfoMessage.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { Text, Box } from 'ink'; +import { Colors } from '../../colors.js'; interface InfoMessageProps { text: string; @@ -18,10 +19,10 @@ export const InfoMessage: React.FC<InfoMessageProps> = ({ text }) => { return ( <Box flexDirection="row"> <Box width={prefixWidth}> - <Text color="yellow">{prefix}</Text> + <Text color={Colors.AccentYellow}>{prefix}</Text> </Box> <Box flexGrow={1}> - <Text wrap="wrap" color="yellow"> + <Text wrap="wrap" color={Colors.AccentYellow}> {text} </Text> </Box> diff --git a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx index 32a7dc1d..ee0b7ef7 100644 --- a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx @@ -16,6 +16,7 @@ import { import { PartListUnion } from '@google/genai'; import { DiffRenderer } from './DiffRenderer.js'; import { UI_WIDTH } from '../../constants.js'; +import { Colors } from '../../colors.js'; export interface ToolConfirmationMessageProps { confirmationDetails: ToolCallConfirmationDetails; @@ -74,7 +75,9 @@ export const ToolConfirmationMessage: React.FC< confirmationDetails as ToolExecuteConfirmationDetails; // For execution, we still need context display and description - const commandDisplay = <Text color="cyan">{executionProps.command}</Text>; + const commandDisplay = ( + <Text color={Colors.AccentCyan}>{executionProps.command}</Text> + ); // Combine command and description into bodyContent for layout consistency bodyContent = ( diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx index 0662e333..448ed4c5 100644 --- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx @@ -10,6 +10,7 @@ import { IndividualToolCallDisplay, ToolCallStatus } from '../../types.js'; import { ToolMessage } from './ToolMessage.js'; import { PartListUnion } from '@google/genai'; import { ToolConfirmationMessage } from './ToolConfirmationMessage.js'; +import { Colors } from '../../colors.js'; interface ToolGroupMessageProps { toolCalls: IndividualToolCallDisplay[]; @@ -22,7 +23,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({ onSubmit, }) => { const hasPending = toolCalls.some((t) => t.status === ToolCallStatus.Pending); - const borderColor = hasPending ? 'yellow' : 'blue'; + const borderColor = hasPending ? Colors.AccentYellow : Colors.AccentBlue; return ( <Box flexDirection="column" borderStyle="round" borderColor={borderColor}> diff --git a/packages/cli/src/ui/components/messages/ToolMessage.tsx b/packages/cli/src/ui/components/messages/ToolMessage.tsx index 9c1dd36b..372d5ffe 100644 --- a/packages/cli/src/ui/components/messages/ToolMessage.tsx +++ b/packages/cli/src/ui/components/messages/ToolMessage.tsx @@ -16,6 +16,7 @@ import { } from '../../types.js'; import { DiffRenderer } from './DiffRenderer.js'; import { FileDiff, ToolResultDisplay } from '../../../tools/tools.js'; +import { Colors } from '../../colors.js'; export const ToolMessage: React.FC<IndividualToolCallDisplay> = ({ callId, @@ -31,7 +32,7 @@ export const ToolMessage: React.FC<IndividualToolCallDisplay> = ({ | undefined; const typedResultDisplay = resultDisplay as ToolResultDisplay | undefined; - let color = 'gray'; + let color = Colors.SubtleComment; let prefix = ''; switch (status) { case ToolCallStatus.Pending: @@ -41,15 +42,15 @@ export const ToolMessage: React.FC<IndividualToolCallDisplay> = ({ prefix = 'Executing:'; break; case ToolCallStatus.Confirming: - color = 'yellow'; + color = Colors.AccentYellow; prefix = 'Confirm:'; break; case ToolCallStatus.Success: - color = 'green'; + color = Colors.AccentGreen; prefix = 'Success:'; break; case ToolCallStatus.Error: - color = 'red'; + color = Colors.AccentRed; prefix = 'Error:'; break; default: @@ -60,11 +61,11 @@ export const ToolMessage: React.FC<IndividualToolCallDisplay> = ({ const title = `${prefix} ${name}`; return ( - <Box key={callId} borderStyle="round" paddingX={1} flexDirection="column"> + <Box key={callId} flexDirection="column" paddingX={1}> <Box> {status === ToolCallStatus.Invoked && ( <Box marginRight={1}> - <Text color="blue"> + <Text color={Colors.AccentBlue}> <Spinner type="dots" /> </Text> </Box> @@ -91,7 +92,7 @@ export const ToolMessage: React.FC<IndividualToolCallDisplay> = ({ )} {/* Display command for execute */} {'command' in typedConfirmationDetails && ( - <Text color="yellow"> + <Text color={Colors.AccentYellow}> Command:{' '} { (typedConfirmationDetails as ToolExecuteConfirmationDetails) diff --git a/packages/cli/src/ui/components/messages/UserMessage.tsx b/packages/cli/src/ui/components/messages/UserMessage.tsx index bc9822a4..e9771b82 100644 --- a/packages/cli/src/ui/components/messages/UserMessage.tsx +++ b/packages/cli/src/ui/components/messages/UserMessage.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { Text, Box } from 'ink'; +import { Colors } from '../../colors.js'; interface UserMessageProps { text: string; @@ -18,7 +19,7 @@ export const UserMessage: React.FC<UserMessageProps> = ({ text }) => { return ( <Box flexDirection="row"> <Box width={prefixWidth}> - <Text color="gray">{prefix}</Text> + <Text color={Colors.SubtleComment}>{prefix}</Text> </Box> <Box flexGrow={1}> <Text wrap="wrap">{text}</Text> diff --git a/packages/cli/src/ui/utils/MarkdownRenderer.tsx b/packages/cli/src/ui/utils/MarkdownRenderer.tsx index d15926ee..f9e8167c 100644 --- a/packages/cli/src/ui/utils/MarkdownRenderer.tsx +++ b/packages/cli/src/ui/utils/MarkdownRenderer.tsx @@ -6,6 +6,7 @@ import React from 'react'; import { Text, Box } from 'ink'; +import { Colors } from '../colors.js'; /** * A utility class to render a subset of Markdown into Ink components. @@ -83,14 +84,14 @@ export class MarkdownRenderer { const codeMatch = fullMatch.match(/^(`+)(.+?)\1$/s); if (codeMatch && codeMatch[2]) { renderedNode = ( - <Text key={key} color="yellow"> + <Text key={key} color={Colors.AccentPurple}> {codeMatch[2]} </Text> ); } else { // Fallback for simple or non-matching cases renderedNode = ( - <Text key={key} color="yellow"> + <Text key={key} color={Colors.AccentPurple}> {fullMatch.slice(1, -1)} </Text> ); @@ -109,7 +110,7 @@ export class MarkdownRenderer { renderedNode = ( <Text key={key}> {linkText} - <Text color="blue"> ({url})</Text> + <Text color={Colors.AccentBlue}> ({url})</Text> </Text> ); } @@ -160,7 +161,7 @@ export class MarkdownRenderer { key={key} borderStyle="round" paddingX={1} - borderColor="gray" + borderColor={Colors.SubtleComment} flexDirection="column" > {lang && <Text dimColor> {lang}</Text>} @@ -281,14 +282,14 @@ export class MarkdownRenderer { switch (level /* ... (header styling as before) ... */) { case 1: headerNode = ( - <Text bold color="cyan"> + <Text bold color={Colors.AccentCyan}> {renderedHeaderText} </Text> ); break; case 2: headerNode = ( - <Text bold color="blue"> + <Text bold color={Colors.AccentBlue}> {renderedHeaderText} </Text> ); @@ -298,7 +299,7 @@ export class MarkdownRenderer { break; case 4: headerNode = ( - <Text italic color="gray"> + <Text italic color={Colors.SubtleComment}> {renderedHeaderText} </Text> ); |
