TrustDialog.tsx
1 import React from 'react' 2 import { Box, Text, useInput } from 'ink' 3 import { getTheme } from '../utils/theme.js' 4 import { Select } from '@inkjs/ui' 5 import { 6 saveCurrentProjectConfig, 7 getCurrentProjectConfig, 8 } from '../utils/config.js' 9 import { PRODUCT_NAME } from '../constants/product.js' 10 import { logEvent } from '../services/statsig.js' 11 import { useExitOnCtrlCD } from '../hooks/useExitOnCtrlCD.js' 12 import { homedir } from 'os' 13 import { getCwd } from '../utils/state.js' 14 import Link from './Link.js' 15 16 type Props = { 17 onDone(): void 18 } 19 20 export function TrustDialog({ onDone }: Props): React.ReactNode { 21 const theme = getTheme() 22 React.useEffect(() => { 23 // Log when dialog is shown 24 logEvent('trust_dialog_shown', {}) 25 }, []) 26 27 function onChange(value: 'yes' | 'no') { 28 const config = getCurrentProjectConfig() 29 switch (value) { 30 case 'yes': { 31 // Log when user accepts 32 const isHomeDir = homedir() === getCwd() 33 logEvent('trust_dialog_accept', { 34 isHomeDir: String(isHomeDir), 35 }) 36 37 if (!isHomeDir) { 38 saveCurrentProjectConfig({ 39 ...config, 40 hasTrustDialogAccepted: true, 41 }) 42 } 43 onDone() 44 break 45 } 46 case 'no': { 47 process.exit(1) 48 break 49 } 50 } 51 } 52 53 const exitState = useExitOnCtrlCD(() => process.exit(0)) 54 55 useInput((_input, key) => { 56 if (key.escape) { 57 process.exit(0) 58 return 59 } 60 }) 61 62 return ( 63 <> 64 <Box 65 flexDirection="column" 66 gap={1} 67 padding={1} 68 borderStyle="round" 69 borderColor={theme.warning} 70 > 71 <Text bold color={theme.warning}> 72 Do you trust the files in this folder? 73 </Text> 74 <Text bold>{process.cwd()}</Text> 75 76 <Box flexDirection="column" gap={1}> 77 <Text> 78 {PRODUCT_NAME} may read files in this folder. Reading untrusted 79 files may lead to {PRODUCT_NAME} to behave in an unexpected ways. 80 </Text> 81 <Text> 82 With your permission {PRODUCT_NAME} may execute files in this 83 folder. Executing untrusted code is unsafe. 84 </Text> 85 86 <Link url="https://docs.anthropic.com/s/claude-code-security" /> 87 </Box> 88 89 <Select 90 options={[ 91 { label: 'Yes, proceed', value: 'yes' }, 92 { label: 'No, exit', value: 'no' }, 93 ]} 94 onChange={value => onChange(value as 'yes' | 'no')} 95 /> 96 </Box> 97 <Box marginLeft={3}> 98 <Text dimColor> 99 {exitState.pending ? ( 100 <>Press {exitState.keyName} again to exit</> 101 ) : ( 102 <>Enter to confirm ยท Esc to exit</> 103 )} 104 </Text> 105 </Box> 106 </> 107 ) 108 }