diff options
Diffstat (limited to 'packages/cli/src/ui/components')
| -rw-r--r-- | packages/cli/src/ui/components/FolderTrustDialog.test.tsx | 29 | ||||
| -rw-r--r-- | packages/cli/src/ui/components/FolderTrustDialog.tsx | 70 |
2 files changed, 99 insertions, 0 deletions
diff --git a/packages/cli/src/ui/components/FolderTrustDialog.test.tsx b/packages/cli/src/ui/components/FolderTrustDialog.test.tsx new file mode 100644 index 00000000..01394d0f --- /dev/null +++ b/packages/cli/src/ui/components/FolderTrustDialog.test.tsx @@ -0,0 +1,29 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { render } from 'ink-testing-library'; +import { vi } from 'vitest'; +import { FolderTrustDialog, FolderTrustChoice } from './FolderTrustDialog.js'; + +describe('FolderTrustDialog', () => { + it('should render the dialog with title and description', () => { + const { lastFrame } = render(<FolderTrustDialog onSelect={vi.fn()} />); + + expect(lastFrame()).toContain('Do you trust this folder?'); + expect(lastFrame()).toContain( + 'Trusting a folder allows Gemini to execute commands it suggests.', + ); + }); + + it('should call onSelect with DO_NOT_TRUST when escape is pressed', () => { + const onSelect = vi.fn(); + const { stdin } = render(<FolderTrustDialog onSelect={onSelect} />); + + stdin.write('\u001B'); // Simulate escape key + + expect(onSelect).toHaveBeenCalledWith(FolderTrustChoice.DO_NOT_TRUST); + }); +}); diff --git a/packages/cli/src/ui/components/FolderTrustDialog.tsx b/packages/cli/src/ui/components/FolderTrustDialog.tsx new file mode 100644 index 00000000..1918998c --- /dev/null +++ b/packages/cli/src/ui/components/FolderTrustDialog.tsx @@ -0,0 +1,70 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Box, Text, useInput } from 'ink'; +import React from 'react'; +import { Colors } from '../colors.js'; +import { + RadioButtonSelect, + RadioSelectItem, +} from './shared/RadioButtonSelect.js'; + +export enum FolderTrustChoice { + TRUST_FOLDER = 'trust_folder', + TRUST_PARENT = 'trust_parent', + DO_NOT_TRUST = 'do_not_trust', +} + +interface FolderTrustDialogProps { + onSelect: (choice: FolderTrustChoice) => void; +} + +export const FolderTrustDialog: React.FC<FolderTrustDialogProps> = ({ + onSelect, +}) => { + useInput((_, key) => { + if (key.escape) { + onSelect(FolderTrustChoice.DO_NOT_TRUST); + } + }); + + const options: Array<RadioSelectItem<FolderTrustChoice>> = [ + { + label: 'Trust folder', + value: FolderTrustChoice.TRUST_FOLDER, + }, + { + label: 'Trust parent folder', + value: FolderTrustChoice.TRUST_PARENT, + }, + { + label: "Don't trust (esc)", + value: FolderTrustChoice.DO_NOT_TRUST, + }, + ]; + + return ( + <Box + flexDirection="column" + borderStyle="round" + borderColor={Colors.AccentYellow} + padding={1} + width="100%" + marginLeft={1} + > + <Box flexDirection="column" marginBottom={1}> + <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. + </Text> + </Box> + + <RadioButtonSelect items={options} onSelect={onSelect} isFocused /> + </Box> + ); +}; |
