Skip to content

Commit 1774bf6

Browse files
authored
Merge pull request #421 from thecodacus/github-import
feat(git): Git Repository Integration
2 parents 2af32b0 + 60dd0b0 commit 1774bf6

File tree

8 files changed

+954
-520
lines changed

8 files changed

+954
-520
lines changed

.husky/pre-commit

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,21 @@ echo "🔍 Running pre-commit hook to check the code looks good... 🔍"
55
export NVM_DIR="$HOME/.nvm"
66
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # Load nvm if you're using i
77

8+
echo "Running typecheck..."
9+
which pnpm
10+
811
if ! pnpm typecheck; then
9-
echo "❌ Type checking failed! Please review TypeScript types."
10-
echo "Once you're done, don't forget to add your changes to the commit! 🚀"
11-
exit 1
12+
echo "❌ Type checking failed! Please review TypeScript types."
13+
echo "Once you're done, don't forget to add your changes to the commit! 🚀"
14+
echo "Typecheck exit code: $?"
15+
exit 1
1216
fi
1317

18+
echo "Running lint..."
1419
if ! pnpm lint; then
1520
echo "❌ Linting failed! 'pnpm lint:fix' will help you fix the easy ones."
1621
echo "Once you're done, don't forget to add your beautification to the commit! 🤩"
22+
echo "lint exit code: $?"
1723
exit 1
1824
fi
1925

app/components/chat/Artifact.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export const Artifact = memo(({ messageId }: ArtifactProps) => {
5252
if (actions.length !== 0 && artifact.type === 'bundled') {
5353
const finished = !actions.find((action) => action.status !== 'complete');
5454

55-
if (finished != allActionFinished) {
55+
if (allActionFinished !== finished) {
5656
setAllActionFinished(finished);
5757
}
5858
}

app/components/chat/BaseChat.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import type { ProviderInfo } from '~/utils/types';
2121
import { ExportChatButton } from '~/components/chat/chatExportAndImport/ExportChatButton';
2222
import { ImportButtons } from '~/components/chat/chatExportAndImport/ImportButtons';
2323
import { ExamplePrompts } from '~/components/chat/ExamplePrompts';
24+
import GitCloneButton from './GitCloneButton';
2425

2526
import FilePreview from './FilePreview';
2627
import { ModelSelector } from '~/components/chat/ModelSelector';
@@ -513,7 +514,12 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
513514
</div>
514515
</div>
515516
</div>
516-
{!chatStarted && ImportButtons(importChat)}
517+
{!chatStarted && (
518+
<div className="flex justify-center gap-2">
519+
{ImportButtons(importChat)}
520+
<GitCloneButton importChat={importChat} />
521+
</div>
522+
)}
517523
{!chatStarted &&
518524
ExamplePrompts((event, messageInput) => {
519525
if (isStreaming) {
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import ignore from 'ignore';
2+
import { useGit } from '~/lib/hooks/useGit';
3+
import type { Message } from 'ai';
4+
import WithTooltip from '~/components/ui/Tooltip';
5+
6+
const IGNORE_PATTERNS = [
7+
'node_modules/**',
8+
'.git/**',
9+
'.github/**',
10+
'.vscode/**',
11+
'**/*.jpg',
12+
'**/*.jpeg',
13+
'**/*.png',
14+
'dist/**',
15+
'build/**',
16+
'.next/**',
17+
'coverage/**',
18+
'.cache/**',
19+
'.vscode/**',
20+
'.idea/**',
21+
'**/*.log',
22+
'**/.DS_Store',
23+
'**/npm-debug.log*',
24+
'**/yarn-debug.log*',
25+
'**/yarn-error.log*',
26+
'**/*lock.json',
27+
'**/*lock.yaml',
28+
];
29+
30+
const ig = ignore().add(IGNORE_PATTERNS);
31+
const generateId = () => Math.random().toString(36).substring(2, 15);
32+
33+
interface GitCloneButtonProps {
34+
className?: string;
35+
importChat?: (description: string, messages: Message[]) => Promise<void>;
36+
}
37+
38+
export default function GitCloneButton({ importChat }: GitCloneButtonProps) {
39+
const { ready, gitClone } = useGit();
40+
const onClick = async (_e: any) => {
41+
if (!ready) {
42+
return;
43+
}
44+
45+
const repoUrl = prompt('Enter the Git url');
46+
47+
if (repoUrl) {
48+
const { workdir, data } = await gitClone(repoUrl);
49+
50+
if (importChat) {
51+
const filePaths = Object.keys(data).filter((filePath) => !ig.ignores(filePath));
52+
console.log(filePaths);
53+
54+
const textDecoder = new TextDecoder('utf-8');
55+
const message: Message = {
56+
role: 'assistant',
57+
content: `Cloning the repo ${repoUrl} into ${workdir}
58+
<boltArtifact id="imported-files" title="Git Cloned Files" type="bundled" >
59+
${filePaths
60+
.map((filePath) => {
61+
const { data: content, encoding } = data[filePath];
62+
63+
if (encoding === 'utf8') {
64+
return `<boltAction type="file" filePath="${filePath}">
65+
${content}
66+
</boltAction>`;
67+
} else if (content instanceof Uint8Array) {
68+
return `<boltAction type="file" filePath="${filePath}">
69+
${textDecoder.decode(content)}
70+
</boltAction>`;
71+
} else {
72+
return '';
73+
}
74+
})
75+
.join('\n')}
76+
</boltArtifact>`,
77+
id: generateId(),
78+
createdAt: new Date(),
79+
};
80+
console.log(JSON.stringify(message));
81+
82+
importChat(`Git Project:${repoUrl.split('/').slice(-1)[0]}`, [message]);
83+
84+
// console.log(files);
85+
}
86+
}
87+
};
88+
89+
return (
90+
<WithTooltip tooltip="Clone A Git Repo">
91+
<button
92+
onClick={(e) => {
93+
onClick(e);
94+
}}
95+
title="Clone A Git Repo"
96+
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"
97+
>
98+
<span className="i-ph:git-branch" />
99+
Clone A Git Repo
100+
</button>
101+
</WithTooltip>
102+
);
103+
}

app/components/chat/chatExportAndImport/ImportButtons.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ImportFolderButton } from '~/components/chat/ImportFolderButton';
55

66
export function ImportButtons(importChat: ((description: string, messages: Message[]) => Promise<void>) | undefined) {
77
return (
8-
<div className="flex flex-col items-center justify-center flex-1 p-4">
8+
<div className="flex flex-col items-center justify-center w-auto">
99
<input
1010
type="file"
1111
id="chat-import"

0 commit comments

Comments
 (0)