diff --git a/blocks/blocks/github.ts b/blocks/blocks/github.ts new file mode 100644 index 0000000000..944c00b64c --- /dev/null +++ b/blocks/blocks/github.ts @@ -0,0 +1,59 @@ +import { GithubIcon } from '../../components/icons' +import { BlockConfig } from '../types' +import { RepoInfoResponse } from '@/tools/github/repo' + +export const GitHubBlock: BlockConfig = { + type: 'github_repo_info', + toolbar: { + title: 'GitHub Repository Info', + description: 'Fetch GitHub repository information and metadata', + bgColor: '#ffffff', + icon: GithubIcon, + category: 'advanced', + }, + tools: { + access: ['github.repoinfo'] + }, + workflow: { + inputs: { + owner: { type: 'string', required: true }, + repo: { type: 'string', required: true } + }, + outputs: { + response: { + type: { + name: 'string', + description: 'string', + stars: 'number', + forks: 'number', + openIssues: 'number', + language: 'string' + } + } + }, + subBlocks: [ + { + id: 'owner', + title: 'Repository Owner', + type: 'short-input', + layout: 'half', + placeholder: 'e.g., microsoft', + }, + { + id: 'repo', + title: 'Repository Name', + type: 'short-input', + layout: 'half', + placeholder: 'e.g., vscode', + }, + { + id: 'apiKey', + title: 'GitHub Token', + type: 'short-input', + layout: 'full', + placeholder: 'Enter GitHub Token', + password: true + } + ], + }, +} diff --git a/blocks/index.ts b/blocks/index.ts index 9e51dd2f1c..29762ef636 100644 --- a/blocks/index.ts +++ b/blocks/index.ts @@ -9,6 +9,7 @@ import { FirecrawlScrapeBlock } from './blocks/firecrawl' import { JinaBlock } from './blocks/jina' import { TranslateBlock } from './blocks/translate' import { SlackMessageBlock } from './blocks/slack' +import { GitHubBlock } from './blocks/github' // Export blocks for ease of use export { @@ -19,7 +20,8 @@ export { FirecrawlScrapeBlock, JinaBlock, TranslateBlock, - SlackMessageBlock + SlackMessageBlock, + GitHubBlock } // Registry of all block configurations @@ -31,7 +33,8 @@ const blocks: Record = { firecrawl_scrape: FirecrawlScrapeBlock, jina_reader: JinaBlock, translate: TranslateBlock, - slack_message: SlackMessageBlock + slack_message: SlackMessageBlock, + github_repo_info: GitHubBlock } // Build a reverse mapping of tools to block types diff --git a/components/icons.tsx b/components/icons.tsx index 0066670366..d6bd1d8f39 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -993,3 +993,16 @@ export const SlackIcon = (props: SVGProps) => ( ) +export const GithubIcon = (props: SVGProps) => ( + + GitHub + + +) + + diff --git a/tools/github/repo.ts b/tools/github/repo.ts new file mode 100644 index 0000000000..95c751527e --- /dev/null +++ b/tools/github/repo.ts @@ -0,0 +1,86 @@ +import { ToolConfig, ToolResponse } from '../types' + +export interface RepoInfoParams { + owner: string + repo: string + apiKey?: string +} + +export interface RepoInfoResponse extends ToolResponse { + output: { + name: string + description: string + stars: number + forks: number + openIssues: number + language: string + } +} + +export const repoInfoTool: ToolConfig = { + id: 'github.repoinfo', + name: 'GitHub Repository Info', + description: 'Fetch detailed information about a GitHub repository', + version: '1.0.0', + + params: { + owner: { + type: 'string', + required: true, + description: 'Repository owner (user or organization)' + }, + repo: { + type: 'string', + required: true, + description: 'Repository name' + }, + apiKey: { + type: 'string', + description: 'GitHub Personal Access Token' + } + }, + + request: { + url: (params: RepoInfoParams) => + `https://api.github.com/repos/${params.owner}/${params.repo}`, + method: 'GET', + headers: (params: RepoInfoParams) => ({ + 'Accept': 'application/vnd.github+json', + 'Authorization': params.apiKey ? `Bearer ${params.apiKey}` : '', + 'X-GitHub-Api-Version': '2022-11-28' + }) + }, + + transformResponse: async (response: Response) => { + if (!response.ok) { + throw new Error(`GitHub API error: ${response.statusText}`) + } + + const data = await response.json() + + return { + success: true, + output: { + name: data.name, + description: data.description || '', + stars: data.stargazers_count, + forks: data.forks_count, + openIssues: data.open_issues_count, + language: data.language || 'Not specified' + } + } + }, + + transformError: (error) => { + if (error instanceof Error) { + if (error.message.includes('404')) { + return 'Repository not found. Please check the owner and repository name.' + } + if (error.message.includes('401')) { + return 'Authentication failed. Please check your GitHub token.' + } + return error.message + } + return 'Failed to fetch repository information' + } +} diff --git a/tools/index.ts b/tools/index.ts index c70e57719a..594a0c0846 100644 --- a/tools/index.ts +++ b/tools/index.ts @@ -13,6 +13,7 @@ import { visionTool as crewAIVision } from './crewai/vision' import { scrapeTool } from './firecrawl/scrape' import { readUrlTool } from './jina/reader' import { slackMessageTool } from './slack/message' +import { repoInfoTool } from './github/repo' // Registry of all available tools export const tools: Record = { @@ -37,7 +38,9 @@ export const tools: Record = { // Jina Tools 'jina.readurl': readUrlTool, // Slack Tools - 'slack.message': slackMessageTool + 'slack.message': slackMessageTool, + // GitHub Tools + 'github.repoinfo': repoInfoTool } // Get a tool by its ID