From 447826ab40354c01667328a651f6a0f239825c64 Mon Sep 17 00:00:00 2001 From: Jacob Richman Date: Mon, 2 Jun 2025 19:09:11 -0700 Subject: [PATCH] fix(cli): restore first-launch theme prompt (#703) --- packages/cli/src/ui/App.test.tsx | 35 +++++++++++++++++--- packages/cli/src/ui/hooks/useThemeCommand.ts | 19 +++++++---- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/ui/App.test.tsx b/packages/cli/src/ui/App.test.tsx index 1a16163f..cba00b42 100644 --- a/packages/cli/src/ui/App.test.tsx +++ b/packages/cli/src/ui/App.test.tsx @@ -188,7 +188,8 @@ describe('App UI', () => { } mockConfig.getShowMemoryUsage.mockReturnValue(false); // Default for most tests - mockSettings = createMockSettings(); + // Ensure a theme is set so the theme dialog does not appear. + mockSettings = createMockSettings({ theme: 'Default' }); }); afterEach(() => { @@ -235,7 +236,10 @@ describe('App UI', () => { }); it('should display custom contextFileName in footer when set and count is 1', async () => { - mockSettings = createMockSettings({ contextFileName: 'AGENTS.MD' }); + mockSettings = createMockSettings({ + contextFileName: 'AGENTS.MD', + theme: 'Default', + }); mockConfig.getGeminiMdFileCount.mockReturnValue(1); mockConfig.getDebugMode.mockReturnValue(false); mockConfig.getShowMemoryUsage.mockReturnValue(false); @@ -253,7 +257,10 @@ describe('App UI', () => { }); it('should display custom contextFileName with plural when set and count is > 1', async () => { - mockSettings = createMockSettings({ contextFileName: 'MY_NOTES.TXT' }); + mockSettings = createMockSettings({ + contextFileName: 'MY_NOTES.TXT', + theme: 'Default', + }); mockConfig.getGeminiMdFileCount.mockReturnValue(3); mockConfig.getDebugMode.mockReturnValue(false); mockConfig.getShowMemoryUsage.mockReturnValue(false); @@ -271,7 +278,10 @@ describe('App UI', () => { }); it('should not display context file message if count is 0, even if contextFileName is set', async () => { - mockSettings = createMockSettings({ contextFileName: 'ANY_FILE.MD' }); + mockSettings = createMockSettings({ + contextFileName: 'ANY_FILE.MD', + theme: 'Default', + }); mockConfig.getGeminiMdFileCount.mockReturnValue(0); mockConfig.getDebugMode.mockReturnValue(false); mockConfig.getShowMemoryUsage.mockReturnValue(false); @@ -328,4 +338,21 @@ describe('App UI', () => { await Promise.resolve(); expect(lastFrame()).toContain('Using 2 MCP servers'); }); + + it('should display theme dialog if no theme is set in settings', async () => { + mockSettings = createMockSettings({}); + mockConfig.getDebugMode.mockReturnValue(false); + mockConfig.getShowMemoryUsage.mockReturnValue(false); + + const { lastFrame, unmount } = render( + , + ); + currentUnmount = unmount; + + expect(lastFrame()).toContain('Select Theme'); + }); }); diff --git a/packages/cli/src/ui/hooks/useThemeCommand.ts b/packages/cli/src/ui/hooks/useThemeCommand.ts index d8b0ef6b..01911b44 100644 --- a/packages/cli/src/ui/hooks/useThemeCommand.ts +++ b/packages/cli/src/ui/hooks/useThemeCommand.ts @@ -26,18 +26,23 @@ export const useThemeCommand = ( const effectiveTheme = loadedSettings.merged.theme; // Initial state: Open dialog if no theme is set in either user or workspace settings - const [isThemeDialogOpen, setIsThemeDialogOpen] = useState(false); + const [isThemeDialogOpen, setIsThemeDialogOpen] = useState( + effectiveTheme === undefined, // Open dialog if no theme is set initially + ); // TODO: refactor how theme's are accessed to avoid requiring a forced render. const [, setForceRender] = useState(0); // Apply initial theme on component mount useEffect(() => { - if (!themeManager.setActiveTheme(effectiveTheme)) { - // If theme is not found during initial load, open the theme selection dialog and set error message - setIsThemeDialogOpen(true); - setThemeError(`Theme "${effectiveTheme}" not found.`); - } else { - setThemeError(null); // Clear any previous theme error on success + // Only try to set a theme if one is actually defined. + // If effectiveTheme was undefined, the dialog is already open due to useState above. + if (effectiveTheme !== undefined) { + if (!themeManager.setActiveTheme(effectiveTheme)) { + setIsThemeDialogOpen(true); + setThemeError(`Theme "${effectiveTheme}" not found.`); + } else { + setThemeError(null); // Clear any previous theme error on success + } } }, [effectiveTheme, setThemeError]); // Re-run if effectiveTheme or setThemeError changes