Add visual cues for nightly version (#3701)
Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
parent
4197f30278
commit
448838dea8
|
@ -26,6 +26,7 @@ import { getUserStartupWarnings } from './utils/userStartupWarnings.js';
|
||||||
import { runNonInteractive } from './nonInteractiveCli.js';
|
import { runNonInteractive } from './nonInteractiveCli.js';
|
||||||
import { loadExtensions, Extension } from './config/extension.js';
|
import { loadExtensions, Extension } from './config/extension.js';
|
||||||
import { cleanupCheckpoints } from './utils/cleanup.js';
|
import { cleanupCheckpoints } from './utils/cleanup.js';
|
||||||
|
import { getCliVersion } from './utils/version.js';
|
||||||
import {
|
import {
|
||||||
ApprovalMode,
|
ApprovalMode,
|
||||||
Config,
|
Config,
|
||||||
|
@ -183,6 +184,7 @@ export async function main() {
|
||||||
|
|
||||||
// Render UI, passing necessary config values. Check that there is no command line question.
|
// Render UI, passing necessary config values. Check that there is no command line question.
|
||||||
if (process.stdin.isTTY && input?.length === 0) {
|
if (process.stdin.isTTY && input?.length === 0) {
|
||||||
|
const version = await getCliVersion();
|
||||||
setWindowTitle(basename(workspaceRoot), settings);
|
setWindowTitle(basename(workspaceRoot), settings);
|
||||||
render(
|
render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
@ -190,6 +192,7 @@ export async function main() {
|
||||||
config={config}
|
config={config}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
startupWarnings={startupWarnings}
|
startupWarnings={startupWarnings}
|
||||||
|
version={version}
|
||||||
/>
|
/>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
{ exitOnCtrlC: false },
|
{ exitOnCtrlC: false },
|
||||||
|
|
|
@ -186,6 +186,7 @@ vi.mock('./components/Tips.js', () => ({
|
||||||
describe('App UI', () => {
|
describe('App UI', () => {
|
||||||
let mockConfig: MockServerConfig;
|
let mockConfig: MockServerConfig;
|
||||||
let mockSettings: LoadedSettings;
|
let mockSettings: LoadedSettings;
|
||||||
|
let mockVersion: string;
|
||||||
let currentUnmount: (() => void) | undefined;
|
let currentUnmount: (() => void) | undefined;
|
||||||
|
|
||||||
const createMockSettings = (
|
const createMockSettings = (
|
||||||
|
@ -229,6 +230,7 @@ describe('App UI', () => {
|
||||||
cwd: '/tmp',
|
cwd: '/tmp',
|
||||||
model: 'model',
|
model: 'model',
|
||||||
}) as unknown as MockServerConfig;
|
}) as unknown as MockServerConfig;
|
||||||
|
mockVersion = '0.0.0-test';
|
||||||
|
|
||||||
// Ensure the getShowMemoryUsage mock function is specifically set up if not covered by constructor mock
|
// Ensure the getShowMemoryUsage mock function is specifically set up if not covered by constructor mock
|
||||||
if (!mockConfig.getShowMemoryUsage) {
|
if (!mockConfig.getShowMemoryUsage) {
|
||||||
|
@ -258,6 +260,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -274,6 +277,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -293,6 +297,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -315,6 +320,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -334,6 +340,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -353,6 +360,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -372,6 +380,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -392,6 +401,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -404,6 +414,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -422,6 +433,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -440,6 +452,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -469,6 +482,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
@ -483,6 +497,7 @@ describe('App UI', () => {
|
||||||
<App
|
<App
|
||||||
config={mockConfig as unknown as ServerConfig}
|
config={mockConfig as unknown as ServerConfig}
|
||||||
settings={mockSettings}
|
settings={mockSettings}
|
||||||
|
version={mockVersion}
|
||||||
/>,
|
/>,
|
||||||
);
|
);
|
||||||
currentUnmount = unmount;
|
currentUnmount = unmount;
|
||||||
|
|
|
@ -84,6 +84,7 @@ interface AppProps {
|
||||||
config: Config;
|
config: Config;
|
||||||
settings: LoadedSettings;
|
settings: LoadedSettings;
|
||||||
startupWarnings?: string[];
|
startupWarnings?: string[];
|
||||||
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AppWrapper = (props: AppProps) => (
|
export const AppWrapper = (props: AppProps) => (
|
||||||
|
@ -92,10 +93,11 @@ export const AppWrapper = (props: AppProps) => (
|
||||||
</SessionStatsProvider>
|
</SessionStatsProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
const App = ({ config, settings, startupWarnings = [] }: AppProps) => {
|
const App = ({ config, settings, startupWarnings = [], version }: AppProps) => {
|
||||||
useBracketedPaste();
|
useBracketedPaste();
|
||||||
const [updateMessage, setUpdateMessage] = useState<string | null>(null);
|
const [updateMessage, setUpdateMessage] = useState<string | null>(null);
|
||||||
const { stdout } = useStdout();
|
const { stdout } = useStdout();
|
||||||
|
const nightly = version.includes('nightly');
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkForUpdates().then(setUpdateMessage);
|
checkForUpdates().then(setUpdateMessage);
|
||||||
|
@ -315,7 +317,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => {
|
||||||
⚡ To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
|
⚡ To continue accessing the ${currentModel} model today, consider using /auth to switch to using a paid API key from AI Studio at https://aistudio.google.com/apikey`;
|
||||||
} else {
|
} else {
|
||||||
// Default fallback message for other cases (like consecutive 429s)
|
// Default fallback message for other cases (like consecutive 429s)
|
||||||
message = `⚡ Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.
|
message = `⚡ Automatically switching from ${currentModel} to ${fallbackModel} for faster responses for the remainder of this session.
|
||||||
⚡ Possible reasons for this are that you have received multiple consecutive capacity errors or you have reached your daily ${currentModel} quota limit
|
⚡ Possible reasons for this are that you have received multiple consecutive capacity errors or you have reached your daily ${currentModel} quota limit
|
||||||
⚡ To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist
|
⚡ To increase your limits, upgrade to a Gemini Code Assist Standard or Enterprise plan with higher limits at https://goo.gle/set-up-gemini-code-assist
|
||||||
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
⚡ Or you can utilize a Gemini API Key. See: https://goo.gle/gemini-cli-docs-auth#gemini-api-key
|
||||||
|
@ -673,7 +675,11 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => {
|
||||||
key={staticKey}
|
key={staticKey}
|
||||||
items={[
|
items={[
|
||||||
<Box flexDirection="column" key="header">
|
<Box flexDirection="column" key="header">
|
||||||
<Header terminalWidth={terminalWidth} />
|
<Header
|
||||||
|
terminalWidth={terminalWidth}
|
||||||
|
version={version}
|
||||||
|
nightly={nightly}
|
||||||
|
/>
|
||||||
{!settings.merged.hideTips && <Tips config={config} />}
|
{!settings.merged.hideTips && <Tips config={config} />}
|
||||||
</Box>,
|
</Box>,
|
||||||
...history.map((h) => (
|
...history.map((h) => (
|
||||||
|
@ -931,6 +937,7 @@ const App = ({ config, settings, startupWarnings = [] }: AppProps) => {
|
||||||
config.getDebugMode() || config.getShowMemoryUsage()
|
config.getDebugMode() || config.getShowMemoryUsage()
|
||||||
}
|
}
|
||||||
promptTokenCount={sessionStats.lastPromptTokenCount}
|
promptTokenCount={sessionStats.lastPromptTokenCount}
|
||||||
|
nightly={nightly}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { Colors } from '../colors.js';
|
||||||
import { shortenPath, tildeifyPath, tokenLimit } from '@google/gemini-cli-core';
|
import { shortenPath, tildeifyPath, tokenLimit } from '@google/gemini-cli-core';
|
||||||
import { ConsoleSummaryDisplay } from './ConsoleSummaryDisplay.js';
|
import { ConsoleSummaryDisplay } from './ConsoleSummaryDisplay.js';
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
|
import Gradient from 'ink-gradient';
|
||||||
import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
|
import { MemoryUsageDisplay } from './MemoryUsageDisplay.js';
|
||||||
|
|
||||||
interface FooterProps {
|
interface FooterProps {
|
||||||
|
@ -23,6 +24,7 @@ interface FooterProps {
|
||||||
showErrorDetails: boolean;
|
showErrorDetails: boolean;
|
||||||
showMemoryUsage?: boolean;
|
showMemoryUsage?: boolean;
|
||||||
promptTokenCount: number;
|
promptTokenCount: number;
|
||||||
|
nightly: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Footer: React.FC<FooterProps> = ({
|
export const Footer: React.FC<FooterProps> = ({
|
||||||
|
@ -36,6 +38,7 @@ export const Footer: React.FC<FooterProps> = ({
|
||||||
showErrorDetails,
|
showErrorDetails,
|
||||||
showMemoryUsage,
|
showMemoryUsage,
|
||||||
promptTokenCount,
|
promptTokenCount,
|
||||||
|
nightly,
|
||||||
}) => {
|
}) => {
|
||||||
const limit = tokenLimit(model);
|
const limit = tokenLimit(model);
|
||||||
const percentage = promptTokenCount / limit;
|
const percentage = promptTokenCount / limit;
|
||||||
|
@ -43,10 +46,19 @@ export const Footer: React.FC<FooterProps> = ({
|
||||||
return (
|
return (
|
||||||
<Box marginTop={1} justifyContent="space-between" width="100%">
|
<Box marginTop={1} justifyContent="space-between" width="100%">
|
||||||
<Box>
|
<Box>
|
||||||
<Text color={Colors.LightBlue}>
|
{nightly ? (
|
||||||
{shortenPath(tildeifyPath(targetDir), 70)}
|
<Gradient colors={Colors.GradientColors}>
|
||||||
{branchName && <Text color={Colors.Gray}> ({branchName}*)</Text>}
|
<Text>
|
||||||
</Text>
|
{shortenPath(tildeifyPath(targetDir), 70)}
|
||||||
|
{branchName && <Text> ({branchName}*)</Text>}
|
||||||
|
</Text>
|
||||||
|
</Gradient>
|
||||||
|
) : (
|
||||||
|
<Text color={Colors.LightBlue}>
|
||||||
|
{shortenPath(tildeifyPath(targetDir), 70)}
|
||||||
|
{branchName && <Text color={Colors.Gray}> ({branchName}*)</Text>}
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
{debugMode && (
|
{debugMode && (
|
||||||
<Text color={Colors.AccentRed}>
|
<Text color={Colors.AccentRed}>
|
||||||
{' ' + (debugMessage || '--debug')}
|
{' ' + (debugMessage || '--debug')}
|
||||||
|
|
|
@ -14,11 +14,15 @@ import { getAsciiArtWidth } from '../utils/textUtils.js';
|
||||||
interface HeaderProps {
|
interface HeaderProps {
|
||||||
customAsciiArt?: string; // For user-defined ASCII art
|
customAsciiArt?: string; // For user-defined ASCII art
|
||||||
terminalWidth: number; // For responsive logo
|
terminalWidth: number; // For responsive logo
|
||||||
|
version: string;
|
||||||
|
nightly: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Header: React.FC<HeaderProps> = ({
|
export const Header: React.FC<HeaderProps> = ({
|
||||||
customAsciiArt,
|
customAsciiArt,
|
||||||
terminalWidth,
|
terminalWidth,
|
||||||
|
version,
|
||||||
|
nightly,
|
||||||
}) => {
|
}) => {
|
||||||
let displayTitle;
|
let displayTitle;
|
||||||
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
|
const widthOfLongLogo = getAsciiArtWidth(longAsciiLogo);
|
||||||
|
@ -38,6 +42,7 @@ export const Header: React.FC<HeaderProps> = ({
|
||||||
alignItems="flex-start"
|
alignItems="flex-start"
|
||||||
width={artWidth}
|
width={artWidth}
|
||||||
flexShrink={0}
|
flexShrink={0}
|
||||||
|
flexDirection="column"
|
||||||
>
|
>
|
||||||
{Colors.GradientColors ? (
|
{Colors.GradientColors ? (
|
||||||
<Gradient colors={Colors.GradientColors}>
|
<Gradient colors={Colors.GradientColors}>
|
||||||
|
@ -46,6 +51,13 @@ export const Header: React.FC<HeaderProps> = ({
|
||||||
) : (
|
) : (
|
||||||
<Text>{displayTitle}</Text>
|
<Text>{displayTitle}</Text>
|
||||||
)}
|
)}
|
||||||
|
{nightly && (
|
||||||
|
<Box width="100%" flexDirection="row" justifyContent="flex-end">
|
||||||
|
<Gradient colors={Colors.GradientColors}>
|
||||||
|
<Text>v{version}</Text>
|
||||||
|
</Gradient>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue