diff --git a/packages/cli/src/gemini.ts b/packages/cli/src/gemini.ts index 420f3242..32e34c20 100644 --- a/packages/cli/src/gemini.ts +++ b/packages/cli/src/gemini.ts @@ -24,7 +24,24 @@ async function main() { const settings = loadSettings(process.cwd()); const config = await loadCliConfig(settings.merged); if (settings.merged.theme) { - themeManager.setActiveTheme(settings.merged.theme); + try { + themeManager.setActiveTheme(settings.merged.theme); + } catch (error: unknown) { + // If the theme is not found during initial load, log a warning and continue. + // The useThemeCommand hook in App.tsx will handle opening the dialog. + if ( + error instanceof Error && + error.message.includes('Theme') && + error.message.includes('not found') + ) { + console.warn( + `Warning: ${error instanceof Error ? error.message : String(error)}`, + ); + } else { + // Re-throw other errors to be caught by the main catch block + throw error; + } + } } // hop into sandbox if we are outside and sandboxing is enabled diff --git a/packages/cli/src/ui/App.tsx b/packages/cli/src/ui/App.tsx index 9fe651b5..725a2012 100644 --- a/packages/cli/src/ui/App.tsx +++ b/packages/cli/src/ui/App.tsx @@ -39,12 +39,13 @@ export const App = ({ config, settings, cliVersion }: AppProps) => { const { history, addItem, clearItems } = useHistory(); const [startupWarnings, setStartupWarnings] = useState([]); const [showHelp, setShowHelp] = useState(false); + const [themeError, setThemeError] = useState(null); const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, - } = useThemeCommand(settings); + } = useThemeCommand(settings, setThemeError); const [staticKey, setStaticKey] = useState(0); const refreshStatic = useCallback(() => { @@ -191,11 +192,18 @@ export const App = ({ config, settings, cliVersion }: AppProps) => { )} {isThemeDialogOpen ? ( - + + {themeError && ( + + {themeError} + + )} + + ) : ( <> void, ): UseThemeCommandReturn => { // Determine the effective theme const effectiveTheme = loadedSettings.merged.theme; // Initial state: Open dialog if no theme is set in either user or workspace settings - const [isThemeDialogOpen, setIsThemeDialogOpen] = useState( - effectiveTheme === undefined, - ); + const [isThemeDialogOpen, setIsThemeDialogOpen] = useState(false); // TODO: refactor how theme's are accessed to avoid requiring a forced render. const [, setForceRender] = useState(0); + // Apply initial theme on component mount + useEffect(() => { + try { + themeManager.setActiveTheme(effectiveTheme); + setThemeError(null); // Clear any previous theme error on success + } catch (error: unknown) { + // If theme is not found during initial load, open the theme selection dialog and set error message + if ( + error instanceof Error && + error.message.includes('Theme') && + error.message.includes('not found') + ) { + setIsThemeDialogOpen(true); + setThemeError( + `Error: ${error instanceof Error ? error.message : String(error)}`, + ); + } else { + console.error( + `Error setting initial theme: ${error instanceof Error ? error.message : String(error)}`, + ); + setThemeError( + `Error setting initial theme: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + }, [effectiveTheme, setThemeError]); // Re-run if effectiveTheme or setThemeError changes + const openThemeDialog = useCallback(() => { setIsThemeDialogOpen(true); }, []); - const applyTheme = useCallback((themeName: string | undefined) => { - try { - themeManager.setActiveTheme(themeName); - setForceRender((v) => v + 1); // Trigger potential re-render - } catch (error) { - console.error(`Error setting theme: ${error}`); - } - }, []); + const applyTheme = useCallback( + (themeName: string | undefined) => { + try { + themeManager.setActiveTheme(themeName); + setForceRender((v) => v + 1); // Trigger potential re-render + setThemeError(null); // Clear any previous theme error on success + } catch (error: unknown) { + // If theme is not found, open the theme selection dialog and set error message + if ( + error instanceof Error && + error.message.includes('Theme') && + error.message.includes('not found') + ) { + setIsThemeDialogOpen(true); + setThemeError( + `Error: ${error instanceof Error ? error.message : String(error)}`, + ); + } else { + console.error( + `Error setting theme: ${error instanceof Error ? error.message : String(error)}`, + ); + setThemeError( + `Error setting theme: ${error instanceof Error ? error.message : String(error)}`, + ); + } + } + }, + [setForceRender, setThemeError], + ); const handleThemeHighlight = useCallback( (themeName: string | undefined) => { applyTheme(themeName); }, [applyTheme], - ); // Added applyTheme to dependencies + ); const handleThemeSelect = useCallback( (themeName: string | undefined, scope: SettingScope) => {