/ src / components / TrustDialog.tsx
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  }