import ignore from 'ignore'; import { useGit } from '~/lib/hooks/useGit'; import type { Message } from 'ai'; import { detectProjectCommands, createCommandsMessage } from '~/utils/projectCommands'; import { generateId } from '~/utils/fileUtils'; const IGNORE_PATTERNS = [ 'node_modules/**', '.git/**', '.github/**', '.vscode/**', '**/*.jpg', '**/*.jpeg', '**/*.png', 'dist/**', 'build/**', '.next/**', 'coverage/**', '.cache/**', '.vscode/**', '.idea/**', '**/*.log', '**/.DS_Store', '**/npm-debug.log*', '**/yarn-debug.log*', '**/yarn-error.log*', '**/*lock.json', '**/*lock.yaml', ]; const ig = ignore().add(IGNORE_PATTERNS); interface GitCloneButtonProps { className?: string; importChat?: (description: string, messages: Message[]) => Promise<void>; } export default function GitCloneButton({ importChat }: GitCloneButtonProps) { const { ready, gitClone } = useGit(); const onClick = async (_e: any) => { if (!ready) { return; } const repoUrl = prompt('Enter the Git url'); if (repoUrl) { const { workdir, data } = await gitClone(repoUrl); if (importChat) { const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath)); console.log(filePaths); const textDecoder = new TextDecoder('utf-8'); // Convert files to common format for command detection const fileContents = filePaths .map((filePath) => { const { data: content, encoding } = data[filePath]; return { path: filePath, content: encoding === 'utf8' ? content : content instanceof Uint8Array ? textDecoder.decode(content) : '', }; }) .filter((f) => f.content); // Detect and create commands message const commands = await detectProjectCommands(fileContents); const commandsMessage = createCommandsMessage(commands); // Create files message const filesMessage: Message = { role: 'assistant', content: `Cloning the repo ${repoUrl} into ${workdir} <boltArtifact id="imported-files" title="Git Cloned Files" type="bundled"> ${fileContents .map( (file) => `<boltAction type="file" filePath="${file.path}"> ${file.content} </boltAction>`, ) .join('\n')} </boltArtifact>`, id: generateId(), createdAt: new Date(), }; const messages = [filesMessage]; if (commandsMessage) { messages.push(commandsMessage); } await importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, messages); } } }; return ( <button onClick={onClick} title="Clone a Git Repo" className="px-4 py-2 rounded-lg border border-bolt-elements-borderColor bg-bolt-elements-prompt-background text-bolt-elements-textPrimary hover:bg-bolt-elements-background-depth-3 transition-all flex items-center gap-2" > <span className="i-ph:git-branch" /> Clone a Git Repo </button> ); }