diff --git a/packages/cli/src/ui/AppContainer.tsx b/packages/cli/src/ui/AppContainer.tsx index e7b6af7eb9..17e08b54ea 100644 --- a/packages/cli/src/ui/AppContainer.tsx +++ b/packages/cli/src/ui/AppContainer.tsx @@ -668,7 +668,7 @@ Logging in with Google... Please restart Gemini CLI to continue. const [showIdeRestartPrompt, setShowIdeRestartPrompt] = useState(false); const { isFolderTrustDialogOpen, handleFolderTrustSelect, isRestarting } = - useFolderTrust(settings, config, setIsTrustedFolder, refreshStatic); + useFolderTrust(settings, setIsTrustedFolder, refreshStatic); const { needsRestart: ideNeedsRestart } = useIdeTrustListener(); const isInitialMount = useRef(true); diff --git a/packages/cli/src/ui/hooks/useFolderTrust.test.ts b/packages/cli/src/ui/hooks/useFolderTrust.test.ts index 180593fa9f..821e65ec2f 100644 --- a/packages/cli/src/ui/hooks/useFolderTrust.test.ts +++ b/packages/cli/src/ui/hooks/useFolderTrust.test.ts @@ -22,7 +22,6 @@ vi.mock('process', () => ({ describe('useFolderTrust', () => { let mockSettings: LoadedSettings; - let mockConfig: unknown; let mockTrustedFolders: LoadedTrustedFolders; let loadTrustedFoldersSpy: vi.SpyInstance; let isWorkspaceTrustedSpy: vi.SpyInstance; @@ -41,8 +40,6 @@ describe('useFolderTrust', () => { setValue: vi.fn(), } as unknown as LoadedSettings; - mockConfig = {} as unknown; - mockTrustedFolders = { setValue: vi.fn(), } as unknown as LoadedTrustedFolders; @@ -63,7 +60,7 @@ describe('useFolderTrust', () => { it('should not open dialog when folder is already trusted', () => { isWorkspaceTrustedSpy.mockReturnValue(true); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); expect(result.current.isFolderTrustDialogOpen).toBe(false); expect(onTrustChange).toHaveBeenCalledWith(true); @@ -72,7 +69,7 @@ describe('useFolderTrust', () => { it('should not open dialog when folder is already untrusted', () => { isWorkspaceTrustedSpy.mockReturnValue(false); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); expect(result.current.isFolderTrustDialogOpen).toBe(false); expect(onTrustChange).toHaveBeenCalledWith(false); @@ -81,7 +78,7 @@ describe('useFolderTrust', () => { it('should open dialog when folder trust is undefined', () => { isWorkspaceTrustedSpy.mockReturnValue(undefined); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); expect(result.current.isFolderTrustDialogOpen).toBe(true); expect(onTrustChange).toHaveBeenCalledWith(undefined); @@ -92,7 +89,7 @@ describe('useFolderTrust', () => { .mockReturnValueOnce(undefined) .mockReturnValueOnce(true); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); isWorkspaceTrustedSpy.mockReturnValue(true); @@ -114,7 +111,7 @@ describe('useFolderTrust', () => { .mockReturnValueOnce(undefined) .mockReturnValueOnce(true); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); act(() => { @@ -134,7 +131,7 @@ describe('useFolderTrust', () => { .mockReturnValueOnce(undefined) .mockReturnValueOnce(false); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); act(() => { @@ -146,14 +143,14 @@ describe('useFolderTrust', () => { TrustLevel.DO_NOT_TRUST, ); expect(onTrustChange).toHaveBeenLastCalledWith(false); - expect(result.current.isRestarting).toBe(false); - expect(result.current.isFolderTrustDialogOpen).toBe(false); + expect(result.current.isRestarting).toBe(true); + expect(result.current.isFolderTrustDialogOpen).toBe(true); }); it('should do nothing for default choice', () => { isWorkspaceTrustedSpy.mockReturnValue(undefined); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); act(() => { @@ -171,15 +168,15 @@ describe('useFolderTrust', () => { it('should set isRestarting to true when trust status changes from false to true', () => { isWorkspaceTrustedSpy.mockReturnValueOnce(false).mockReturnValueOnce(true); // Initially untrusted, then trusted const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); act(() => { result.current.handleFolderTrustSelect(FolderTrustChoice.TRUST_FOLDER); }); - expect(result.current.isRestarting).toBe(false); - expect(result.current.isFolderTrustDialogOpen).toBe(false); // Dialog should close after selection + expect(result.current.isRestarting).toBe(true); + expect(result.current.isFolderTrustDialogOpen).toBe(true); // Dialog should stay open }); it('should not set isRestarting to true when trust status does not change', () => { @@ -187,7 +184,7 @@ describe('useFolderTrust', () => { .mockReturnValueOnce(undefined) .mockReturnValueOnce(true); // Initially undefined, then trust const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); act(() => { @@ -201,7 +198,7 @@ describe('useFolderTrust', () => { it('should call refreshStatic when dialog opens and closes', () => { isWorkspaceTrustedSpy.mockReturnValue(undefined); const { result } = renderHook(() => - useFolderTrust(mockSettings, mockConfig, onTrustChange, refreshStatic), + useFolderTrust(mockSettings, onTrustChange, refreshStatic), ); // The hook runs, isFolderTrustDialogOpen becomes true, useEffect triggers. diff --git a/packages/cli/src/ui/hooks/useFolderTrust.ts b/packages/cli/src/ui/hooks/useFolderTrust.ts index 93e019ae20..ddefc8827f 100644 --- a/packages/cli/src/ui/hooks/useFolderTrust.ts +++ b/packages/cli/src/ui/hooks/useFolderTrust.ts @@ -5,7 +5,6 @@ */ import { useState, useCallback, useEffect } from 'react'; -import { type Config } from '@google/gemini-cli-core'; import type { LoadedSettings } from '../../config/settings.js'; import { FolderTrustChoice } from '../components/FolderTrustDialog.js'; import { @@ -17,13 +16,12 @@ import * as process from 'node:process'; export const useFolderTrust = ( settings: LoadedSettings, - config: Config, onTrustChange: (isTrusted: boolean | undefined) => void, refreshStatic: () => void, ) => { const [isTrusted, setIsTrusted] = useState(undefined); const [isFolderTrustDialogOpen, setIsFolderTrustDialogOpen] = useState(false); - const [isRestarting] = useState(false); + const [isRestarting, setIsRestarting] = useState(false); const folderTrust = settings.merged.security?.folderTrust?.enabled; @@ -46,6 +44,8 @@ export const useFolderTrust = ( const cwd = process.cwd(); let trustLevel: TrustLevel; + const wasTrusted = isTrusted ?? true; + switch (choice) { case FolderTrustChoice.TRUST_FOLDER: trustLevel = TrustLevel.TRUST_FOLDER; @@ -61,12 +61,21 @@ export const useFolderTrust = ( } trustedFolders.setValue(cwd, trustLevel); - const trusted = isWorkspaceTrusted(settings.merged); - setIsTrusted(trusted); - setIsFolderTrustDialogOpen(false); - onTrustChange(trusted); + const currentIsTrusted = + trustLevel === TrustLevel.TRUST_FOLDER || + trustLevel === TrustLevel.TRUST_PARENT; + setIsTrusted(currentIsTrusted); + onTrustChange(currentIsTrusted); + + const needsRestart = wasTrusted !== currentIsTrusted; + if (needsRestart) { + setIsRestarting(true); + setIsFolderTrustDialogOpen(true); + } else { + setIsFolderTrustDialogOpen(false); + } }, - [settings.merged, onTrustChange], + [onTrustChange, isTrusted], ); return {