summaryrefslogtreecommitdiff
path: root/packages/cli/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/cli/src')
-rw-r--r--packages/cli/src/ui/App.tsx28
-rw-r--r--packages/cli/src/ui/commands/chatCommand.ts4
-rw-r--r--packages/cli/src/ui/components/AboutBox.tsx36
-rw-r--r--packages/cli/src/ui/components/AuthDialog.tsx22
-rw-r--r--packages/cli/src/ui/components/AuthInProgress.tsx8
-rw-r--r--packages/cli/src/ui/components/AutoAcceptIndicator.tsx8
-rw-r--r--packages/cli/src/ui/components/ConsoleSummaryDisplay.tsx6
-rw-r--r--packages/cli/src/ui/components/ContextSummaryDisplay.tsx10
-rw-r--r--packages/cli/src/ui/components/ContextUsageDisplay.tsx4
-rw-r--r--packages/cli/src/ui/components/DebugProfiler.tsx4
-rw-r--r--packages/cli/src/ui/components/DetailedMessagesDisplay.tsx19
-rw-r--r--packages/cli/src/ui/components/EditorSettingsDialog.tsx16
-rw-r--r--packages/cli/src/ui/components/FolderTrustDialog.tsx10
-rw-r--r--packages/cli/src/ui/components/Footer.tsx8
-rw-r--r--packages/cli/src/ui/components/GeminiRespondingSpinner.tsx3
-rw-r--r--packages/cli/src/ui/components/Header.test.tsx16
-rw-r--r--packages/cli/src/ui/components/Header.tsx30
-rw-r--r--packages/cli/src/ui/components/Help.tsx84
-rw-r--r--packages/cli/src/ui/components/InputPrompt.tsx9
-rw-r--r--packages/cli/src/ui/components/LoadingIndicator.tsx10
-rw-r--r--packages/cli/src/ui/components/MemoryUsageDisplay.tsx12
-rw-r--r--packages/cli/src/ui/components/ModelStatsDisplay.tsx30
-rw-r--r--packages/cli/src/ui/components/PrepareLabel.tsx6
-rw-r--r--packages/cli/src/ui/components/SettingsDialog.tsx36
-rw-r--r--packages/cli/src/ui/components/ShellConfirmationDialog.tsx18
-rw-r--r--packages/cli/src/ui/components/ShellModeIndicator.tsx6
-rw-r--r--packages/cli/src/ui/components/ShowMoreLines.tsx4
-rw-r--r--packages/cli/src/ui/components/StatsDisplay.test.tsx2
-rw-r--r--packages/cli/src/ui/components/StatsDisplay.tsx115
-rw-r--r--packages/cli/src/ui/components/SuggestionsDisplay.tsx14
-rw-r--r--packages/cli/src/ui/components/ThemeDialog.tsx37
-rw-r--r--packages/cli/src/ui/components/Tips.tsx16
-rw-r--r--packages/cli/src/ui/components/ToolStatsDisplay.tsx61
-rw-r--r--packages/cli/src/ui/components/UpdateNotification.tsx6
-rw-r--r--packages/cli/src/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap5
-rw-r--r--packages/cli/src/ui/components/__snapshots__/StatsDisplay.test.tsx.snap22
-rw-r--r--packages/cli/src/ui/components/messages/CompressionMessage.tsx6
-rw-r--r--packages/cli/src/ui/components/messages/DiffRenderer.tsx47
-rw-r--r--packages/cli/src/ui/components/messages/ErrorMessage.tsx6
-rw-r--r--packages/cli/src/ui/components/messages/GeminiMessage.tsx4
-rw-r--r--packages/cli/src/ui/components/messages/InfoMessage.tsx6
-rw-r--r--packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx27
-rw-r--r--packages/cli/src/ui/components/messages/ToolGroupMessage.tsx4
-rw-r--r--packages/cli/src/ui/components/messages/ToolMessage.tsx27
-rw-r--r--packages/cli/src/ui/components/messages/UserMessage.tsx6
-rw-r--r--packages/cli/src/ui/components/messages/UserShellMessage.tsx6
-rw-r--r--packages/cli/src/ui/components/shared/MaxSizedBox.tsx7
-rw-r--r--packages/cli/src/ui/components/shared/RadioButtonSelect.tsx32
-rw-r--r--packages/cli/src/ui/privacy/CloudFreePrivacyNotice.tsx30
-rw-r--r--packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.tsx20
-rw-r--r--packages/cli/src/ui/privacy/GeminiPrivacyNotice.tsx34
-rw-r--r--packages/cli/src/ui/themes/no-color.ts2
-rw-r--r--packages/cli/src/ui/themes/semantic-tokens.ts8
-rw-r--r--packages/cli/src/ui/themes/theme.ts4
-rw-r--r--packages/cli/src/ui/utils/CodeColorizer.tsx5
-rw-r--r--packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx38
-rw-r--r--packages/cli/src/ui/utils/MarkdownDisplay.tsx28
-rw-r--r--packages/cli/src/ui/utils/TableRenderer.tsx10
-rw-r--r--packages/cli/src/ui/utils/displayUtils.test.ts18
-rw-r--r--packages/cli/src/ui/utils/displayUtils.ts8
60 files changed, 502 insertions, 606 deletions
diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx
index ca391e83..9773971b 100644
--- a/packages/cli/src/ui/App.tsx
+++ b/packages/cli/src/ui/App.tsx
@@ -38,7 +38,7 @@ import { EditorSettingsDialog } from './components/EditorSettingsDialog.js';
import { FolderTrustDialog } from './components/FolderTrustDialog.js';
import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js';
import { RadioButtonSelect } from './components/shared/RadioButtonSelect.js';
-import { theme } from './semantic-colors.js';
+import { Colors } from './colors.js';
import { loadHierarchicalGeminiMemory } from '../config/config.js';
import { LoadedSettings, SettingScope } from '../config/settings.js';
import { Tips } from './components/Tips.js';
@@ -949,13 +949,13 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
{startupWarnings.length > 0 && (
<Box
borderStyle="round"
- borderColor={theme.status.warning}
+ borderColor={Colors.AccentYellow}
paddingX={1}
marginY={1}
flexDirection="column"
>
{startupWarnings.map((warning, index) => (
- <Text key={index} color={theme.status.warning}>
+ <Text key={index} color={Colors.AccentYellow}>
{warning}
</Text>
))}
@@ -991,7 +991,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
<Box flexDirection="column">
{themeError && (
<Box marginBottom={1}>
- <Text color={theme.status.error}>{themeError}</Text>
+ <Text color={Colors.AccentRed}>{themeError}</Text>
</Box>
)}
<ThemeDialog
@@ -1050,7 +1050,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
<Box flexDirection="column">
{editorError && (
<Box marginBottom={1}>
- <Text color={theme.status.error}>{editorError}</Text>
+ <Text color={Colors.AccentRed}>{editorError}</Text>
</Box>
)}
<EditorSettingsDialog
@@ -1090,20 +1090,18 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
>
<Box>
{process.env.GEMINI_SYSTEM_MD && (
- <Text color={theme.status.error}>|⌐■_■| </Text>
+ <Text color={Colors.AccentRed}>|⌐■_■| </Text>
)}
{ctrlCPressedOnce ? (
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
Press Ctrl+C again to exit.
</Text>
) : ctrlDPressedOnce ? (
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
Press Ctrl+D again to exit.
</Text>
) : showEscapePrompt ? (
- <Text color={theme.text.secondary}>
- Press Esc again to clear.
- </Text>
+ <Text color={Colors.Gray}>Press Esc again to clear.</Text>
) : (
<ContextSummaryDisplay
ideContext={ideContextState}
@@ -1166,7 +1164,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
{initError && streamingState !== StreamingState.Responding && (
<Box
borderStyle="round"
- borderColor={theme.status.error}
+ borderColor={Colors.AccentRed}
paddingX={1}
marginBottom={1}
>
@@ -1174,7 +1172,7 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
(item) =>
item.type === 'error' && item.text?.includes(initError),
)?.text ? (
- <Text color={theme.status.error}>
+ <Text color={Colors.AccentRed}>
{
history.find(
(item) =>
@@ -1184,10 +1182,10 @@ const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
</Text>
) : (
<>
- <Text color={theme.status.error}>
+ <Text color={Colors.AccentRed}>
Initialization Error: {initError}
</Text>
- <Text color={theme.status.error}>
+ <Text color={Colors.AccentRed}>
{' '}
Please check API key and configuration.
</Text>
diff --git a/packages/cli/src/ui/commands/chatCommand.ts b/packages/cli/src/ui/commands/chatCommand.ts
index b614682e..1c9029a9 100644
--- a/packages/cli/src/ui/commands/chatCommand.ts
+++ b/packages/cli/src/ui/commands/chatCommand.ts
@@ -7,7 +7,7 @@
import * as fsPromises from 'fs/promises';
import React from 'react';
import { Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import {
CommandContext,
SlashCommand,
@@ -124,7 +124,7 @@ const saveCommand: SlashCommand = {
Text,
null,
'A checkpoint with the tag ',
- React.createElement(Text, { color: theme.text.accent }, tag),
+ React.createElement(Text, { color: Colors.AccentPurple }, tag),
' already exists. Do you want to overwrite it?',
),
originalInvocation: {
diff --git a/packages/cli/src/ui/components/AboutBox.tsx b/packages/cli/src/ui/components/AboutBox.tsx
index 54bcbc3c..a0954576 100644
--- a/packages/cli/src/ui/components/AboutBox.tsx
+++ b/packages/cli/src/ui/components/AboutBox.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { GIT_COMMIT_INFO } from '../../generated/git-commit.js';
interface AboutBoxProps {
@@ -30,77 +30,77 @@ export const AboutBox: React.FC<AboutBoxProps> = ({
}) => (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
padding={1}
marginY={1}
width="100%"
>
<Box marginBottom={1}>
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
About Gemini CLI
</Text>
</Box>
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
CLI Version
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>{cliVersion}</Text>
+ <Text>{cliVersion}</Text>
</Box>
</Box>
{GIT_COMMIT_INFO && !['N/A'].includes(GIT_COMMIT_INFO) && (
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
Git Commit
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>{GIT_COMMIT_INFO}</Text>
+ <Text>{GIT_COMMIT_INFO}</Text>
</Box>
</Box>
)}
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
Model
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>{modelVersion}</Text>
+ <Text>{modelVersion}</Text>
</Box>
</Box>
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
Sandbox
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>{sandboxEnv}</Text>
+ <Text>{sandboxEnv}</Text>
</Box>
</Box>
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
OS
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>{osVersion}</Text>
+ <Text>{osVersion}</Text>
</Box>
</Box>
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
Auth Method
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>
+ <Text>
{selectedAuthType.startsWith('oauth') ? 'OAuth' : selectedAuthType}
</Text>
</Box>
@@ -108,19 +108,19 @@ export const AboutBox: React.FC<AboutBoxProps> = ({
{gcpProject && (
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
GCP Project
</Text>
</Box>
<Box>
- <Text color={theme.text.primary}>{gcpProject}</Text>
+ <Text>{gcpProject}</Text>
</Box>
</Box>
)}
{ideClient && (
<Box flexDirection="row">
<Box width="35%">
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.LightBlue}>
IDE Client
</Text>
</Box>
diff --git a/packages/cli/src/ui/components/AuthDialog.tsx b/packages/cli/src/ui/components/AuthDialog.tsx
index b9215988..c353727c 100644
--- a/packages/cli/src/ui/components/AuthDialog.tsx
+++ b/packages/cli/src/ui/components/AuthDialog.tsx
@@ -6,7 +6,7 @@
import React, { useState } from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { RadioButtonSelect } from './shared/RadioButtonSelect.js';
import { LoadedSettings, SettingScope } from '../../config/settings.js';
import { AuthType } from '@google/gemini-cli-core';
@@ -133,18 +133,14 @@ export function AuthDialog({
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
padding={1}
width="100%"
>
- <Text bold color={theme.text.primary}>
- Get started
- </Text>
+ <Text bold>Get started</Text>
<Box marginTop={1}>
- <Text color={theme.text.primary}>
- How would you like to authenticate for this project?
- </Text>
+ <Text>How would you like to authenticate for this project?</Text>
</Box>
<Box marginTop={1}>
<RadioButtonSelect
@@ -155,19 +151,17 @@ export function AuthDialog({
</Box>
{errorMessage && (
<Box marginTop={1}>
- <Text color={theme.status.error}>{errorMessage}</Text>
+ <Text color={Colors.AccentRed}>{errorMessage}</Text>
</Box>
)}
<Box marginTop={1}>
- <Text color={theme.text.secondary}>(Use Enter to select)</Text>
+ <Text color={Colors.Gray}>(Use Enter to select)</Text>
</Box>
<Box marginTop={1}>
- <Text color={theme.text.primary}>
- Terms of Services and Privacy Notice for Gemini CLI
- </Text>
+ <Text>Terms of Services and Privacy Notice for Gemini CLI</Text>
</Box>
<Box marginTop={1}>
- <Text color={theme.text.link}>
+ <Text color={Colors.AccentBlue}>
{
'https://github.com/google-gemini/gemini-cli/blob/main/docs/tos-privacy.md'
}
diff --git a/packages/cli/src/ui/components/AuthInProgress.tsx b/packages/cli/src/ui/components/AuthInProgress.tsx
index 81f98ad5..53377c7c 100644
--- a/packages/cli/src/ui/components/AuthInProgress.tsx
+++ b/packages/cli/src/ui/components/AuthInProgress.tsx
@@ -7,7 +7,7 @@
import React, { useState, useEffect } from 'react';
import { Box, Text } from 'ink';
import Spinner from 'ink-spinner';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
interface AuthInProgressProps {
@@ -40,18 +40,18 @@ export function AuthInProgress({
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
padding={1}
width="100%"
>
{timedOut ? (
- <Text color={theme.status.error}>
+ <Text color={Colors.AccentRed}>
Authentication timed out. Please try again.
</Text>
) : (
<Box>
- <Text color={theme.text.primary}>
+ <Text>
<Spinner type="dots" /> Waiting for auth... (Press ESC or CTRL+C to
cancel)
</Text>
diff --git a/packages/cli/src/ui/components/AutoAcceptIndicator.tsx b/packages/cli/src/ui/components/AutoAcceptIndicator.tsx
index a98f036c..f8d50fd0 100644
--- a/packages/cli/src/ui/components/AutoAcceptIndicator.tsx
+++ b/packages/cli/src/ui/components/AutoAcceptIndicator.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { ApprovalMode } from '@google/gemini-cli-core';
interface AutoAcceptIndicatorProps {
@@ -22,12 +22,12 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
switch (approvalMode) {
case ApprovalMode.AUTO_EDIT:
- textColor = theme.status.success;
+ textColor = Colors.AccentGreen;
textContent = 'accepting edits';
subText = ' (shift + tab to toggle)';
break;
case ApprovalMode.YOLO:
- textColor = theme.status.error;
+ textColor = Colors.AccentRed;
textContent = 'YOLO mode';
subText = ' (ctrl + y to toggle)';
break;
@@ -40,7 +40,7 @@ export const AutoAcceptIndicator: React.FC<AutoAcceptIndicatorProps> = ({
<Box>
<Text color={textColor}>
{textContent}
- {subText && <Text color={theme.text.secondary}>{subText}</Text>}
+ {subText && <Text color={Colors.Gray}>{subText}</Text>}
</Text>
</Box>
);
diff --git a/packages/cli/src/ui/components/ConsoleSummaryDisplay.tsx b/packages/cli/src/ui/components/ConsoleSummaryDisplay.tsx
index e992403e..c79cc096 100644
--- a/packages/cli/src/ui/components/ConsoleSummaryDisplay.tsx
+++ b/packages/cli/src/ui/components/ConsoleSummaryDisplay.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
interface ConsoleSummaryDisplayProps {
errorCount: number;
@@ -25,9 +25,9 @@ export const ConsoleSummaryDisplay: React.FC<ConsoleSummaryDisplayProps> = ({
return (
<Box>
{errorCount > 0 && (
- <Text color={theme.status.error}>
+ <Text color={Colors.AccentRed}>
{errorIcon} {errorCount} error{errorCount > 1 ? 's' : ''}{' '}
- <Text color={theme.text.secondary}>(ctrl+o for details)</Text>
+ <Text color={Colors.Gray}>(ctrl+o for details)</Text>
</Text>
)}
</Box>
diff --git a/packages/cli/src/ui/components/ContextSummaryDisplay.tsx b/packages/cli/src/ui/components/ContextSummaryDisplay.tsx
index ae909a84..0c946385 100644
--- a/packages/cli/src/ui/components/ContextSummaryDisplay.tsx
+++ b/packages/cli/src/ui/components/ContextSummaryDisplay.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { type IdeContext, type MCPServerConfig } from '@google/gemini-cli-core';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
import { isNarrowWidth } from '../utils/isNarrowWidth.js';
@@ -99,9 +99,9 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
if (isNarrow) {
return (
<Box flexDirection="column">
- <Text color={theme.text.secondary}>Using:</Text>
+ <Text color={Colors.Gray}>Using:</Text>
{summaryParts.map((part, index) => (
- <Text key={index} color={theme.text.secondary}>
+ <Text key={index} color={Colors.Gray}>
{' '}- {part}
</Text>
))}
@@ -111,9 +111,7 @@ export const ContextSummaryDisplay: React.FC<ContextSummaryDisplayProps> = ({
return (
<Box>
- <Text color={theme.text.secondary}>
- Using: {summaryParts.join(' | ')}
- </Text>
+ <Text color={Colors.Gray}>Using: {summaryParts.join(' | ')}</Text>
</Box>
);
};
diff --git a/packages/cli/src/ui/components/ContextUsageDisplay.tsx b/packages/cli/src/ui/components/ContextUsageDisplay.tsx
index d7d8c063..037be333 100644
--- a/packages/cli/src/ui/components/ContextUsageDisplay.tsx
+++ b/packages/cli/src/ui/components/ContextUsageDisplay.tsx
@@ -5,7 +5,7 @@
*/
import { Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { tokenLimit } from '@google/gemini-cli-core';
export const ContextUsageDisplay = ({
@@ -18,7 +18,7 @@ export const ContextUsageDisplay = ({
const percentage = promptTokenCount / tokenLimit(model);
return (
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
({((1 - percentage) * 100).toFixed(0)}% context left)
</Text>
);
diff --git a/packages/cli/src/ui/components/DebugProfiler.tsx b/packages/cli/src/ui/components/DebugProfiler.tsx
index 4a4d6b4c..22c16cfb 100644
--- a/packages/cli/src/ui/components/DebugProfiler.tsx
+++ b/packages/cli/src/ui/components/DebugProfiler.tsx
@@ -6,7 +6,7 @@
import { Text } from 'ink';
import { useEffect, useRef, useState } from 'react';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
export const DebugProfiler = () => {
@@ -31,6 +31,6 @@ export const DebugProfiler = () => {
}
return (
- <Text color={theme.status.warning}>Renders: {numRenders.current} </Text>
+ <Text color={Colors.AccentYellow}>Renders: {numRenders.current} </Text>
);
};
diff --git a/packages/cli/src/ui/components/DetailedMessagesDisplay.tsx b/packages/cli/src/ui/components/DetailedMessagesDisplay.tsx
index 055c87b9..2bc5d392 100644
--- a/packages/cli/src/ui/components/DetailedMessagesDisplay.tsx
+++ b/packages/cli/src/ui/components/DetailedMessagesDisplay.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { ConsoleMessageItem } from '../types.js';
import { MaxSizedBox } from './shared/MaxSizedBox.js';
@@ -31,32 +31,31 @@ export const DetailedMessagesDisplay: React.FC<
flexDirection="column"
marginTop={1}
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
paddingX={1}
width={width}
>
<Box marginBottom={1}>
- <Text bold color={theme.text.primary}>
- Debug Console{' '}
- <Text color={theme.text.secondary}>(ctrl+o to close)</Text>
+ <Text bold color={Colors.Foreground}>
+ Debug Console <Text color={Colors.Gray}>(ctrl+o to close)</Text>
</Text>
</Box>
<MaxSizedBox maxHeight={maxHeight} maxWidth={width - borderAndPadding}>
{messages.map((msg, index) => {
- let textColor = theme.text.primary;
+ let textColor = Colors.Foreground;
let icon = '\u2139'; // Information source (ℹ)
switch (msg.type) {
case 'warn':
- textColor = theme.status.warning;
+ textColor = Colors.AccentYellow;
icon = '\u26A0'; // Warning sign (⚠)
break;
case 'error':
- textColor = theme.status.error;
+ textColor = Colors.AccentRed;
icon = '\u2716'; // Heavy multiplication x (✖)
break;
case 'debug':
- textColor = theme.text.secondary;
+ textColor = Colors.Gray; // Or Colors.Gray
icon = '\u1F50D'; // Left-pointing magnifying glass (????)
break;
case 'log':
@@ -71,7 +70,7 @@ export const DetailedMessagesDisplay: React.FC<
<Text color={textColor} wrap="wrap">
{msg.content}
{msg.count && msg.count > 1 && (
- <Text color={theme.text.secondary}> (x{msg.count})</Text>
+ <Text color={Colors.Gray}> (x{msg.count})</Text>
)}
</Text>
</Box>
diff --git a/packages/cli/src/ui/components/EditorSettingsDialog.tsx b/packages/cli/src/ui/components/EditorSettingsDialog.tsx
index 7b58262f..3c4c518b 100644
--- a/packages/cli/src/ui/components/EditorSettingsDialog.tsx
+++ b/packages/cli/src/ui/components/EditorSettingsDialog.tsx
@@ -6,7 +6,7 @@
import React, { useState } from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import {
EDITOR_DISPLAY_NAMES,
editorSettingsManager,
@@ -103,7 +103,7 @@ export function EditorSettingsDialog({
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="row"
padding={1}
width="100%"
@@ -111,7 +111,7 @@ export function EditorSettingsDialog({
<Box flexDirection="column" width="45%" paddingRight={2}>
<Text bold={focusedSection === 'editor'}>
{focusedSection === 'editor' ? '> ' : ' '}Select Editor{' '}
- <Text color={theme.text.secondary}>{otherScopeModifiedMessage}</Text>
+ <Text color={Colors.Gray}>{otherScopeModifiedMessage}</Text>
</Text>
<RadioButtonSelect
items={editorItems.map((item) => ({
@@ -138,7 +138,7 @@ export function EditorSettingsDialog({
</Box>
<Box marginTop={1}>
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
(Use Enter to select, Tab to change focus)
</Text>
</Box>
@@ -147,17 +147,17 @@ export function EditorSettingsDialog({
<Box flexDirection="column" width="55%" paddingLeft={2}>
<Text bold>Editor Preference</Text>
<Box flexDirection="column" gap={1} marginTop={1}>
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
These editors are currently supported. Please note that some editors
cannot be used in sandbox mode.
</Text>
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
Your preferred editor is:{' '}
<Text
color={
mergedEditorName === 'None'
- ? theme.status.error
- : theme.text.accent
+ ? Colors.AccentRed
+ : Colors.AccentCyan
}
bold
>
diff --git a/packages/cli/src/ui/components/FolderTrustDialog.tsx b/packages/cli/src/ui/components/FolderTrustDialog.tsx
index 987b92e9..30f3ff52 100644
--- a/packages/cli/src/ui/components/FolderTrustDialog.tsx
+++ b/packages/cli/src/ui/components/FolderTrustDialog.tsx
@@ -6,7 +6,7 @@
import { Box, Text } from 'ink';
import React from 'react';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import {
RadioButtonSelect,
RadioSelectItem,
@@ -54,16 +54,14 @@ export const FolderTrustDialog: React.FC<FolderTrustDialogProps> = ({
<Box
flexDirection="column"
borderStyle="round"
- borderColor={theme.status.warning}
+ borderColor={Colors.AccentYellow}
padding={1}
width="100%"
marginLeft={1}
>
<Box flexDirection="column" marginBottom={1}>
- <Text bold color={theme.text.primary}>
- Do you trust this folder?
- </Text>
- <Text color={theme.text.primary}>
+ <Text bold>Do you trust this folder?</Text>
+ <Text>
Trusting a folder allows Gemini to execute commands it suggests. This
is a security feature to prevent accidental execution in untrusted
directories.
diff --git a/packages/cli/src/ui/components/Footer.tsx b/packages/cli/src/ui/components/Footer.tsx
index 12dee691..09b94ec1 100644
--- a/packages/cli/src/ui/components/Footer.tsx
+++ b/packages/cli/src/ui/components/Footer.tsx
@@ -72,7 +72,7 @@ export const Footer: React.FC<FooterProps> = ({
{vimMode && <Text color={theme.text.secondary}>[{vimMode}] </Text>}
{nightly ? (
<Gradient colors={theme.ui.gradient}>
- <Text color={theme.text.primary}>
+ <Text>
{displayPath}
{branchName && <Text> ({branchName}*)</Text>}
</Text>
@@ -132,8 +132,8 @@ export const Footer: React.FC<FooterProps> = ({
/>
</Text>
{corgiMode && (
- <Text color={theme.text.primary}>
- <Text color={theme.text.secondary}>| </Text>
+ <Text>
+ <Text color={theme.ui.symbol}>| </Text>
<Text color={theme.status.error}>▼</Text>
<Text color={theme.text.primary}>(´</Text>
<Text color={theme.status.error}>ᴥ</Text>
@@ -143,7 +143,7 @@ export const Footer: React.FC<FooterProps> = ({
)}
{!showErrorDetails && errorCount > 0 && (
<Box>
- <Text color={theme.text.secondary}>| </Text>
+ <Text color={theme.ui.symbol}>| </Text>
<ConsoleSummaryDisplay errorCount={errorCount} />
</Box>
)}
diff --git a/packages/cli/src/ui/components/GeminiRespondingSpinner.tsx b/packages/cli/src/ui/components/GeminiRespondingSpinner.tsx
index 8bafbdcc..97e10cb3 100644
--- a/packages/cli/src/ui/components/GeminiRespondingSpinner.tsx
+++ b/packages/cli/src/ui/components/GeminiRespondingSpinner.tsx
@@ -10,7 +10,6 @@ import Spinner from 'ink-spinner';
import type { SpinnerName } from 'cli-spinners';
import { useStreamingContext } from '../contexts/StreamingContext.js';
import { StreamingState } from '../types.js';
-import { theme } from '../semantic-colors.js';
interface GeminiRespondingSpinnerProps {
/**
@@ -29,7 +28,7 @@ export const GeminiRespondingSpinner: React.FC<
if (streamingState === StreamingState.Responding) {
return <Spinner type={spinnerType} />;
} else if (nonRespondingDisplay) {
- return <Text color={theme.text.primary}>{nonRespondingDisplay}</Text>;
+ return <Text>{nonRespondingDisplay}</Text>;
}
return null;
};
diff --git a/packages/cli/src/ui/components/Header.test.tsx b/packages/cli/src/ui/components/Header.test.tsx
index a1b694a6..95ed3f07 100644
--- a/packages/cli/src/ui/components/Header.test.tsx
+++ b/packages/cli/src/ui/components/Header.test.tsx
@@ -5,7 +5,7 @@
*/
import { render } from 'ink-testing-library';
-import { describe, it, expect, vi } from 'vitest';
+import { describe, it, expect, vi, beforeEach } from 'vitest';
import { Header } from './Header.js';
import * as useTerminalSize from '../hooks/useTerminalSize.js';
import { longAsciiLogo } from './AsciiArt.js';
@@ -13,13 +13,15 @@ import { longAsciiLogo } from './AsciiArt.js';
vi.mock('../hooks/useTerminalSize.js');
describe('<Header />', () => {
+ beforeEach(() => {});
+
it('renders the long logo on a wide terminal', () => {
vi.spyOn(useTerminalSize, 'useTerminalSize').mockReturnValue({
columns: 120,
rows: 20,
});
const { lastFrame } = render(<Header version="1.0.0" nightly={false} />);
- expect(lastFrame()?.trim()).toContain(longAsciiLogo.trim());
+ expect(lastFrame()).toContain(longAsciiLogo);
});
it('renders custom ASCII art when provided', () => {
@@ -27,20 +29,16 @@ describe('<Header />', () => {
const { lastFrame } = render(
<Header version="1.0.0" nightly={false} customAsciiArt={customArt} />,
);
- expect(lastFrame()?.trim()).toContain(customArt);
+ expect(lastFrame()).toContain(customArt);
});
it('displays the version number when nightly is true', () => {
const { lastFrame } = render(<Header version="1.0.0" nightly={true} />);
- expect(lastFrame()?.trim()).toContain('v1.0.0');
+ expect(lastFrame()).toContain('v1.0.0');
});
it('does not display the version number when nightly is false', () => {
- vi.spyOn(useTerminalSize, 'useTerminalSize').mockReturnValue({
- columns: 40,
- rows: 20,
- });
const { lastFrame } = render(<Header version="1.0.0" nightly={false} />);
- expect(lastFrame()?.trim()).not.toContain('v1.0.0');
+ expect(lastFrame()).not.toContain('v1.0.0');
});
});
diff --git a/packages/cli/src/ui/components/Header.tsx b/packages/cli/src/ui/components/Header.tsx
index 5942e304..0894ad14 100644
--- a/packages/cli/src/ui/components/Header.tsx
+++ b/packages/cli/src/ui/components/Header.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { Box, Text } from 'ink';
import Gradient from 'ink-gradient';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { shortAsciiLogo, longAsciiLogo, tinyAsciiLogo } from './AsciiArt.js';
import { getAsciiArtWidth } from '../utils/textUtils.js';
import { useTerminalSize } from '../hooks/useTerminalSize.js';
@@ -18,16 +18,6 @@ interface HeaderProps {
nightly: boolean;
}
-const GradientText: React.FC<{ children: React.ReactNode }> = ({
- children,
-}) => {
- const textElement = <Text color={theme.text.primary}>{children}</Text>;
- if (theme.ui.gradient && theme.ui.gradient.length > 0) {
- return <Gradient colors={theme.ui.gradient}>{textElement}</Gradient>;
- }
- return textElement;
-};
-
export const Header: React.FC<HeaderProps> = ({
customAsciiArt,
version,
@@ -57,12 +47,22 @@ export const Header: React.FC<HeaderProps> = ({
flexShrink={0}
flexDirection="column"
>
- <Box>
- <GradientText>{displayTitle}</GradientText>
- </Box>
+ {Colors.GradientColors ? (
+ <Gradient colors={Colors.GradientColors}>
+ <Text>{displayTitle}</Text>
+ </Gradient>
+ ) : (
+ <Text>{displayTitle}</Text>
+ )}
{nightly && (
<Box width="100%" flexDirection="row" justifyContent="flex-end">
- <Text color={theme.text.primary}>v{version}</Text>
+ {Colors.GradientColors ? (
+ <Gradient colors={Colors.GradientColors}>
+ <Text>v{version}</Text>
+ </Gradient>
+ ) : (
+ <Text>v{version}</Text>
+ )}
</Box>
)}
</Box>
diff --git a/packages/cli/src/ui/components/Help.tsx b/packages/cli/src/ui/components/Help.tsx
index 9b6709ac..d9f7b4a8 100644
--- a/packages/cli/src/ui/components/Help.tsx
+++ b/packages/cli/src/ui/components/Help.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { SlashCommand } from '../commands/types.js';
interface Help {
@@ -17,42 +17,42 @@ export const Help: React.FC<Help> = ({ commands }) => (
<Box
flexDirection="column"
marginBottom={1}
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
borderStyle="round"
padding={1}
>
{/* Basics */}
- <Text bold color={theme.text.primary}>
+ <Text bold color={Colors.Foreground}>
Basics:
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Add context
</Text>
: Use{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
@
</Text>{' '}
to specify files for context (e.g.,{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
@src/myFile.ts
</Text>
) to target specific files or folders.
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Shell mode
</Text>
: Execute shell commands via{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
!
</Text>{' '}
(e.g.,{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
!npm run start
</Text>
) or use natural language (e.g.{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
start server
</Text>
).
@@ -61,15 +61,15 @@ export const Help: React.FC<Help> = ({ commands }) => (
<Box height={1} />
{/* Commands */}
- <Text bold color={theme.text.primary}>
+ <Text bold color={Colors.Foreground}>
Commands:
</Text>
{commands
.filter((command) => command.description)
.map((command: SlashCommand) => (
<Box key={command.name} flexDirection="column">
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
{' '}
/{command.name}
</Text>
@@ -77,8 +77,8 @@ export const Help: React.FC<Help> = ({ commands }) => (
</Text>
{command.subCommands &&
command.subCommands.map((subCommand) => (
- <Text key={subCommand.name} color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text key={subCommand.name} color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
{' '}
{subCommand.name}
</Text>
@@ -87,8 +87,8 @@ export const Help: React.FC<Help> = ({ commands }) => (
))}
</Box>
))}
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
{' '}
!{' '}
</Text>
@@ -98,75 +98,75 @@ export const Help: React.FC<Help> = ({ commands }) => (
<Box height={1} />
{/* Shortcuts */}
- <Text bold color={theme.text.primary}>
+ <Text bold color={Colors.Foreground}>
Keyboard Shortcuts:
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Alt+Left/Right
</Text>{' '}
- Jump through words in the input
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Ctrl+C
</Text>{' '}
- Quit application
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
{process.platform === 'win32' ? 'Ctrl+Enter' : 'Ctrl+J'}
</Text>{' '}
{process.platform === 'linux'
? '- New line (Alt+Enter works for certain linux distros)'
: '- New line'}
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Ctrl+L
</Text>{' '}
- Clear the screen
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
{process.platform === 'darwin' ? 'Ctrl+X / Meta+Enter' : 'Ctrl+X'}
</Text>{' '}
- Open input in external editor
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Ctrl+Y
</Text>{' '}
- Toggle YOLO mode
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Enter
</Text>{' '}
- Send message
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Esc
</Text>{' '}
- Cancel operation
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Shift+Tab
</Text>{' '}
- Toggle auto-accepting edits
</Text>
- <Text color={theme.text.primary}>
- <Text bold color={theme.text.accent}>
+ <Text color={Colors.Foreground}>
+ <Text bold color={Colors.AccentPurple}>
Up/Down
</Text>{' '}
- Cycle through your prompt history
</Text>
<Box height={1} />
- <Text color={theme.text.primary}>
+ <Text color={Colors.Foreground}>
For a full list of shortcuts, see{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
docs/keyboard-shortcuts.md
</Text>
</Text>
diff --git a/packages/cli/src/ui/components/InputPrompt.tsx b/packages/cli/src/ui/components/InputPrompt.tsx
index 3a87b76e..dcfdace3 100644
--- a/packages/cli/src/ui/components/InputPrompt.tsx
+++ b/packages/cli/src/ui/components/InputPrompt.tsx
@@ -559,7 +559,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
<Box flexGrow={1} flexDirection="column">
{buffer.text.length === 0 && placeholder ? (
focus ? (
- <Text color={theme.text.primary}>
+ <Text>
{chalk.inverse(placeholder.slice(0, 1))}
<Text color={theme.text.secondary}>{placeholder.slice(1)}</Text>
</Text>
@@ -600,12 +600,7 @@ export const InputPrompt: React.FC<InputPromptProps> = ({
}
}
return (
- <Text
- key={`line-${visualIdxInRenderedSet}`}
- color={theme.text.primary}
- >
- {display}
- </Text>
+ <Text key={`line-${visualIdxInRenderedSet}`}>{display}</Text>
);
})
)}
diff --git a/packages/cli/src/ui/components/LoadingIndicator.tsx b/packages/cli/src/ui/components/LoadingIndicator.tsx
index fc51a7ef..7ac356dd 100644
--- a/packages/cli/src/ui/components/LoadingIndicator.tsx
+++ b/packages/cli/src/ui/components/LoadingIndicator.tsx
@@ -7,7 +7,7 @@
import { ThoughtSummary } from '@google/gemini-cli-core';
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { useStreamingContext } from '../contexts/StreamingContext.js';
import { StreamingState } from '../types.js';
import { GeminiRespondingSpinner } from './GeminiRespondingSpinner.js';
@@ -61,9 +61,11 @@ export const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({
}
/>
</Box>
- {primaryText && <Text color={theme.text.accent}>{primaryText}</Text>}
+ {primaryText && (
+ <Text color={Colors.AccentPurple}>{primaryText}</Text>
+ )}
{!isNarrow && cancelAndTimerContent && (
- <Text color={theme.text.secondary}> {cancelAndTimerContent}</Text>
+ <Text color={Colors.Gray}> {cancelAndTimerContent}</Text>
)}
</Box>
{!isNarrow && <Box flexGrow={1}>{/* Spacer */}</Box>}
@@ -71,7 +73,7 @@ export const LoadingIndicator: React.FC<LoadingIndicatorProps> = ({
</Box>
{isNarrow && cancelAndTimerContent && (
<Box>
- <Text color={theme.text.secondary}>{cancelAndTimerContent}</Text>
+ <Text color={Colors.Gray}>{cancelAndTimerContent}</Text>
</Box>
)}
{isNarrow && rightContent && <Box>{rightContent}</Box>}
diff --git a/packages/cli/src/ui/components/MemoryUsageDisplay.tsx b/packages/cli/src/ui/components/MemoryUsageDisplay.tsx
index 55be64cc..d768445c 100644
--- a/packages/cli/src/ui/components/MemoryUsageDisplay.tsx
+++ b/packages/cli/src/ui/components/MemoryUsageDisplay.tsx
@@ -6,24 +6,20 @@
import React, { useEffect, useState } from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import process from 'node:process';
import { formatMemoryUsage } from '../utils/formatters.js';
export const MemoryUsageDisplay: React.FC = () => {
const [memoryUsage, setMemoryUsage] = useState<string>('');
- const [memoryUsageColor, setMemoryUsageColor] = useState<string>(
- theme.text.secondary,
- );
+ const [memoryUsageColor, setMemoryUsageColor] = useState<string>(Colors.Gray);
useEffect(() => {
const updateMemory = () => {
const usage = process.memoryUsage().rss;
setMemoryUsage(formatMemoryUsage(usage));
setMemoryUsageColor(
- usage >= 2 * 1024 * 1024 * 1024
- ? theme.status.error
- : theme.text.secondary,
+ usage >= 2 * 1024 * 1024 * 1024 ? Colors.AccentRed : Colors.Gray,
);
};
const intervalId = setInterval(updateMemory, 2000);
@@ -33,7 +29,7 @@ export const MemoryUsageDisplay: React.FC = () => {
return (
<Box>
- <Text color={theme.text.secondary}>| </Text>
+ <Text color={Colors.Gray}>| </Text>
<Text color={memoryUsageColor}>{memoryUsage}</Text>
</Box>
);
diff --git a/packages/cli/src/ui/components/ModelStatsDisplay.tsx b/packages/cli/src/ui/components/ModelStatsDisplay.tsx
index c3b109a3..1911e757 100644
--- a/packages/cli/src/ui/components/ModelStatsDisplay.tsx
+++ b/packages/cli/src/ui/components/ModelStatsDisplay.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { formatDuration } from '../utils/formatters.js';
import {
calculateAverageLatency,
@@ -33,13 +33,13 @@ const StatRow: React.FC<StatRowProps> = ({
}) => (
<Box>
<Box width={METRIC_COL_WIDTH}>
- <Text bold color={isSection ? theme.text.primary : theme.text.link}>
+ <Text bold={isSection} color={isSection ? undefined : Colors.LightBlue}>
{isSubtle ? ` ↳ ${title}` : title}
</Text>
</Box>
{values.map((value, index) => (
<Box width={MODEL_COL_WIDTH} key={index}>
- <Text color={theme.text.primary}>{value}</Text>
+ <Text>{value}</Text>
</Box>
))}
</Box>
@@ -56,13 +56,11 @@ export const ModelStatsDisplay: React.FC = () => {
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
paddingY={1}
paddingX={2}
>
- <Text color={theme.text.primary}>
- No API calls have been made in this session.
- </Text>
+ <Text>No API calls have been made in this session.</Text>
</Box>
);
}
@@ -84,12 +82,12 @@ export const ModelStatsDisplay: React.FC = () => {
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
paddingY={1}
paddingX={2}
>
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
Model Stats For Nerds
</Text>
<Box height={1} />
@@ -97,15 +95,11 @@ export const ModelStatsDisplay: React.FC = () => {
{/* Header */}
<Box>
<Box width={METRIC_COL_WIDTH}>
- <Text bold color={theme.text.primary}>
- Metric
- </Text>
+ <Text bold>Metric</Text>
</Box>
{modelNames.map((name) => (
<Box width={MODEL_COL_WIDTH} key={name}>
- <Text bold color={theme.text.primary}>
- {name}
- </Text>
+ <Text bold>{name}</Text>
</Box>
))}
</Box>
@@ -132,7 +126,7 @@ export const ModelStatsDisplay: React.FC = () => {
return (
<Text
color={
- m.api.totalErrors > 0 ? theme.status.error : theme.text.primary
+ m.api.totalErrors > 0 ? Colors.AccentRed : Colors.Foreground
}
>
{m.api.totalErrors.toLocaleString()} ({errorRate.toFixed(1)}%)
@@ -155,7 +149,7 @@ export const ModelStatsDisplay: React.FC = () => {
<StatRow
title="Total"
values={getModelValues((m) => (
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
{m.tokens.total.toLocaleString()}
</Text>
))}
@@ -172,7 +166,7 @@ export const ModelStatsDisplay: React.FC = () => {
values={getModelValues((m) => {
const cacheHitRate = calculateCacheHitRate(m);
return (
- <Text color={theme.status.success}>
+ <Text color={Colors.AccentGreen}>
{m.tokens.cached.toLocaleString()} ({cacheHitRate.toFixed(1)}%)
</Text>
);
diff --git a/packages/cli/src/ui/components/PrepareLabel.tsx b/packages/cli/src/ui/components/PrepareLabel.tsx
index e255d386..652a77a6 100644
--- a/packages/cli/src/ui/components/PrepareLabel.tsx
+++ b/packages/cli/src/ui/components/PrepareLabel.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
interface PrepareLabelProps {
label: string;
@@ -21,7 +21,7 @@ export const PrepareLabel: React.FC<PrepareLabelProps> = ({
matchedIndex,
userInput,
textColor,
- highlightColor = theme.status.warning,
+ highlightColor = Colors.AccentYellow,
}) => {
if (
matchedIndex === undefined ||
@@ -37,7 +37,7 @@ export const PrepareLabel: React.FC<PrepareLabelProps> = ({
const end = label.slice(matchedIndex + userInput.length);
return (
- <Text color={theme.text.primary}>
+ <Text>
<Text color={textColor}>{start}</Text>
<Text color="black" bold backgroundColor={highlightColor}>
{match}
diff --git a/packages/cli/src/ui/components/SettingsDialog.tsx b/packages/cli/src/ui/components/SettingsDialog.tsx
index ce50e28f..a09cd76a 100644
--- a/packages/cli/src/ui/components/SettingsDialog.tsx
+++ b/packages/cli/src/ui/components/SettingsDialog.tsx
@@ -6,7 +6,7 @@
import React, { useState, useEffect } from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import {
LoadedSettings,
SettingScope,
@@ -366,18 +366,18 @@ export function SettingsDialog({
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="row"
padding={1}
width="100%"
height="100%"
>
<Box flexDirection="column" flexGrow={1}>
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.AccentBlue}>
Settings
</Text>
<Box height={1} />
- {showScrollUp && <Text color={theme.text.secondary}>▲</Text>}
+ {showScrollUp && <Text color={Colors.Gray}>▲</Text>}
{visibleItems.map((item, idx) => {
const isActive =
focusSection === 'settings' &&
@@ -405,21 +405,17 @@ export function SettingsDialog({
<React.Fragment key={item.value}>
<Box flexDirection="row" alignItems="center">
<Box minWidth={2} flexShrink={0}>
- <Text
- color={
- isActive ? theme.status.success : theme.text.secondary
- }
- >
+ <Text color={isActive ? Colors.AccentGreen : Colors.Gray}>
{isActive ? '●' : ''}
</Text>
</Box>
<Box minWidth={50}>
<Text
- color={isActive ? theme.status.success : theme.text.primary}
+ color={isActive ? Colors.AccentGreen : Colors.Foreground}
>
{item.label}
{scopeMessage && (
- <Text color={theme.text.secondary}> {scopeMessage}</Text>
+ <Text color={Colors.Gray}> {scopeMessage}</Text>
)}
</Text>
</Box>
@@ -427,10 +423,10 @@ export function SettingsDialog({
<Text
color={
isActive
- ? theme.status.success
+ ? Colors.AccentGreen
: shouldBeGreyedOut
- ? theme.text.secondary
- : theme.text.primary
+ ? Colors.Gray
+ : Colors.Foreground
}
>
{displayValue}
@@ -440,16 +436,12 @@ export function SettingsDialog({
</React.Fragment>
);
})}
- {showScrollDown && <Text color={theme.text.secondary}>▼</Text>}
+ {showScrollDown && <Text color={Colors.Gray}>▼</Text>}
<Box height={1} />
<Box marginTop={1} flexDirection="column">
- <Text
- bold={focusSection === 'scope'}
- wrap="truncate"
- color={theme.text.primary}
- >
+ <Text bold={focusSection === 'scope'} wrap="truncate">
{focusSection === 'scope' ? '> ' : ' '}Apply To
</Text>
<RadioButtonSelect
@@ -463,11 +455,11 @@ export function SettingsDialog({
</Box>
<Box height={1} />
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
(Use Enter to select, Tab to change focus)
</Text>
{showRestartPrompt && (
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
To see changes, Gemini CLI must be restarted. Press r to exit and
apply changes now.
</Text>
diff --git a/packages/cli/src/ui/components/ShellConfirmationDialog.tsx b/packages/cli/src/ui/components/ShellConfirmationDialog.tsx
index 99273593..04e57364 100644
--- a/packages/cli/src/ui/components/ShellConfirmationDialog.tsx
+++ b/packages/cli/src/ui/components/ShellConfirmationDialog.tsx
@@ -7,7 +7,7 @@
import { ToolConfirmationOutcome } from '@google/gemini-cli-core';
import { Box, Text } from 'ink';
import React from 'react';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import {
RadioButtonSelect,
RadioSelectItem,
@@ -69,27 +69,23 @@ export const ShellConfirmationDialog: React.FC<
<Box
flexDirection="column"
borderStyle="round"
- borderColor={theme.status.warning}
+ borderColor={Colors.AccentYellow}
padding={1}
width="100%"
marginLeft={1}
>
<Box flexDirection="column" marginBottom={1}>
- <Text bold color={theme.text.primary}>
- Shell Command Execution
- </Text>
- <Text color={theme.text.primary}>
- A custom command wants to run the following shell commands:
- </Text>
+ <Text bold>Shell Command Execution</Text>
+ <Text>A custom command wants to run the following shell commands:</Text>
<Box
flexDirection="column"
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
paddingX={1}
marginTop={1}
>
{commands.map((cmd) => (
- <Text key={cmd} color={theme.text.accent}>
+ <Text key={cmd} color={Colors.AccentCyan}>
{cmd}
</Text>
))}
@@ -97,7 +93,7 @@ export const ShellConfirmationDialog: React.FC<
</Box>
<Box marginBottom={1}>
- <Text color={theme.text.primary}>Do you want to proceed?</Text>
+ <Text>Do you want to proceed?</Text>
</Box>
<RadioButtonSelect items={options} onSelect={handleSelect} isFocused />
diff --git a/packages/cli/src/ui/components/ShellModeIndicator.tsx b/packages/cli/src/ui/components/ShellModeIndicator.tsx
index 3ad632c8..f5b11b24 100644
--- a/packages/cli/src/ui/components/ShellModeIndicator.tsx
+++ b/packages/cli/src/ui/components/ShellModeIndicator.tsx
@@ -6,13 +6,13 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
export const ShellModeIndicator: React.FC = () => (
<Box>
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
shell mode enabled
- <Text color={theme.text.secondary}> (esc to disable)</Text>
+ <Text color={Colors.Gray}> (esc to disable)</Text>
</Text>
</Box>
);
diff --git a/packages/cli/src/ui/components/ShowMoreLines.tsx b/packages/cli/src/ui/components/ShowMoreLines.tsx
index 8823eee6..41232d94 100644
--- a/packages/cli/src/ui/components/ShowMoreLines.tsx
+++ b/packages/cli/src/ui/components/ShowMoreLines.tsx
@@ -8,7 +8,7 @@ import { Box, Text } from 'ink';
import { useOverflowState } from '../contexts/OverflowContext.js';
import { useStreamingContext } from '../contexts/StreamingContext.js';
import { StreamingState } from '../types.js';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
interface ShowMoreLinesProps {
constrainHeight: boolean;
@@ -32,7 +32,7 @@ export const ShowMoreLines = ({ constrainHeight }: ShowMoreLinesProps) => {
return (
<Box>
- <Text color={theme.text.secondary} wrap="truncate">
+ <Text color={Colors.Gray} wrap="truncate">
Press ctrl-s to show more lines
</Text>
</Box>
diff --git a/packages/cli/src/ui/components/StatsDisplay.test.tsx b/packages/cli/src/ui/components/StatsDisplay.test.tsx
index d186f612..eed105e3 100644
--- a/packages/cli/src/ui/components/StatsDisplay.test.tsx
+++ b/packages/cli/src/ui/components/StatsDisplay.test.tsx
@@ -43,7 +43,7 @@ describe('<StatsDisplay />', () => {
const zeroMetrics: SessionMetrics = {
models: {},
tools: {
- totalCalls: 1,
+ totalCalls: 0,
totalSuccess: 0,
totalFail: 0,
totalDurationMs: 0,
diff --git a/packages/cli/src/ui/components/StatsDisplay.tsx b/packages/cli/src/ui/components/StatsDisplay.tsx
index 03c1fff6..71c88aef 100644
--- a/packages/cli/src/ui/components/StatsDisplay.tsx
+++ b/packages/cli/src/ui/components/StatsDisplay.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { Box, Text } from 'ink';
import Gradient from 'ink-gradient';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { formatDuration } from '../utils/formatters.js';
import { useSessionStats, ModelMetrics } from '../contexts/SessionContext.js';
import {
@@ -29,7 +29,7 @@ const StatRow: React.FC<StatRowProps> = ({ title, children }) => (
<Box>
{/* Fixed width for the label creates a clean "gutter" for alignment */}
<Box width={28}>
- <Text color={theme.text.link}>{title}</Text>
+ <Text color={Colors.LightBlue}>{title}</Text>
</Box>
{children}
</Box>
@@ -45,7 +45,7 @@ const SubStatRow: React.FC<SubStatRowProps> = ({ title, children }) => (
<Box paddingLeft={2}>
{/* Adjust width for the "» " prefix */}
<Box width={26}>
- <Text color={theme.text.secondary}>» {title}</Text>
+ <Text>» {title}</Text>
</Box>
{children}
</Box>
@@ -59,9 +59,7 @@ interface SectionProps {
const Section: React.FC<SectionProps> = ({ title, children }) => (
<Box flexDirection="column" width="100%" marginBottom={1}>
- <Text bold color={theme.text.primary}>
- {title}
- </Text>
+ <Text bold>{title}</Text>
{children}
</Box>
);
@@ -81,24 +79,16 @@ const ModelUsageTable: React.FC<{
{/* Header */}
<Box>
<Box width={nameWidth}>
- <Text bold color={theme.text.primary}>
- Model Usage
- </Text>
+ <Text bold>Model Usage</Text>
</Box>
<Box width={requestsWidth} justifyContent="flex-end">
- <Text bold color={theme.text.primary}>
- Reqs
- </Text>
+ <Text bold>Reqs</Text>
</Box>
<Box width={inputTokensWidth} justifyContent="flex-end">
- <Text bold color={theme.text.primary}>
- Input Tokens
- </Text>
+ <Text bold>Input Tokens</Text>
</Box>
<Box width={outputTokensWidth} justifyContent="flex-end">
- <Text bold color={theme.text.primary}>
- Output Tokens
- </Text>
+ <Text bold>Output Tokens</Text>
</Box>
</Box>
{/* Divider */}
@@ -108,7 +98,6 @@ const ModelUsageTable: React.FC<{
borderTop={false}
borderLeft={false}
borderRight={false}
- borderColor={theme.border.default}
width={nameWidth + requestsWidth + inputTokensWidth + outputTokensWidth}
></Box>
@@ -116,20 +105,18 @@ const ModelUsageTable: React.FC<{
{Object.entries(models).map(([name, modelMetrics]) => (
<Box key={name}>
<Box width={nameWidth}>
- <Text color={theme.text.primary}>{name.replace('-001', '')}</Text>
+ <Text>{name.replace('-001', '')}</Text>
</Box>
<Box width={requestsWidth} justifyContent="flex-end">
- <Text color={theme.text.primary}>
- {modelMetrics.api.totalRequests}
- </Text>
+ <Text>{modelMetrics.api.totalRequests}</Text>
</Box>
<Box width={inputTokensWidth} justifyContent="flex-end">
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
{modelMetrics.tokens.prompt.toLocaleString()}
</Text>
</Box>
<Box width={outputTokensWidth} justifyContent="flex-end">
- <Text color={theme.status.warning}>
+ <Text color={Colors.AccentYellow}>
{modelMetrics.tokens.candidates.toLocaleString()}
</Text>
</Box>
@@ -137,13 +124,13 @@ const ModelUsageTable: React.FC<{
))}
{cacheEfficiency > 0 && (
<Box flexDirection="column" marginTop={1}>
- <Text color={theme.text.primary}>
- <Text color={theme.status.success}>Savings Highlight:</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentGreen}>Savings Highlight:</Text>{' '}
{totalCachedTokens.toLocaleString()} ({cacheEfficiency.toFixed(1)}
%) of input tokens were served from the cache, reducing costs.
</Text>
<Box height={1} />
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
» Tip: For a full token breakdown, run `/stats model`.
</Text>
</Box>
@@ -182,18 +169,18 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
const renderTitle = () => {
if (title) {
- return theme.ui.gradient && theme.ui.gradient.length > 0 ? (
- <Gradient colors={theme.ui.gradient}>
+ return Colors.GradientColors && Colors.GradientColors.length > 0 ? (
+ <Gradient colors={Colors.GradientColors}>
<Text bold>{title}</Text>
</Gradient>
) : (
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
{title}
</Text>
);
}
return (
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
Session Stats
</Text>
);
@@ -202,7 +189,7 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
paddingY={1}
paddingX={2}
@@ -210,55 +197,51 @@ export const StatsDisplay: React.FC<StatsDisplayProps> = ({
{renderTitle()}
<Box height={1} />
- {tools.totalCalls > 0 && (
- <Section title="Interaction Summary">
- <StatRow title="Session ID:">
- <Text>{stats.sessionId}</Text>
- </StatRow>
- <StatRow title="Tool Calls:">
- <Text color={theme.text.primary}>
- {tools.totalCalls} ({' '}
- <Text color={theme.status.success}>✔ {tools.totalSuccess}</Text>{' '}
- <Text color={theme.status.error}>✖ {tools.totalFail}</Text> )
+ <Section title="Interaction Summary">
+ <StatRow title="Session ID:">
+ <Text>{stats.sessionId}</Text>
+ </StatRow>
+ <StatRow title="Tool Calls:">
+ <Text>
+ {tools.totalCalls} ({' '}
+ <Text color={Colors.AccentGreen}>✔ {tools.totalSuccess}</Text>{' '}
+ <Text color={Colors.AccentRed}>✖ {tools.totalFail}</Text> )
+ </Text>
+ </StatRow>
+ <StatRow title="Success Rate:">
+ <Text color={successColor}>{computed.successRate.toFixed(1)}%</Text>
+ </StatRow>
+ {computed.totalDecisions > 0 && (
+ <StatRow title="User Agreement:">
+ <Text color={agreementColor}>
+ {computed.agreementRate.toFixed(1)}%{' '}
+ <Text color={Colors.Gray}>
+ ({computed.totalDecisions} reviewed)
+ </Text>
</Text>
</StatRow>
- <StatRow title="Success Rate:">
- <Text color={successColor}>{computed.successRate.toFixed(1)}%</Text>
- </StatRow>
- {computed.totalDecisions > 0 && (
- <StatRow title="User Agreement:">
- <Text color={agreementColor}>
- {computed.agreementRate.toFixed(1)}%{' '}
- <Text color={theme.text.secondary}>
- ({computed.totalDecisions} reviewed)
- </Text>
- </Text>
- </StatRow>
- )}
- </Section>
- )}
+ )}
+ </Section>
<Section title="Performance">
<StatRow title="Wall Time:">
- <Text color={theme.text.primary}>{duration}</Text>
+ <Text>{duration}</Text>
</StatRow>
<StatRow title="Agent Active:">
- <Text color={theme.text.primary}>
- {formatDuration(computed.agentActiveTime)}
- </Text>
+ <Text>{formatDuration(computed.agentActiveTime)}</Text>
</StatRow>
<SubStatRow title="API Time:">
- <Text color={theme.text.primary}>
+ <Text>
{formatDuration(computed.totalApiTime)}{' '}
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
({computed.apiTimePercent.toFixed(1)}%)
</Text>
</Text>
</SubStatRow>
<SubStatRow title="Tool Time:">
- <Text color={theme.text.primary}>
+ <Text>
{formatDuration(computed.totalToolTime)}{' '}
- <Text color={theme.text.secondary}>
+ <Text color={Colors.Gray}>
({computed.toolTimePercent.toFixed(1)}%)
</Text>
</Text>
diff --git a/packages/cli/src/ui/components/SuggestionsDisplay.tsx b/packages/cli/src/ui/components/SuggestionsDisplay.tsx
index 4f18e837..1275a911 100644
--- a/packages/cli/src/ui/components/SuggestionsDisplay.tsx
+++ b/packages/cli/src/ui/components/SuggestionsDisplay.tsx
@@ -5,7 +5,7 @@
*/
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { PrepareLabel } from './PrepareLabel.js';
export interface Suggestion {
label: string;
@@ -35,7 +35,7 @@ export function SuggestionsDisplay({
if (isLoading) {
return (
<Box paddingX={1} width={width}>
- <Text color={theme.text.secondary}>Loading suggestions...</Text>
+ <Text color="gray">Loading suggestions...</Text>
</Box>
);
}
@@ -54,12 +54,12 @@ export function SuggestionsDisplay({
return (
<Box flexDirection="column" paddingX={1} width={width}>
- {scrollOffset > 0 && <Text color={theme.text.primary}>▲</Text>}
+ {scrollOffset > 0 && <Text color={Colors.Foreground}>▲</Text>}
{visibleSuggestions.map((suggestion, index) => {
const originalIndex = startIndex + index;
const isActive = originalIndex === activeIndex;
- const textColor = isActive ? theme.text.accent : theme.text.secondary;
+ const textColor = isActive ? Colors.AccentPurple : Colors.Gray;
const labelElement = (
<PrepareLabel
label={suggestion.label}
@@ -91,11 +91,9 @@ export function SuggestionsDisplay({
</Box>
);
})}
- {endIndex < suggestions.length && (
- <Text color={theme.text.secondary}>▼</Text>
- )}
+ {endIndex < suggestions.length && <Text color="gray">▼</Text>}
{suggestions.length > MAX_SUGGESTIONS_TO_SHOW && (
- <Text color={theme.text.secondary}>
+ <Text color="gray">
({activeIndex + 1}/{suggestions.length})
</Text>
)}
diff --git a/packages/cli/src/ui/components/ThemeDialog.tsx b/packages/cli/src/ui/components/ThemeDialog.tsx
index c26dfa96..16ecfc8f 100644
--- a/packages/cli/src/ui/components/ThemeDialog.tsx
+++ b/packages/cli/src/ui/components/ThemeDialog.tsx
@@ -6,7 +6,7 @@
import React, { useCallback, useState } from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { themeManager, DEFAULT_THEME } from '../themes/theme-manager.js';
import { RadioButtonSelect } from './shared/RadioButtonSelect.js';
import { DiffRenderer } from './messages/DiffRenderer.js';
@@ -207,7 +207,7 @@ export function ThemeDialog({
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
paddingTop={includePadding ? 1 : 0}
paddingBottom={includePadding ? 1 : 0}
@@ -218,19 +218,9 @@ export function ThemeDialog({
<Box flexDirection="row">
{/* Left Column: Selection */}
<Box flexDirection="column" width="45%" paddingRight={2}>
- <Text
- bold={currentFocusedSection === 'theme'}
- wrap="truncate"
- color={
- currentFocusedSection === 'theme'
- ? theme.text.primary
- : theme.text.secondary
- }
- >
+ <Text bold={currentFocusedSection === 'theme'} wrap="truncate">
{currentFocusedSection === 'theme' ? '> ' : ' '}Select Theme{' '}
- <Text color={theme.text.secondary}>
- {otherScopeModifiedMessage}
- </Text>
+ <Text color={Colors.Gray}>{otherScopeModifiedMessage}</Text>
</Text>
<RadioButtonSelect
key={selectInputKey}
@@ -247,15 +237,7 @@ export function ThemeDialog({
{/* Scope Selection */}
{showScopeSelection && (
<Box marginTop={1} flexDirection="column">
- <Text
- bold={currentFocusedSection === 'scope'}
- wrap="truncate"
- color={
- currentFocusedSection === 'scope'
- ? theme.text.primary
- : theme.text.secondary
- }
- >
+ <Text bold={currentFocusedSection === 'scope'} wrap="truncate">
{currentFocusedSection === 'scope' ? '> ' : ' '}Apply To
</Text>
<RadioButtonSelect
@@ -272,9 +254,7 @@ export function ThemeDialog({
{/* Right Column: Preview */}
<Box flexDirection="column" width="55%" paddingLeft={2}>
- <Text bold color={theme.text.primary}>
- Preview
- </Text>
+ <Text bold>Preview</Text>
{/* Get the Theme object for the highlighted theme, fall back to default if not found */}
{(() => {
const previewTheme =
@@ -284,7 +264,7 @@ export function ThemeDialog({
return (
<Box
borderStyle="single"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
paddingTop={includePadding ? 1 : 0}
paddingBottom={includePadding ? 1 : 0}
paddingLeft={1}
@@ -301,7 +281,6 @@ def fibonacci(n):
'python',
codeBlockHeight,
colorizeCodeWidth,
- previewTheme,
)}
<Box marginTop={1} />
<DiffRenderer
@@ -321,7 +300,7 @@ def fibonacci(n):
</Box>
</Box>
<Box marginTop={1}>
- <Text color={theme.text.secondary} wrap="truncate">
+ <Text color={Colors.Gray} wrap="truncate">
(Use Enter to select
{showScopeSelection ? ', Tab to change focus' : ''})
</Text>
diff --git a/packages/cli/src/ui/components/Tips.tsx b/packages/cli/src/ui/components/Tips.tsx
index 6e754e08..4aa6c112 100644
--- a/packages/cli/src/ui/components/Tips.tsx
+++ b/packages/cli/src/ui/components/Tips.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { type Config } from '@google/gemini-cli-core';
interface TipsProps {
@@ -17,25 +17,25 @@ export const Tips: React.FC<TipsProps> = ({ config }) => {
const geminiMdFileCount = config.getGeminiMdFileCount();
return (
<Box flexDirection="column">
- <Text color={theme.text.primary}>Tips for getting started:</Text>
- <Text color={theme.text.primary}>
+ <Text color={Colors.Foreground}>Tips for getting started:</Text>
+ <Text color={Colors.Foreground}>
1. Ask questions, edit files, or run commands.
</Text>
- <Text color={theme.text.primary}>
+ <Text color={Colors.Foreground}>
2. Be specific for the best results.
</Text>
{geminiMdFileCount === 0 && (
- <Text color={theme.text.primary}>
+ <Text color={Colors.Foreground}>
3. Create{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
GEMINI.md
</Text>{' '}
files to customize your interactions with Gemini.
</Text>
)}
- <Text color={theme.text.primary}>
+ <Text color={Colors.Foreground}>
{geminiMdFileCount === 0 ? '4.' : '3.'}{' '}
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
/help
</Text>{' '}
for more information.
diff --git a/packages/cli/src/ui/components/ToolStatsDisplay.tsx b/packages/cli/src/ui/components/ToolStatsDisplay.tsx
index 4bcee9fc..f2335d9e 100644
--- a/packages/cli/src/ui/components/ToolStatsDisplay.tsx
+++ b/packages/cli/src/ui/components/ToolStatsDisplay.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { formatDuration } from '../utils/formatters.js';
import {
getStatusColor,
@@ -37,16 +37,16 @@ const StatRow: React.FC<{
return (
<Box>
<Box width={TOOL_NAME_COL_WIDTH}>
- <Text color={theme.text.link}>{name}</Text>
+ <Text color={Colors.LightBlue}>{name}</Text>
</Box>
<Box width={CALLS_COL_WIDTH} justifyContent="flex-end">
- <Text color={theme.text.primary}>{stats.count}</Text>
+ <Text>{stats.count}</Text>
</Box>
<Box width={SUCCESS_RATE_COL_WIDTH} justifyContent="flex-end">
<Text color={successColor}>{successRate.toFixed(1)}%</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text color={theme.text.primary}>{formatDuration(avgDuration)}</Text>
+ <Text>{formatDuration(avgDuration)}</Text>
</Box>
</Box>
);
@@ -63,13 +63,11 @@ export const ToolStatsDisplay: React.FC = () => {
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
paddingY={1}
paddingX={2}
>
- <Text color={theme.text.primary}>
- No tool calls have been made in this session.
- </Text>
+ <Text>No tool calls have been made in this session.</Text>
</Box>
);
}
@@ -96,13 +94,13 @@ export const ToolStatsDisplay: React.FC = () => {
return (
<Box
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
flexDirection="column"
paddingY={1}
paddingX={2}
width={70}
>
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
Tool Stats For Nerds
</Text>
<Box height={1} />
@@ -110,24 +108,16 @@ export const ToolStatsDisplay: React.FC = () => {
{/* Header */}
<Box>
<Box width={TOOL_NAME_COL_WIDTH}>
- <Text bold color={theme.text.primary}>
- Tool Name
- </Text>
+ <Text bold>Tool Name</Text>
</Box>
<Box width={CALLS_COL_WIDTH} justifyContent="flex-end">
- <Text bold color={theme.text.primary}>
- Calls
- </Text>
+ <Text bold>Calls</Text>
</Box>
<Box width={SUCCESS_RATE_COL_WIDTH} justifyContent="flex-end">
- <Text bold color={theme.text.primary}>
- Success Rate
- </Text>
+ <Text bold>Success Rate</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text bold color={theme.text.primary}>
- Avg Duration
- </Text>
+ <Text bold>Avg Duration</Text>
</Box>
</Box>
@@ -149,47 +139,45 @@ export const ToolStatsDisplay: React.FC = () => {
<Box height={1} />
{/* User Decision Summary */}
- <Text bold color={theme.text.primary}>
- User Decision Summary
- </Text>
+ <Text bold>User Decision Summary</Text>
<Box>
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
- <Text color={theme.text.link}>Total Reviewed Suggestions:</Text>
+ <Text color={Colors.LightBlue}>Total Reviewed Suggestions:</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text color={theme.text.primary}>{totalReviewed}</Text>
+ <Text>{totalReviewed}</Text>
</Box>
</Box>
<Box>
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
- <Text color={theme.text.primary}> » Accepted:</Text>
+ <Text> » Accepted:</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text color={theme.status.success}>{totalDecisions.accept}</Text>
+ <Text color={Colors.AccentGreen}>{totalDecisions.accept}</Text>
</Box>
</Box>
<Box>
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
- <Text color={theme.text.primary}> » Rejected:</Text>
+ <Text> » Rejected:</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text color={theme.status.error}>{totalDecisions.reject}</Text>
+ <Text color={Colors.AccentRed}>{totalDecisions.reject}</Text>
</Box>
</Box>
<Box>
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
- <Text color={theme.text.primary}> » Modified:</Text>
+ <Text> » Modified:</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text color={theme.status.warning}>{totalDecisions.modify}</Text>
+ <Text color={Colors.AccentYellow}>{totalDecisions.modify}</Text>
</Box>
</Box>
@@ -207,13 +195,10 @@ export const ToolStatsDisplay: React.FC = () => {
<Box
width={TOOL_NAME_COL_WIDTH + CALLS_COL_WIDTH + SUCCESS_RATE_COL_WIDTH}
>
- <Text color={theme.text.primary}> Overall Agreement Rate:</Text>
+ <Text> Overall Agreement Rate:</Text>
</Box>
<Box width={AVG_DURATION_COL_WIDTH} justifyContent="flex-end">
- <Text
- bold
- color={totalReviewed > 0 ? agreementColor : theme.text.primary}
- >
+ <Text bold color={totalReviewed > 0 ? agreementColor : undefined}>
{totalReviewed > 0 ? `${agreementRate.toFixed(1)}%` : '--'}
</Text>
</Box>
diff --git a/packages/cli/src/ui/components/UpdateNotification.tsx b/packages/cli/src/ui/components/UpdateNotification.tsx
index 8142a201..b88c9bd5 100644
--- a/packages/cli/src/ui/components/UpdateNotification.tsx
+++ b/packages/cli/src/ui/components/UpdateNotification.tsx
@@ -5,7 +5,7 @@
*/
import { Box, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
interface UpdateNotificationProps {
message: string;
@@ -14,10 +14,10 @@ interface UpdateNotificationProps {
export const UpdateNotification = ({ message }: UpdateNotificationProps) => (
<Box
borderStyle="round"
- borderColor={theme.status.warning}
+ borderColor={Colors.AccentYellow}
paddingX={1}
marginY={1}
>
- <Text color={theme.status.warning}>{message}</Text>
+ <Text color={Colors.AccentYellow}>{message}</Text>
</Box>
);
diff --git a/packages/cli/src/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap
index c9b2bd64..98e7722e 100644
--- a/packages/cli/src/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap
+++ b/packages/cli/src/ui/components/__snapshots__/SessionSummaryDisplay.test.tsx.snap
@@ -5,6 +5,11 @@ exports[`<SessionSummaryDisplay /> > renders the summary display with a title 1`
│ │
│ Agent powering down. Goodbye! │
│ │
+│ Interaction Summary │
+│ Session ID: │
+│ Tool Calls: 0 ( ✔ 0 ✖ 0 ) │
+│ Success Rate: 0.0% │
+│ │
│ Performance │
│ Wall Time: 1h 23m 45s │
│ Agent Active: 50.2s │
diff --git a/packages/cli/src/ui/components/__snapshots__/StatsDisplay.test.tsx.snap b/packages/cli/src/ui/components/__snapshots__/StatsDisplay.test.tsx.snap
index bd27804c..09202599 100644
--- a/packages/cli/src/ui/components/__snapshots__/StatsDisplay.test.tsx.snap
+++ b/packages/cli/src/ui/components/__snapshots__/StatsDisplay.test.tsx.snap
@@ -65,6 +65,11 @@ exports[`<StatsDisplay /> > Conditional Rendering Tests > hides Efficiency secti
│ │
│ Session Stats │
│ │
+│ Interaction Summary │
+│ Session ID: test-session-id │
+│ Tool Calls: 0 ( ✔ 0 ✖ 0 ) │
+│ Success Rate: 0.0% │
+│ │
│ Performance │
│ Wall Time: 1s │
│ Agent Active: 100ms │
@@ -104,6 +109,11 @@ exports[`<StatsDisplay /> > Title Rendering > renders the custom title when a ti
│ │
│ Agent powering down. Goodbye! │
│ │
+│ Interaction Summary │
+│ Session ID: test-session-id │
+│ Tool Calls: 0 ( ✔ 0 ✖ 0 ) │
+│ Success Rate: 0.0% │
+│ │
│ Performance │
│ Wall Time: 1s │
│ Agent Active: 0s │
@@ -119,6 +129,11 @@ exports[`<StatsDisplay /> > Title Rendering > renders the default title when no
│ │
│ Session Stats │
│ │
+│ Interaction Summary │
+│ Session ID: test-session-id │
+│ Tool Calls: 0 ( ✔ 0 ✖ 0 ) │
+│ Success Rate: 0.0% │
+│ │
│ Performance │
│ Wall Time: 1s │
│ Agent Active: 0s │
@@ -134,6 +149,11 @@ exports[`<StatsDisplay /> > renders a table with two models correctly 1`] = `
│ │
│ Session Stats │
│ │
+│ Interaction Summary │
+│ Session ID: test-session-id │
+│ Tool Calls: 0 ( ✔ 0 ✖ 0 ) │
+│ Success Rate: 0.0% │
+│ │
│ Performance │
│ Wall Time: 1s │
│ Agent Active: 19.5s │
@@ -189,7 +209,7 @@ exports[`<StatsDisplay /> > renders only the Performance section in its zero sta
│ │
│ Interaction Summary │
│ Session ID: test-session-id │
-│ Tool Calls: 1 ( ✔ 0 ✖ 0 ) │
+│ Tool Calls: 0 ( ✔ 0 ✖ 0 ) │
│ Success Rate: 0.0% │
│ │
│ Performance │
diff --git a/packages/cli/src/ui/components/messages/CompressionMessage.tsx b/packages/cli/src/ui/components/messages/CompressionMessage.tsx
index 8f46a361..c7ef122b 100644
--- a/packages/cli/src/ui/components/messages/CompressionMessage.tsx
+++ b/packages/cli/src/ui/components/messages/CompressionMessage.tsx
@@ -8,7 +8,7 @@ import React from 'react';
import { Box, Text } from 'ink';
import { CompressionProps } from '../../types.js';
import Spinner from 'ink-spinner';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
export interface CompressionDisplayProps {
compression: CompressionProps;
@@ -32,13 +32,13 @@ export const CompressionMessage: React.FC<CompressionDisplayProps> = ({
{compression.isPending ? (
<Spinner type="dots" />
) : (
- <Text color={theme.text.accent}>✦</Text>
+ <Text color={Colors.AccentPurple}>✦</Text>
)}
</Box>
<Box>
<Text
color={
- compression.isPending ? theme.text.accent : theme.status.success
+ compression.isPending ? Colors.AccentPurple : Colors.AccentGreen
}
>
{text}
diff --git a/packages/cli/src/ui/components/messages/DiffRenderer.tsx b/packages/cli/src/ui/components/messages/DiffRenderer.tsx
index edea9939..fda5f1d4 100644
--- a/packages/cli/src/ui/components/messages/DiffRenderer.tsx
+++ b/packages/cli/src/ui/components/messages/DiffRenderer.tsx
@@ -6,9 +6,11 @@
import React from 'react';
import { Box, Text } from 'ink';
+import { Colors } from '../../colors.js';
import crypto from 'crypto';
import { colorizeCode, colorizeLine } from '../../utils/CodeColorizer.js';
import { MaxSizedBox } from '../shared/MaxSizedBox.js';
+import { theme } from '../../semantic-colors.js';
interface DiffLine {
type: 'add' | 'del' | 'context' | 'hunk' | 'other';
@@ -106,20 +108,14 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({
theme,
}) => {
if (!diffContent || typeof diffContent !== 'string') {
- return (
- <Text color={theme?.semanticColors.status.warning}>No diff content.</Text>
- );
+ return <Text color={Colors.AccentYellow}>No diff content.</Text>;
}
const parsedLines = parseDiffWithLineNumbers(diffContent);
if (parsedLines.length === 0) {
return (
- <Box
- borderStyle="round"
- borderColor={theme?.semanticColors.border.default}
- padding={1}
- >
+ <Box borderStyle="round" borderColor={Colors.Gray} padding={1}>
<Text dimColor>No changes detected.</Text>
</Box>
);
@@ -162,7 +158,6 @@ export const DiffRenderer: React.FC<DiffRendererProps> = ({
tabWidth,
availableTerminalHeight,
terminalWidth,
- theme,
);
}
@@ -175,7 +170,6 @@ const renderDiffContent = (
tabWidth = DEFAULT_TAB_WIDTH,
availableTerminalHeight: number | undefined,
terminalWidth: number,
- theme: import('../../themes/theme.js').Theme | undefined,
) => {
// 1. Normalize whitespace (replace tabs with spaces) *before* further processing
const normalizedLines = parsedLines.map((line) => ({
@@ -190,11 +184,7 @@ const renderDiffContent = (
if (displayableLines.length === 0) {
return (
- <Box
- borderStyle="round"
- borderColor={theme?.semanticColors.border.default}
- padding={1}
- >
+ <Box borderStyle="round" borderColor={Colors.Gray} padding={1}>
<Text dimColor>No changes detected.</Text>
</Box>
);
@@ -258,10 +248,7 @@ const renderDiffContent = (
) {
acc.push(
<Box key={`gap-${index}`}>
- <Text
- wrap="truncate"
- color={theme?.semanticColors.border.default}
- >
+ <Text wrap="truncate" color={Colors.Gray}>
{'═'.repeat(terminalWidth)}
</Text>
</Box>,
@@ -302,12 +289,12 @@ const renderDiffContent = (
acc.push(
<Box key={lineKey} flexDirection="row">
<Text
- color={theme?.semanticColors.text.secondary}
+ color={theme.text.secondary}
backgroundColor={
line.type === 'add'
- ? theme?.semanticColors.background.diff.added
+ ? theme.background.diff.added
: line.type === 'del'
- ? theme?.semanticColors.background.diff.removed
+ ? theme.background.diff.removed
: undefined
}
>
@@ -315,32 +302,30 @@ const renderDiffContent = (
</Text>
{line.type === 'context' ? (
<>
- <Text color={theme?.semanticColors.text.primary}>
- {prefixSymbol}{' '}
- </Text>
+ <Text>{prefixSymbol} </Text>
<Text wrap="wrap">
- {colorizeLine(displayContent, language, theme)}
+ {colorizeLine(displayContent, language)}
</Text>
</>
) : (
<Text
backgroundColor={
line.type === 'add'
- ? theme?.semanticColors.background.diff.added
- : theme?.semanticColors.background.diff.removed
+ ? theme.background.diff.added
+ : theme.background.diff.removed
}
wrap="wrap"
>
<Text
color={
line.type === 'add'
- ? theme?.semanticColors.status.success
- : theme?.semanticColors.status.error
+ ? theme.status.success
+ : theme.status.error
}
>
{prefixSymbol}
</Text>{' '}
- {colorizeLine(displayContent, language, theme)}
+ {colorizeLine(displayContent, language)}
</Text>
)}
</Box>,
diff --git a/packages/cli/src/ui/components/messages/ErrorMessage.tsx b/packages/cli/src/ui/components/messages/ErrorMessage.tsx
index bc249acf..edbea435 100644
--- a/packages/cli/src/ui/components/messages/ErrorMessage.tsx
+++ b/packages/cli/src/ui/components/messages/ErrorMessage.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text, Box } from 'ink';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
interface ErrorMessageProps {
text: string;
@@ -19,10 +19,10 @@ export const ErrorMessage: React.FC<ErrorMessageProps> = ({ text }) => {
return (
<Box flexDirection="row" marginBottom={1}>
<Box width={prefixWidth}>
- <Text color={theme.status.error}>{prefix}</Text>
+ <Text color={Colors.AccentRed}>{prefix}</Text>
</Box>
<Box flexGrow={1}>
- <Text wrap="wrap" color={theme.status.error}>
+ <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 21c2f77d..9863acd6 100644
--- a/packages/cli/src/ui/components/messages/GeminiMessage.tsx
+++ b/packages/cli/src/ui/components/messages/GeminiMessage.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { Text, Box } from 'ink';
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
interface GeminiMessageProps {
text: string;
@@ -28,7 +28,7 @@ export const GeminiMessage: React.FC<GeminiMessageProps> = ({
return (
<Box flexDirection="row">
<Box width={prefixWidth}>
- <Text color={theme.text.accent}>{prefix}</Text>
+ <Text color={Colors.AccentPurple}>{prefix}</Text>
</Box>
<Box flexGrow={1} flexDirection="column">
<MarkdownDisplay
diff --git a/packages/cli/src/ui/components/messages/InfoMessage.tsx b/packages/cli/src/ui/components/messages/InfoMessage.tsx
index 5b69216d..c9129999 100644
--- a/packages/cli/src/ui/components/messages/InfoMessage.tsx
+++ b/packages/cli/src/ui/components/messages/InfoMessage.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text, Box } from 'ink';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
interface InfoMessageProps {
text: string;
@@ -19,10 +19,10 @@ export const InfoMessage: React.FC<InfoMessageProps> = ({ text }) => {
return (
<Box flexDirection="row" marginTop={1}>
<Box width={prefixWidth}>
- <Text color={theme.status.warning}>{prefix}</Text>
+ <Text color={Colors.AccentYellow}>{prefix}</Text>
</Box>
<Box flexGrow={1}>
- <Text wrap="wrap" color={theme.status.warning}>
+ <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 599b5445..2f93609e 100644
--- a/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
+++ b/packages/cli/src/ui/components/messages/ToolConfirmationMessage.tsx
@@ -7,7 +7,7 @@
import React from 'react';
import { Box, Text } from 'ink';
import { DiffRenderer } from './DiffRenderer.js';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
import {
ToolCallConfirmationDetails,
ToolConfirmationOutcome,
@@ -112,13 +112,13 @@ export const ToolConfirmationMessage: React.FC<
<Box
minWidth="90%"
borderStyle="round"
- borderColor={theme.border.default}
+ borderColor={Colors.Gray}
justifyContent="space-around"
padding={1}
overflow="hidden"
>
- <Text color={theme.text.primary}>Modify in progress: </Text>
- <Text color={theme.status.success}>
+ <Text>Modify in progress: </Text>
+ <Text color={Colors.AccentGreen}>
Save and close external editor to continue
</Text>
</Box>
@@ -192,7 +192,7 @@ export const ToolConfirmationMessage: React.FC<
maxWidth={Math.max(childWidth - 4, 1)}
>
<Box>
- <Text color={theme.text.accent}>{executionProps.command}</Text>
+ <Text color={Colors.AccentCyan}>{executionProps.command}</Text>
</Box>
</MaxSizedBox>
</Box>
@@ -222,15 +222,12 @@ export const ToolConfirmationMessage: React.FC<
bodyContent = (
<Box flexDirection="column" paddingX={1} marginLeft={1}>
- <Text color={theme.text.accent}>{infoProps.prompt}</Text>
+ <Text color={Colors.AccentCyan}>{infoProps.prompt}</Text>
{displayUrls && infoProps.urls && infoProps.urls.length > 0 && (
<Box flexDirection="column" marginTop={1}>
- <Text color={theme.text.primary}>URLs to fetch:</Text>
+ <Text>URLs to fetch:</Text>
{infoProps.urls.map((url) => (
- <Text key={url} color={theme.text.primary}>
- {' '}
- - {url}
- </Text>
+ <Text key={url}> - {url}</Text>
))}
</Box>
)}
@@ -242,8 +239,8 @@ export const ToolConfirmationMessage: React.FC<
bodyContent = (
<Box flexDirection="column" paddingX={1} marginLeft={1}>
- <Text color={theme.text.accent}>MCP Server: {mcpProps.serverName}</Text>
- <Text color={theme.text.accent}>Tool: {mcpProps.toolName}</Text>
+ <Text color={Colors.AccentCyan}>MCP Server: {mcpProps.serverName}</Text>
+ <Text color={Colors.AccentCyan}>Tool: {mcpProps.toolName}</Text>
</Box>
);
@@ -278,9 +275,7 @@ export const ToolConfirmationMessage: React.FC<
{/* Confirmation Question */}
<Box marginBottom={1} flexShrink={0}>
- <Text wrap="truncate" color={theme.text.primary}>
- {question}
- </Text>
+ <Text wrap="truncate">{question}</Text>
</Box>
{/* Select Input for Options */}
diff --git a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
index 3e7a317c..e2df3d9c 100644
--- a/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
+++ b/packages/cli/src/ui/components/messages/ToolGroupMessage.tsx
@@ -9,7 +9,7 @@ import { Box } from 'ink';
import { IndividualToolCallDisplay, ToolCallStatus } from '../../types.js';
import { ToolMessage } from './ToolMessage.js';
import { ToolConfirmationMessage } from './ToolConfirmationMessage.js';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
import { Config } from '@google/gemini-cli-core';
import { SHELL_COMMAND_NAME } from '../../constants.js';
@@ -35,7 +35,7 @@ export const ToolGroupMessage: React.FC<ToolGroupMessageProps> = ({
);
const isShellCommand = toolCalls.some((t) => t.name === SHELL_COMMAND_NAME);
const borderColor =
- hasPending || isShellCommand ? theme.status.warning : theme.border.default;
+ hasPending || isShellCommand ? Colors.AccentYellow : Colors.Gray;
const staticHeight = /* border */ 2 + /* marginBottom */ 1;
// This is a bit of a magic number, but it accounts for the border and
diff --git a/packages/cli/src/ui/components/messages/ToolMessage.tsx b/packages/cli/src/ui/components/messages/ToolMessage.tsx
index bf82c400..e1eb75b8 100644
--- a/packages/cli/src/ui/components/messages/ToolMessage.tsx
+++ b/packages/cli/src/ui/components/messages/ToolMessage.tsx
@@ -8,7 +8,7 @@ import React from 'react';
import { Box, Text } from 'ink';
import { IndividualToolCallDisplay, ToolCallStatus } from '../../types.js';
import { DiffRenderer } from './DiffRenderer.js';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
import { MarkdownDisplay } from '../../utils/MarkdownDisplay.js';
import { GeminiRespondingSpinner } from '../GeminiRespondingSpinner.js';
import { MaxSizedBox } from '../shared/MaxSizedBox.js';
@@ -90,9 +90,7 @@ export const ToolMessage: React.FC<ToolMessageProps> = ({
{typeof resultDisplay === 'string' && !renderOutputAsMarkdown && (
<MaxSizedBox maxHeight={availableHeight} maxWidth={childWidth}>
<Box>
- <Text wrap="wrap" color={theme.text.primary}>
- {resultDisplay}
- </Text>
+ <Text wrap="wrap">{resultDisplay}</Text>
</Box>
</MaxSizedBox>
)}
@@ -120,7 +118,7 @@ const ToolStatusIndicator: React.FC<ToolStatusIndicatorProps> = ({
}) => (
<Box minWidth={STATUS_INDICATOR_WIDTH}>
{status === ToolCallStatus.Pending && (
- <Text color={theme.status.success}>o</Text>
+ <Text color={Colors.AccentGreen}>o</Text>
)}
{status === ToolCallStatus.Executing && (
<GeminiRespondingSpinner
@@ -129,18 +127,18 @@ const ToolStatusIndicator: React.FC<ToolStatusIndicatorProps> = ({
/>
)}
{status === ToolCallStatus.Success && (
- <Text color={theme.status.success}>✔</Text>
+ <Text color={Colors.AccentGreen}>✔</Text>
)}
{status === ToolCallStatus.Confirming && (
- <Text color={theme.status.warning}>?</Text>
+ <Text color={Colors.AccentYellow}>?</Text>
)}
{status === ToolCallStatus.Canceled && (
- <Text color={theme.status.warning} bold>
+ <Text color={Colors.AccentYellow} bold>
-
</Text>
)}
{status === ToolCallStatus.Error && (
- <Text color={theme.status.error} bold>
+ <Text color={Colors.AccentRed} bold>
x
</Text>
)}
@@ -162,11 +160,11 @@ const ToolInfo: React.FC<ToolInfo> = ({
const nameColor = React.useMemo<string>(() => {
switch (emphasis) {
case 'high':
- return theme.text.primary;
+ return Colors.Foreground;
case 'medium':
- return theme.text.primary;
+ return Colors.Foreground;
case 'low':
- return theme.text.secondary;
+ return Colors.Gray;
default: {
const exhaustiveCheck: never = emphasis;
return exhaustiveCheck;
@@ -178,19 +176,18 @@ const ToolInfo: React.FC<ToolInfo> = ({
<Text
wrap="truncate-end"
strikethrough={status === ToolCallStatus.Canceled}
- color={theme.text.primary}
>
<Text color={nameColor} bold>
{name}
</Text>{' '}
- <Text color={theme.text.secondary}>{description}</Text>
+ <Text color={Colors.Gray}>{description}</Text>
</Text>
</Box>
);
};
const TrailingIndicator: React.FC = () => (
- <Text color={theme.text.primary} wrap="truncate">
+ <Text color={Colors.Foreground} wrap="truncate">
{' '}
</Text>
diff --git a/packages/cli/src/ui/components/messages/UserMessage.tsx b/packages/cli/src/ui/components/messages/UserMessage.tsx
index f9a6f7a5..332cb0f4 100644
--- a/packages/cli/src/ui/components/messages/UserMessage.tsx
+++ b/packages/cli/src/ui/components/messages/UserMessage.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text, Box } from 'ink';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
interface UserMessageProps {
text: string;
@@ -17,8 +17,8 @@ export const UserMessage: React.FC<UserMessageProps> = ({ text }) => {
const prefixWidth = prefix.length;
const isSlashCommand = text.startsWith('/');
- const textColor = isSlashCommand ? theme.text.accent : theme.text.secondary;
- const borderColor = isSlashCommand ? theme.text.accent : theme.border.default;
+ const textColor = isSlashCommand ? Colors.AccentPurple : Colors.Gray;
+ const borderColor = isSlashCommand ? Colors.AccentPurple : Colors.Gray;
return (
<Box
diff --git a/packages/cli/src/ui/components/messages/UserShellMessage.tsx b/packages/cli/src/ui/components/messages/UserShellMessage.tsx
index 57b917d0..946ca7e7 100644
--- a/packages/cli/src/ui/components/messages/UserShellMessage.tsx
+++ b/packages/cli/src/ui/components/messages/UserShellMessage.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Box, Text } from 'ink';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
interface UserShellMessageProps {
text: string;
@@ -18,8 +18,8 @@ export const UserShellMessage: React.FC<UserShellMessageProps> = ({ text }) => {
return (
<Box>
- <Text color={theme.text.accent}>$ </Text>
- <Text color={theme.text.primary}>{commandToDisplay}</Text>
+ <Text color={Colors.AccentCyan}>$ </Text>
+ <Text>{commandToDisplay}</Text>
</Box>
);
};
diff --git a/packages/cli/src/ui/components/shared/MaxSizedBox.tsx b/packages/cli/src/ui/components/shared/MaxSizedBox.tsx
index 4c8b0862..346472bf 100644
--- a/packages/cli/src/ui/components/shared/MaxSizedBox.tsx
+++ b/packages/cli/src/ui/components/shared/MaxSizedBox.tsx
@@ -7,7 +7,7 @@
import React, { Fragment, useEffect, useId } from 'react';
import { Box, Text } from 'ink';
import stringWidth from 'string-width';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
import { toCodePoints } from '../../utils/textUtils.js';
import { useOverflowActions } from '../../contexts/OverflowContext.js';
@@ -173,7 +173,6 @@ export const MaxSizedBox: React.FC<MaxSizedBoxProps> = ({
<Box key={index}>
{line.length > 0 ? (
line.map((segment, segIndex) => (
- // Avoid adding color styles to this <Text> element, breaks code colorization
<Text key={segIndex} {...segment.props}>
{segment.text}
</Text>
@@ -187,14 +186,14 @@ export const MaxSizedBox: React.FC<MaxSizedBoxProps> = ({
return (
<Box flexDirection="column" width={maxWidth} flexShrink={0}>
{totalHiddenLines > 0 && overflowDirection === 'top' && (
- <Text color={theme.text.secondary} wrap="truncate">
+ <Text color={Colors.Gray} wrap="truncate">
... first {totalHiddenLines} line{totalHiddenLines === 1 ? '' : 's'}{' '}
hidden ...
</Text>
)}
{visibleLines}
{totalHiddenLines > 0 && overflowDirection === 'bottom' && (
- <Text color={theme.text.secondary} wrap="truncate">
+ <Text color={Colors.Gray} wrap="truncate">
... last {totalHiddenLines} line{totalHiddenLines === 1 ? '' : 's'}{' '}
hidden ...
</Text>
diff --git a/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx b/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
index b6c78feb..746744e5 100644
--- a/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
+++ b/packages/cli/src/ui/components/shared/RadioButtonSelect.tsx
@@ -6,7 +6,7 @@
import React, { useEffect, useState, useRef } from 'react';
import { Text, Box } from 'ink';
-import { theme } from '../../semantic-colors.js';
+import { Colors } from '../../colors.js';
import { useKeypress } from '../../hooks/useKeypress.js';
/**
@@ -164,9 +164,7 @@ export function RadioButtonSelect<T>({
return (
<Box flexDirection="column">
{showScrollArrows && (
- <Text
- color={scrollOffset > 0 ? theme.text.primary : theme.text.secondary}
- >
+ <Text color={scrollOffset > 0 ? Colors.Foreground : Colors.Gray}>
</Text>
)}
@@ -174,18 +172,18 @@ export function RadioButtonSelect<T>({
const itemIndex = scrollOffset + index;
const isSelected = activeIndex === itemIndex;
- let textColor = theme.text.primary;
- let numberColor = theme.text.primary;
+ let textColor = Colors.Foreground;
+ let numberColor = Colors.Foreground;
if (isSelected) {
- textColor = theme.status.success;
- numberColor = theme.status.success;
+ textColor = Colors.AccentGreen;
+ numberColor = Colors.AccentGreen;
} else if (item.disabled) {
- textColor = theme.text.secondary;
- numberColor = theme.text.secondary;
+ textColor = Colors.Gray;
+ numberColor = Colors.Gray;
}
if (!showNumbers) {
- numberColor = theme.text.secondary;
+ numberColor = Colors.Gray;
}
const numberColumnWidth = String(items.length).length;
@@ -196,9 +194,7 @@ export function RadioButtonSelect<T>({
return (
<Box key={item.label} alignItems="center">
<Box minWidth={2} flexShrink={0}>
- <Text
- color={isSelected ? theme.status.success : theme.text.primary}
- >
+ <Text color={isSelected ? Colors.AccentGreen : Colors.Foreground}>
{isSelected ? '●' : ' '}
</Text>
</Box>
@@ -212,9 +208,7 @@ export function RadioButtonSelect<T>({
{item.themeNameDisplay && item.themeTypeDisplay ? (
<Text color={textColor} wrap="truncate">
{item.themeNameDisplay}{' '}
- <Text color={theme.text.secondary}>
- {item.themeTypeDisplay}
- </Text>
+ <Text color={Colors.Gray}>{item.themeTypeDisplay}</Text>
</Text>
) : (
<Text color={textColor} wrap="truncate">
@@ -228,8 +222,8 @@ export function RadioButtonSelect<T>({
<Text
color={
scrollOffset + maxItemsToShow < items.length
- ? theme.text.primary
- : theme.text.secondary
+ ? Colors.Foreground
+ : Colors.Gray
}
>
diff --git a/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.tsx b/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.tsx
index f79bb4d6..d4c13097 100644
--- a/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.tsx
+++ b/packages/cli/src/ui/privacy/CloudFreePrivacyNotice.tsx
@@ -9,7 +9,7 @@ import { RadioButtonSelect } from '../components/shared/RadioButtonSelect.js';
import { usePrivacySettings } from '../hooks/usePrivacySettings.js';
import { CloudPaidPrivacyNotice } from './CloudPaidPrivacyNotice.js';
import { Config } from '@google/gemini-cli-core';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
interface CloudFreePrivacyNoticeProps {
@@ -34,16 +34,16 @@ export const CloudFreePrivacyNotice = ({
);
if (privacyState.isLoading) {
- return <Text color={theme.text.secondary}>Loading...</Text>;
+ return <Text color={Colors.Gray}>Loading...</Text>;
}
if (privacyState.error) {
return (
<Box flexDirection="column" marginY={1}>
- <Text color={theme.status.error}>
+ <Text color={Colors.AccentRed}>
Error loading Opt-in settings: {privacyState.error}
</Text>
- <Text color={theme.text.secondary}>Press Esc to exit.</Text>
+ <Text color={Colors.Gray}>Press Esc to exit.</Text>
</Box>
);
}
@@ -59,17 +59,17 @@ export const CloudFreePrivacyNotice = ({
return (
<Box flexDirection="column" marginY={1}>
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
Gemini Code Assist for Individuals Privacy Notice
</Text>
<Newline />
- <Text color={theme.text.primary}>
+ <Text>
This notice and our Privacy Policy
- <Text color={theme.text.link}>[1]</Text> describe how Gemini Code Assist
- handles your data. Please read them carefully.
+ <Text color={Colors.AccentBlue}>[1]</Text> describe how Gemini Code
+ Assist handles your data. Please read them carefully.
</Text>
<Newline />
- <Text color={theme.text.primary}>
+ <Text>
When you use Gemini Code Assist for individuals with Gemini CLI, Google
collects your prompts, related code, generated output, code edits,
related feature usage information, and your feedback to provide,
@@ -77,7 +77,7 @@ export const CloudFreePrivacyNotice = ({
technologies.
</Text>
<Newline />
- <Text color={theme.text.primary}>
+ <Text>
To help with quality and improve our products (such as generative
machine-learning models), human reviewers may read, annotate, and
process the data collected above. We take steps to protect your privacy
@@ -90,7 +90,7 @@ export const CloudFreePrivacyNotice = ({
</Text>
<Newline />
<Box flexDirection="column">
- <Text color={theme.text.primary}>
+ <Text>
Allow Google to use this data to develop and improve our products?
</Text>
<RadioButtonSelect
@@ -106,14 +106,12 @@ export const CloudFreePrivacyNotice = ({
/>
</Box>
<Newline />
- <Text color={theme.text.primary}>
- <Text color={theme.text.link}>[1]</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentBlue}>[1]</Text>{' '}
https://policies.google.com/privacy
</Text>
<Newline />
- <Text color={theme.text.secondary}>
- Press Enter to choose an option and exit.
- </Text>
+ <Text color={Colors.Gray}>Press Enter to choose an option and exit.</Text>
</Box>
);
};
diff --git a/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.tsx b/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.tsx
index ce640308..f0adbb68 100644
--- a/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.tsx
+++ b/packages/cli/src/ui/privacy/CloudPaidPrivacyNotice.tsx
@@ -5,7 +5,7 @@
*/
import { Box, Newline, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
interface CloudPaidPrivacyNoticeProps {
@@ -26,14 +26,14 @@ export const CloudPaidPrivacyNotice = ({
return (
<Box flexDirection="column" marginBottom={1}>
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
Vertex AI Notice
</Text>
<Newline />
- <Text color={theme.text.primary}>
- Service Specific Terms<Text color={theme.text.link}>[1]</Text> are
+ <Text>
+ Service Specific Terms<Text color={Colors.AccentBlue}>[1]</Text> are
incorporated into the agreement under which Google has agreed to provide
- Google Cloud Platform<Text color={theme.status.success}>[2]</Text> to
+ Google Cloud Platform<Text color={Colors.AccentGreen}>[2]</Text> to
Customer (the “Agreement”). If the Agreement authorizes the resale or
supply of Google Cloud Platform under a Google Cloud partner or reseller
program, then except for in the section entitled “Partner-Specific
@@ -44,16 +44,16 @@ export const CloudPaidPrivacyNotice = ({
them in the Agreement.
</Text>
<Newline />
- <Text color={theme.text.primary}>
- <Text color={theme.text.link}>[1]</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentBlue}>[1]</Text>{' '}
https://cloud.google.com/terms/service-terms
</Text>
- <Text color={theme.text.primary}>
- <Text color={theme.status.success}>[2]</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentGreen}>[2]</Text>{' '}
https://cloud.google.com/terms/services
</Text>
<Newline />
- <Text color={theme.text.secondary}>Press Esc to exit.</Text>
+ <Text color={Colors.Gray}>Press Esc to exit.</Text>
</Box>
);
};
diff --git a/packages/cli/src/ui/privacy/GeminiPrivacyNotice.tsx b/packages/cli/src/ui/privacy/GeminiPrivacyNotice.tsx
index 1f4015b5..c0eaa74f 100644
--- a/packages/cli/src/ui/privacy/GeminiPrivacyNotice.tsx
+++ b/packages/cli/src/ui/privacy/GeminiPrivacyNotice.tsx
@@ -5,7 +5,7 @@
*/
import { Box, Newline, Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { useKeypress } from '../hooks/useKeypress.js';
interface GeminiPrivacyNoticeProps {
@@ -24,39 +24,39 @@ export const GeminiPrivacyNotice = ({ onExit }: GeminiPrivacyNoticeProps) => {
return (
<Box flexDirection="column" marginBottom={1}>
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentPurple}>
Gemini API Key Notice
</Text>
<Newline />
- <Text color={theme.text.primary}>
- By using the Gemini API<Text color={theme.text.link}>[1]</Text>, Google
- AI Studio
- <Text color={theme.status.error}>[2]</Text>, and the other Google
+ <Text>
+ By using the Gemini API<Text color={Colors.AccentBlue}>[1]</Text>,
+ Google AI Studio
+ <Text color={Colors.AccentRed}>[2]</Text>, and the other Google
developer services that reference these terms (collectively, the
&quot;APIs&quot; or &quot;Services&quot;), you are agreeing to Google
APIs Terms of Service (the &quot;API Terms&quot;)
- <Text color={theme.status.success}>[3]</Text>, and the Gemini API
+ <Text color={Colors.AccentGreen}>[3]</Text>, and the Gemini API
Additional Terms of Service (the &quot;Additional Terms&quot;)
- <Text color={theme.text.accent}>[4]</Text>.
+ <Text color={Colors.AccentPurple}>[4]</Text>.
</Text>
<Newline />
- <Text color={theme.text.primary}>
- <Text color={theme.text.link}>[1]</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentBlue}>[1]</Text>{' '}
https://ai.google.dev/docs/gemini_api_overview
</Text>
- <Text color={theme.text.primary}>
- <Text color={theme.status.error}>[2]</Text> https://aistudio.google.com/
+ <Text>
+ <Text color={Colors.AccentRed}>[2]</Text> https://aistudio.google.com/
</Text>
- <Text color={theme.text.primary}>
- <Text color={theme.status.success}>[3]</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentGreen}>[3]</Text>{' '}
https://developers.google.com/terms
</Text>
- <Text color={theme.text.primary}>
- <Text color={theme.text.accent}>[4]</Text>{' '}
+ <Text>
+ <Text color={Colors.AccentPurple}>[4]</Text>{' '}
https://ai.google.dev/gemini-api/terms
</Text>
<Newline />
- <Text color={theme.text.secondary}>Press Esc to exit.</Text>
+ <Text color={Colors.Gray}>Press Esc to exit.</Text>
</Box>
);
};
diff --git a/packages/cli/src/ui/themes/no-color.ts b/packages/cli/src/ui/themes/no-color.ts
index 4d5dc1bb..161b407e 100644
--- a/packages/cli/src/ui/themes/no-color.ts
+++ b/packages/cli/src/ui/themes/no-color.ts
@@ -43,6 +43,8 @@ const noColorSemanticColors: SemanticColors = {
focused: '',
},
ui: {
+ comment: '',
+ symbol: '',
gradient: [],
},
status: {
diff --git a/packages/cli/src/ui/themes/semantic-tokens.ts b/packages/cli/src/ui/themes/semantic-tokens.ts
index a2079934..56430304 100644
--- a/packages/cli/src/ui/themes/semantic-tokens.ts
+++ b/packages/cli/src/ui/themes/semantic-tokens.ts
@@ -25,6 +25,8 @@ export interface SemanticColors {
focused: string;
};
ui: {
+ comment: string;
+ symbol: string;
gradient: string[] | undefined;
};
status: {
@@ -53,6 +55,8 @@ export const lightSemanticColors: SemanticColors = {
focused: lightTheme.AccentBlue,
},
ui: {
+ comment: lightTheme.Comment,
+ symbol: lightTheme.Gray,
gradient: lightTheme.GradientColors,
},
status: {
@@ -81,6 +85,8 @@ export const darkSemanticColors: SemanticColors = {
focused: darkTheme.AccentBlue,
},
ui: {
+ comment: darkTheme.Comment,
+ symbol: darkTheme.Gray,
gradient: darkTheme.GradientColors,
},
status: {
@@ -109,6 +115,8 @@ export const ansiSemanticColors: SemanticColors = {
focused: ansiTheme.AccentBlue,
},
ui: {
+ comment: ansiTheme.Comment,
+ symbol: ansiTheme.Gray,
gradient: ansiTheme.GradientColors,
},
status: {
diff --git a/packages/cli/src/ui/themes/theme.ts b/packages/cli/src/ui/themes/theme.ts
index 40900deb..e46c7f48 100644
--- a/packages/cli/src/ui/themes/theme.ts
+++ b/packages/cli/src/ui/themes/theme.ts
@@ -235,7 +235,7 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
customTheme.background?.diff?.added ?? customTheme.DiffAdded ?? '',
DiffRemoved:
customTheme.background?.diff?.removed ?? customTheme.DiffRemoved ?? '',
- Comment: customTheme.text?.secondary ?? customTheme.Comment ?? '',
+ Comment: customTheme.ui?.comment ?? customTheme.Comment ?? '',
Gray: customTheme.text?.secondary ?? customTheme.Gray ?? '',
GradientColors: customTheme.ui?.gradient ?? customTheme.GradientColors,
};
@@ -397,6 +397,8 @@ export function createCustomTheme(customTheme: CustomTheme): Theme {
focused: colors.AccentBlue,
},
ui: {
+ comment: colors.Comment,
+ symbol: colors.Gray,
gradient: colors.GradientColors,
},
status: {
diff --git a/packages/cli/src/ui/utils/CodeColorizer.tsx b/packages/cli/src/ui/utils/CodeColorizer.tsx
index 047e7bae..b183d556 100644
--- a/packages/cli/src/ui/utils/CodeColorizer.tsx
+++ b/packages/cli/src/ui/utils/CodeColorizer.tsx
@@ -21,7 +21,6 @@ import {
MINIMUM_MAX_HEIGHT,
} from '../components/shared/MaxSizedBox.js';
import { LoadedSettings } from '../../config/settings.js';
-import { theme as semanticTheme } from '../semantic-colors.js';
// Configure theming and parsing utilities.
const lowlight = createLowlight(common);
@@ -172,7 +171,7 @@ export function colorizeCode(
return (
<Box key={index}>
{showLineNumbers && (
- <Text color={semanticTheme.text.secondary}>
+ <Text color={activeTheme.colors.Gray}>
{`${String(index + 1 + hiddenLinesCount).padStart(
padWidth,
' ',
@@ -209,7 +208,7 @@ export function colorizeCode(
{`${String(index + 1).padStart(padWidth, ' ')} `}
</Text>
)}
- <Text color={semanticTheme.text.secondary}>{line}</Text>
+ <Text color={activeTheme.colors.Gray}>{line}</Text>
</Box>
))}
</MaxSizedBox>
diff --git a/packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx b/packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx
index 28c47b83..ff8d6257 100644
--- a/packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx
+++ b/packages/cli/src/ui/utils/InlineMarkdownRenderer.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import stringWidth from 'string-width';
// Constants for Markdown parsing
@@ -31,7 +31,7 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
while ((match = inlineRegex.exec(text)) !== null) {
if (match.index > lastIndex) {
nodes.push(
- <Text key={`t-${lastIndex}`} color={theme.text.primary}>
+ <Text key={`t-${lastIndex}`}>
{text.slice(lastIndex, match.index)}
</Text>,
);
@@ -48,7 +48,7 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
fullMatch.length > BOLD_MARKER_LENGTH * 2
) {
renderedNode = (
- <Text key={key} bold color={theme.text.primary}>
+ <Text key={key} bold>
{fullMatch.slice(BOLD_MARKER_LENGTH, -BOLD_MARKER_LENGTH)}
</Text>
);
@@ -60,13 +60,13 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
!/\w/.test(
text.substring(inlineRegex.lastIndex, inlineRegex.lastIndex + 1),
) &&
- !/\S[./]/.test(text.substring(match.index - 2, match.index)) &&
- !/[./]\S/.test(
+ !/\S[./\\]/.test(text.substring(match.index - 2, match.index)) &&
+ !/[./\\]\S/.test(
text.substring(inlineRegex.lastIndex, inlineRegex.lastIndex + 2),
)
) {
renderedNode = (
- <Text key={key} italic color={theme.text.primary}>
+ <Text key={key} italic>
{fullMatch.slice(ITALIC_MARKER_LENGTH, -ITALIC_MARKER_LENGTH)}
</Text>
);
@@ -76,7 +76,7 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
fullMatch.length > STRIKETHROUGH_MARKER_LENGTH * 2
) {
renderedNode = (
- <Text key={key} strikethrough color={theme.text.primary}>
+ <Text key={key} strikethrough>
{fullMatch.slice(
STRIKETHROUGH_MARKER_LENGTH,
-STRIKETHROUGH_MARKER_LENGTH,
@@ -91,7 +91,7 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
const codeMatch = fullMatch.match(/^(`+)(.+?)\1$/s);
if (codeMatch && codeMatch[2]) {
renderedNode = (
- <Text key={key} color={theme.text.accent}>
+ <Text key={key} color={Colors.AccentPurple}>
{codeMatch[2]}
</Text>
);
@@ -106,9 +106,9 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
const linkText = linkMatch[1];
const url = linkMatch[2];
renderedNode = (
- <Text key={key} color={theme.text.primary}>
+ <Text key={key}>
{linkText}
- <Text color={theme.text.link}> ({url})</Text>
+ <Text color={Colors.AccentBlue}> ({url})</Text>
</Text>
);
}
@@ -116,10 +116,10 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
fullMatch.startsWith('<u>') &&
fullMatch.endsWith('</u>') &&
fullMatch.length >
- UNDERLINE_TAG_START_LENGTH + UNDERLINE_TAG_END_LENGTH - 1
+ UNDERLINE_TAG_START_LENGTH + UNDERLINE_TAG_END_LENGTH - 1 // -1 because length is compared to combined length of start and end tags
) {
renderedNode = (
- <Text key={key} underline color={theme.text.primary}>
+ <Text key={key} underline>
{fullMatch.slice(
UNDERLINE_TAG_START_LENGTH,
-UNDERLINE_TAG_END_LENGTH,
@@ -132,22 +132,12 @@ const RenderInlineInternal: React.FC<RenderInlineProps> = ({ text }) => {
renderedNode = null;
}
- nodes.push(
- renderedNode ?? (
- <Text key={key} color={theme.text.primary}>
- {fullMatch}
- </Text>
- ),
- );
+ nodes.push(renderedNode ?? <Text key={key}>{fullMatch}</Text>);
lastIndex = inlineRegex.lastIndex;
}
if (lastIndex < text.length) {
- nodes.push(
- <Text key={`t-${lastIndex}`} color={theme.text.primary}>
- {text.slice(lastIndex)}
- </Text>,
- );
+ nodes.push(<Text key={`t-${lastIndex}`}>{text.slice(lastIndex)}</Text>);
}
return <>{nodes.filter((node) => node !== null)}</>;
diff --git a/packages/cli/src/ui/utils/MarkdownDisplay.tsx b/packages/cli/src/ui/utils/MarkdownDisplay.tsx
index d656dbc8..7568e1f8 100644
--- a/packages/cli/src/ui/utils/MarkdownDisplay.tsx
+++ b/packages/cli/src/ui/utils/MarkdownDisplay.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text, Box } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { colorizeCode } from './CodeColorizer.js';
import { TableRenderer } from './TableRenderer.js';
import { RenderInline } from './InlineMarkdownRenderer.js';
@@ -115,7 +115,7 @@ const MarkdownDisplayInternal: React.FC<MarkdownDisplayProps> = ({
// Not a table, treat as regular text
addContentBlock(
<Box key={key}>
- <Text wrap="wrap" color={theme.text.primary}>
+ <Text wrap="wrap">
<RenderInline text={line} />
</Text>
</Box>,
@@ -154,7 +154,7 @@ const MarkdownDisplayInternal: React.FC<MarkdownDisplayProps> = ({
if (line.trim().length > 0) {
addContentBlock(
<Box key={key}>
- <Text wrap="wrap" color={theme.text.primary}>
+ <Text wrap="wrap">
<RenderInline text={line} />
</Text>
</Box>,
@@ -173,35 +173,35 @@ const MarkdownDisplayInternal: React.FC<MarkdownDisplayProps> = ({
switch (level) {
case 1:
headerNode = (
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentCyan}>
<RenderInline text={headerText} />
</Text>
);
break;
case 2:
headerNode = (
- <Text bold color={theme.text.link}>
+ <Text bold color={Colors.AccentBlue}>
<RenderInline text={headerText} />
</Text>
);
break;
case 3:
headerNode = (
- <Text bold color={theme.text.primary}>
+ <Text bold>
<RenderInline text={headerText} />
</Text>
);
break;
case 4:
headerNode = (
- <Text italic color={theme.text.secondary}>
+ <Text italic color={Colors.Gray}>
<RenderInline text={headerText} />
</Text>
);
break;
default:
headerNode = (
- <Text color={theme.text.primary}>
+ <Text>
<RenderInline text={headerText} />
</Text>
);
@@ -245,7 +245,7 @@ const MarkdownDisplayInternal: React.FC<MarkdownDisplayProps> = ({
} else {
addContentBlock(
<Box key={key}>
- <Text wrap="wrap" color={theme.text.primary}>
+ <Text wrap="wrap">
<RenderInline text={line} />
</Text>
</Box>,
@@ -314,9 +314,7 @@ const RenderCodeBlockInternal: React.FC<RenderCodeBlockProps> = ({
// Not enough space to even show the message meaningfully
return (
<Box paddingLeft={CODE_BLOCK_PREFIX_PADDING}>
- <Text color={theme.text.secondary}>
- ... code is being written ...
- </Text>
+ <Text color={Colors.Gray}>... code is being written ...</Text>
</Box>
);
}
@@ -332,7 +330,7 @@ const RenderCodeBlockInternal: React.FC<RenderCodeBlockProps> = ({
return (
<Box paddingLeft={CODE_BLOCK_PREFIX_PADDING} flexDirection="column">
{colorizedTruncatedCode}
- <Text color={theme.text.secondary}>... generating more ...</Text>
+ <Text color={Colors.Gray}>... generating more ...</Text>
</Box>
);
}
@@ -385,10 +383,10 @@ const RenderListItemInternal: React.FC<RenderListItemProps> = ({
flexDirection="row"
>
<Box width={prefixWidth}>
- <Text color={theme.text.accent}>{prefix}</Text>
+ <Text>{prefix}</Text>
</Box>
<Box flexGrow={LIST_ITEM_TEXT_FLEX_GROW}>
- <Text wrap="wrap" color={theme.text.primary}>
+ <Text wrap="wrap">
<RenderInline text={itemText} />
</Text>
</Box>
diff --git a/packages/cli/src/ui/utils/TableRenderer.tsx b/packages/cli/src/ui/utils/TableRenderer.tsx
index 478a0893..2ec19549 100644
--- a/packages/cli/src/ui/utils/TableRenderer.tsx
+++ b/packages/cli/src/ui/utils/TableRenderer.tsx
@@ -6,7 +6,7 @@
import React from 'react';
import { Text, Box } from 'ink';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
import { RenderInline, getPlainTextLength } from './InlineMarkdownRenderer.js';
interface TableRendererProps {
@@ -87,9 +87,9 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
const paddingNeeded = Math.max(0, contentWidth - actualDisplayWidth);
return (
- <Text color={theme.text.primary}>
+ <Text>
{isHeader ? (
- <Text bold color={theme.text.accent}>
+ <Text bold color={Colors.AccentCyan}>
<RenderInline text={cellContent} />
</Text>
) : (
@@ -112,7 +112,7 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
const borderParts = adjustedWidths.map((w) => char.horizontal.repeat(w));
const border = char.left + borderParts.join(char.middle) + char.right;
- return <Text color={theme.text.primary}>{border}</Text>;
+ return <Text>{border}</Text>;
};
// Helper function to render a table row
@@ -123,7 +123,7 @@ export const TableRenderer: React.FC<TableRendererProps> = ({
});
return (
- <Text color={theme.text.primary}>
+ <Text>
│{' '}
{renderedCells.map((cell, index) => (
<React.Fragment key={index}>
diff --git a/packages/cli/src/ui/utils/displayUtils.test.ts b/packages/cli/src/ui/utils/displayUtils.test.ts
index 64b0a727..7dd9f0e8 100644
--- a/packages/cli/src/ui/utils/displayUtils.test.ts
+++ b/packages/cli/src/ui/utils/displayUtils.test.ts
@@ -14,7 +14,7 @@ import {
CACHE_EFFICIENCY_HIGH,
CACHE_EFFICIENCY_MEDIUM,
} from './displayUtils.js';
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
describe('displayUtils', () => {
describe('getStatusColor', () => {
@@ -24,24 +24,24 @@ describe('displayUtils', () => {
};
it('should return green for values >= green threshold', () => {
- expect(getStatusColor(90, thresholds)).toBe(theme.status.success);
- expect(getStatusColor(80, thresholds)).toBe(theme.status.success);
+ expect(getStatusColor(90, thresholds)).toBe(Colors.AccentGreen);
+ expect(getStatusColor(80, thresholds)).toBe(Colors.AccentGreen);
});
it('should return yellow for values < green and >= yellow threshold', () => {
- expect(getStatusColor(79, thresholds)).toBe(theme.status.warning);
- expect(getStatusColor(50, thresholds)).toBe(theme.status.warning);
+ expect(getStatusColor(79, thresholds)).toBe(Colors.AccentYellow);
+ expect(getStatusColor(50, thresholds)).toBe(Colors.AccentYellow);
});
it('should return red for values < yellow threshold', () => {
- expect(getStatusColor(49, thresholds)).toBe(theme.status.error);
- expect(getStatusColor(0, thresholds)).toBe(theme.status.error);
+ expect(getStatusColor(49, thresholds)).toBe(Colors.AccentRed);
+ expect(getStatusColor(0, thresholds)).toBe(Colors.AccentRed);
});
it('should return defaultColor for values < yellow threshold when provided', () => {
expect(
- getStatusColor(49, thresholds, { defaultColor: theme.text.primary }),
- ).toBe(theme.text.primary);
+ getStatusColor(49, thresholds, { defaultColor: Colors.Foreground }),
+ ).toBe(Colors.Foreground);
});
});
diff --git a/packages/cli/src/ui/utils/displayUtils.ts b/packages/cli/src/ui/utils/displayUtils.ts
index 6f6c9209..a52c6ff0 100644
--- a/packages/cli/src/ui/utils/displayUtils.ts
+++ b/packages/cli/src/ui/utils/displayUtils.ts
@@ -4,7 +4,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
-import { theme } from '../semantic-colors.js';
+import { Colors } from '../colors.js';
// --- Thresholds ---
export const TOOL_SUCCESS_RATE_HIGH = 95;
@@ -23,10 +23,10 @@ export const getStatusColor = (
options: { defaultColor?: string } = {},
) => {
if (value >= thresholds.green) {
- return theme.status.success;
+ return Colors.AccentGreen;
}
if (value >= thresholds.yellow) {
- return theme.status.warning;
+ return Colors.AccentYellow;
}
- return options.defaultColor || theme.status.error;
+ return options.defaultColor || Colors.AccentRed;
};