import gradio as gr from github import Github, GithubException import os import requests import re from collections import Counter import jinja2 from diff_match_patch import diff_match_patch # Import diff-match-patch library # Load token. Best practice is to use environment variables. GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') if not GITHUB_TOKEN: raise ValueError("GITHUB_TOKEN environment variable not set!") g = Github(GITHUB_TOKEN) # Project templates (parameterized with Jinja2). PROJECT_TEMPLATES = { "flask": { "params": { "database_type": { "type": "choice", "default": "sqlite", "choices": ["sqlite", "postgresql", "mysql"], "description": "Type of database to configure for the Flask app." } }, "files": { "app.py": """from flask import Flask from flask_sqlalchemy import SQLAlchemy import os basedir = os.path.abspath(os.path.dirname(__file__)) app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') or \\ '{{database_uri}}' # Placeholder for database URI app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) class HelloWorld(db.Model): id = db.Column(db.Integer, primary_key=True) message = db.Column(db.String(128)) def __repr__(self): return f'' @app.route('/') def hello(): return "Hello, Flask!" @app.route('/db_test') def db_test(): try: HelloWorld.query.first() # Simple DB query to test connection return "Database connection successful!" except Exception as e: return f"Database connection failed: {e}" if __name__ == '__main__': with app.app_context(): # Create application context for DB operations db.create_all() if not HelloWorld.query.first(): # Initialize DB with a default entry if empty default_hello = HelloWorld(message="Hello, Database!") db.session.add(default_hello) db.session.commit() app.run(debug=True)""", "requirements.txt": """Flask Flask-SQLAlchemy {{sqlalchemy_dependency}} # Placeholder for SQLAlchemy dependency""", ".gitignore": "__pycache__/\n*.pyc\nvenv/\ninstance/\n*.db" }, "post_process": "install_dependencies" }, "react": { "files": { "package.json": """{ "name": "react-app", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@vitejs/plugin-react": "^4.2.1", "vite": "^5.0.8" }}""", "vite.config.js": """import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' # https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], })""", "index.html": """ Vite + React
""", "src/main.jsx": """import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' import './index.css' ReactDOM.createRoot(document.getElementById('root')).render( , )""", "src/App.jsx": """import React from 'react' import './App.css' function App() { return ( <>

Hello from React!

) } export default App""", "src/index.css": """body { margin: 0; font-family: sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: monospace; }""", ".gitignore": "node_modules/\ndist/" } }, "django": { "files": { "manage.py": """#!/usr/bin/env python import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings") try: from django.core.management import execute_from_command_line except ImportError as exc: raise ImportError( "Couldn't import Django. Are you sure it is installed and " "available on your PYTHONPATH environment variable? Did you " "forget to activate a virtual environment?" ) from exc execute_from_command_line(sys.argv)""", "myapp/settings.py": """import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) SECRET_KEY = 'your_secret_key_here' DEBUG = True ALLOWED_HOSTS = [] INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] ROOT_URLCONF = 'myapp.urls' TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], }, }, ] WSGI_APPLICATION = 'myapp.wsgi.application' DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } AUTH_PASSWORD_VALIDATORS = [ {'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',}, {'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',}, {'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',}, {'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',}, ] LANGUAGE_CODE = 'en-us' TIME_ZONE = 'UTC' USE_I18N = True USE_L10N = True USE_TZ = True STATIC_URL = '/static/' """, "myapp/urls.py": """from django.contrib import admin from django.urls import path from django.http import HttpResponse def home(request): return HttpResponse("Hello, Django!") urlpatterns = [ path('admin/', admin.site.urls), path('', home, name='home'), ]""", "myapp/wsgi.py": """import os from django.core.wsgi import get_wsgi_application os.environ.setdefault("DJANGO_SETTINGS_MODULE", "myapp.settings") application = get_wsgi_application()""", "requirements.txt": "Django", ".gitignore": "__pycache__/\n*.pyc\nvenv/\ndb.sqlite3\n", }, "rename_files": {"myapp": "{{repo_name_snake_case}}"} }, "nodejs_express": { "files": { "server.js": """const express = require('express') const app = express() const port = 3000 app.get('/', (req, res) => { res.send('Hello World from Express!') }) app.listen(port, () => { console.log(`Server listening on port ${port}`) })""", "package.json": """{ "name": "express-app", "version": "1.0.0", "description": "", "main": "server.js", "scripts": { "start": "node server.js" }, "dependencies": { "express": "^4.17.1" } }""", ".gitignore": "node_modules/\n" } }, "static_website": { "files": { "index.html": """ Simple Static Website

Hello from Static Website!

This is a basic HTML page.

""", "style.css": """body { font-family: sans-serif; margin: 20px; }""", "script.js": """console.log("Hello from JavaScript!");""", ".gitignore": "" } }, "python_script": { "files": { "main.py": """def main(): print("Hello from Python script!") if __name__ == "__main__": main()""", "requirements.txt": "", ".gitignore": "__pycache__/\n*.pyc\nvenv/\n" } }, "empty": { "files": { "README.md": "# {{repo_name}}", ".gitignore": "" }, "rename_files": {"README.md": "{{readme_filename}}"} }, "shadcn": { "files": { "package.json": """{ "name": "shadcn-react-app", "private": true, "version": "0.0.0", "type": "module", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview", "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0", "preview": "vite preview" }, "dependencies": { "@radix-ui/react-slot": "^1.0.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "lucide-react": "^0.303.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tailwind-merge": "^2.2.0", "tailwindcss-animate": "^1.0.7" }, "devDependencies": { "@vitejs/plugin-react": "^4.2.1", "autoprefixer": "^10.4.16", "eslint": "^8.55.0", "eslint-plugin-react": "^7.33.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", "postcss": "^8.4.33", "tailwindcss": "^3.4.1", "vite": "^5.0.8" } }""", "vite.config.js": """import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' # https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], })""", "index.html": """ Vite + React + Shadcn
""", "src/main.jsx": """import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' import './index.css' ReactDOM.createRoot(document.getElementById('root')).render( , )""", "src/App.jsx": """import React from 'react' import { Button } from "./components/ui/button" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "./components/ui/card" function App() { return (

Witaj w aplikacji Shadcn UI!

Karta 1 Prosta karta z Shadcn UI.

Zawartość karty.

Karta 2 Kolejna karta dla przykładu.

Więcej zawartości.

Dłuższa Karta Karta zajmująca więcej miejsca.

Ta karta demonstruje jak karty mogą dostosowywać się do różnych rozmiarów ekranów i układów. Shadcn UI i Tailwind CSS dają dużą elastyczność w projektowaniu interfejsów.

) } export default App""", "src/index.css": """@tailwind base; @tailwind components; @tailwind utilities; @layer base { :root { --background: 0 0% 100%; --foreground: 222.2 84.9% 4.9%; --card: 0 0% 100%; --card-foreground: 222.2 84.9% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84.9% 4.9%; --primary: 221.2 83.2% 53.3%; --primary-foreground: 210 40% 98%; --secondary: 210 40% 96.1%; --secondary-foreground: 222.2 47.4% 11.2%; --muted: 210 40% 96.1%; --muted-foreground: 215.4 16.3% 46.9%; --accent: 210 40% 96.1%; --accent-foreground: 222.2 47.4% 11.2%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 210 40% 98%; --border: 214.3 31.8% 91.4%; --input: 214.3 31.8% 91.4%; --ring: 221.2 83.2% 53.3%; --radius: 0.5rem; } .dark { --background: 222.2 84.9% 4.9%; --foreground: 210 40% 98%; --card: 222.2 84.9% 4.9%; --card-foreground: 210 40% 98%; --popover: 222.2 84.9% 4.9%; --popover-foreground: 210 40% 98%; --primary: 217.2 91.2% 59.8%; --primary-foreground: 222.2 47.4% 11.2%; --secondary: 217.2 32.6% 17.5%; --secondary-foreground: 210 40% 98%; --muted: 217.2 32.6% 17.5%; --muted-foreground: 215 20.2% 65.1%; --accent: 217.2 32.6% 17.5%; --accent-foreground: 210 40% 98%; --destructive: 0 62.8% 30.6%; --destructive-foreground: 210 40% 98%; --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; --ring: 224.9 98.6% 67.3%; } } @layer components { .container { @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8; } } """, "postcss.config.js": """module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, }, }""", "tailwind.config.js": """/** @type {import('tailwindcss').Config} */ module.exports = { darkMode: ["class"], content: [ './pages/**/*.{js,jsx}', './components/**/*.{js,jsx}', './app/**/*.{js,jsx}', './src/**/*.{js,jsx}', ], prefix: "", theme: { container: { center: true, padding: "2rem", screens: { "2xl": "1400px", }, }, extend: { colors: { border: "hsl(var(--border))", input: "hsl(var(--input))", ring: "hsl(var(--ring))", background: "hsl(var(--background))", foreground: "hsl(var(--foreground))", primary: { DEFAULT: "hsl(var(--primary))", foreground: "hsl(var(--primary-foreground))", }, secondary: { DEFAULT: "hsl(var(--secondary))", foreground: "hsl(var(--secondary-foreground))", }, destructive: { DEFAULT: "hsl(var(--destructive))", foreground: "hsl(var(--destructive-foreground))", }, muted: { DEFAULT: "hsl(var(--muted))", foreground: "hsl(var(--muted-foreground))", }, accent: { DEFAULT: "hsl(var(--accent))", foreground: "hsl(var(--accent-foreground))", }, popover: { DEFAULT: "hsl(var(--popover))", foreground: "hsl(var(--popover-foreground))", }, card: { DEFAULT: "hsl(var(--card))", foreground: "hsl(var(--card-foreground))", }, }, borderRadius: { lg: "var(--radius)", md: "calc(var(--radius) - 2px)", sm: "calc(var(--radius) - 4px)", }, keyframes: { "accordion-down": { from: { height: "0" }, to: { height: "var(--radix-accordion-content-height)" }, }, "accordion-up": { from: { height: "var(--radix-accordion-content-height)" }, to: { height: "0" }, }, }, animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", }, }, }, plugins: [require("tailwindcss-animate")], }""", "src/components/ui/button.jsx": """import * as React from "react" import { cn } from "@/lib/utils" import { Slot } from "@radix-ui/react-slot" import { cva } from "class-variance-authority"; const buttonVariants = cva( "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-accent-foreground", { variants: { variant: { default: "bg-primary text-primary-foreground hover:bg-primary/90", destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90", outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "underline-offset-4 hover:underline text-primary", }, size: { default: "h-10 px-4 py-2", sm: "h-9 rounded-md px-3", lg: "h-11 rounded-md px-8", icon: "h-10 w-10", }, }, defaultVariants: { variant: "default", size: "default", }, } ) const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => { const Comp = asChild ? Slot : "button" return () }) Button.displayName = "Button" export { Button, buttonVariants }""", "src/components/ui/card.jsx": """import * as React from "react" import { cn } from "@/lib/utils" const Card = React.forwardRef(({ className, ...props }, ref) => (
)) Card.displayName = "Card" const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
)) CardHeader.displayName = "CardHeader" const CardTitle = React.forwardRef(({ className, ...props }, ref) => (

)) CardTitle.displayName = "CardTitle" const CardDescription = React.forwardRef(({ className, ...props }, ref) => (

)) CardDescription.displayName = "CardDescription" const CardContent = React.forwardRef(({ className, ...props }, ref) => (

)) CardContent.displayName = "CardContent" const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
)) CardFooter.displayName = "CardFooter" export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }""", "src/lib/utils.js": """import { clsx } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs) { return twMerge(clsx(inputs)) }""" }, "post_process": "shadcn_setup" }, "fastapi": { "files": { "main.py": """from fastapi import FastAPI app = FastAPI() @app.get("/") async def read_root(): return {"Hello": "World from FastAPI"} """, "requirements.txt": "fastapi\nuvicorn", ".gitignore": "__pycache__/\nvenv/\n" } }, "nextjs": { "files": { "package.json": """{ "name": "nextjs-app", "version": "0.1.0", "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint" }, "dependencies": { "@types/node": "20.8.9", "@types/react": "18.2.33", "@types/react-dom": "18.2.14", "eslint": "8.52.0", "eslint-config-next": "14.0.0", "next": "14.0.0", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "5.2.2" } }""", "next.config.js": """/** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, } module.exports = nextConfig""", "pages/index.js": """import Head from 'next/head' import styles from '../styles/Home.module.css' export default function Home() { return (
Create Next App

Welcome to Next.js!

Get started by editing{' '} pages/index.js

) }""", "styles/Home.module.css": """.container { min-height: 100vh; padding: 0 0.5rem; display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; } .main { padding: 5rem 0; flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; } .footer { width: 100%; height: 100px; border-top: 1px solid #eaeaea; display: flex; justify-content: center; align-items: center; } .footer img { margin-left: 0.5rem; } .footer a { display: flex; justify-content: center; align-items: center; } .title a { color: #0070f3; text-decoration: none; } .title a:hover, .title a:focus, .title a:active { text-decoration: underline; } .title { margin: 0; line-height: 1.15; font-size: 4rem; } .title, .description { text-align: center; } .description { line-height: 1.5; font-size: 1.5rem; } .code { background: #fafafa; border-radius: 5px; padding: 0.75rem; font-size: 1.1rem; font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace; } .logo { height: 1em; margin-left: 0.5rem; } @media (max-width: 600px) { .grid { width: 100%; flex-direction: column; } }""", "pages/_app.js": """import '../styles/globals.css' function MyApp({ Component, pageProps }) { return } export default MyApp""", "pages/api/hello.js": """// Next.js API route support: https://nextjs.org/docs/api-routes/introduction export default function handler(req, res) { res.status(200).json({ text: 'Hello' }) }""", "package-lock.json": """{ "name": "nextjs-app", "version": "0.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "nextjs-app", "version": "0.1.0", "private": true, "dependencies": { "@types/node": "20.8.9", "@types/react": "18.2.33", "@types/react-dom": "18.2.14", "eslint": "8.52.0", "eslint-config-next": "14.0.0", "next": "14.0.0", "react": "18.2.0", "react-dom": "18.2.0", "typescript": "5.2.2" } }, "node_modules/@babel/code-frame": { "version": "7.23.5", #"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", #"integrity": "sha512-...", "dependencies": { "@babel/highlight": "^7.22.16" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { "version": "7.23.4", #"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", #"integrity": "sha512-...", "dependencies": { "chalk": "^2.0.0", "esutils": "^2.0.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@cnakazawa/describe-type": { "version": "2.1.1", #"resolved": "https://registry.npmjs.org/@cnakazawa/describe-type/-/describe-type-2.1.1.tgz", #"integrity": "sha512-...", }, "node_modules/@eslint/eslintrc": { "version": "2.1.1", #"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", #"integrity": "sha512-...", "dependencies": { "ajv": "^6.12.2", "chalk": "^2.0.0", "functional-red-black-tree": "^1.0.1", "ignore": "^5.1.7", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", "json-stable-stringify-without-jsonify": "^1.0.3", "semver": "^6.3.0", "strip-json-comments": "^3.1.1" }, "engines": { "node": "^10.0.0 || >= 12.0.0" } }, "node_modules/@eslint/js": { "version": "8.52.0", #"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", #"integrity": "sha512-...", "engines": { "node": "^10.0.0 || >= 12.0.0" } }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.12", # "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.12.tgz", #"integrity": "sha512-...", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.3.4", "semver": "^7.5.4" }, "engines": { "node": ">=14.18.0" } }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", #"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", #"integrity": "sha512-...", "engines": { "node": ">=12" } }, "node_modules/@jest/types": { "version": "29.6.3", #"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", #"integrity": "sha512-...", "dependencies": { "@types/jest": "*", "@types/node": "*", "expect-type": "0.8.1" } }, "node_modules/@next/env": { "version": "14.0.0", #"resolved": "https://registry.npmjs.org/@next/env/-/env-14.0.0.tgz", #"integrity": "sha512-...", }, "node_modules/@npmcli/ci-detect": { "version": "2.0.1", #"resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-2.0.1.tgz", #"integrity": "sha512-...", }, "node_modules/@radix-ui/react-slot": { "version": "1.0.2", #"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz", #"integrity": "sha512-...", }, "node_modules/@radix-ui/slot": { "version": "1.0.2", #"resolved": "https://registry.npmjs.org/@radix-ui/slot/-/slot-1.0.2.tgz", #"integrity": "sha512-...", "peerDependencies": { "react": "*" } }, "node_modules/@rollup/plugin-commonjs": { "version": "25.0.7", #"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz", #"integrity": "sha512-...", "peerDependencies": { "rollup": "^1.20.0||^2||^3" }, "peerDependenciesMeta": { "rollup": { "optional": true } } }, "node_modules/@rollup/plugin-inject": { "version": "5.1.0", #"resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.1.0.tgz", #"integrity": "sha512-...", "peerDependencies": { "rollup": "^1.20.0||^2||^3" }, "peerDependenciesMeta": { "rollup": { "optional": true } } }, "node_modules/@stylistic/eslint-plugin-js": { "version": "1.5.1", #"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.5.1.tgz", #"integrity": "sha512-...", "dependencies": { "@stylistic/eslint-plugin-plus": "1.5.1", "globals": "^13.20.0" }, "peerDependencies": { "eslint": ">=8.0.0" } }, "node_modules/@stylistic/eslint-plugin-plus": { "version": "1.5.1", #"resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.5.1.tgz", #"integrity": "sha512-...", "peerDependencies": { "eslint": ">=8.0.0" } }, "node_modules/@stylistic/js": { "version": "1.5.1", #"resolved": "https://registry.npmjs.org/@stylistic/js/-/js-1.5.1.tgz", #"integrity": "sha512-...", "engines": { "node": ">=14.0.0" } }, "node_modules/@svgr/plugin-jsx": { "version": "8.1.4", #"resolved": "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-8.1.4.tgz", #"integrity": "sha512-...", "dependencies": { "@babel/plugin-syntax-jsx": "^7.18.6", "@svgr/babel-preset": "8.1.4", "@svgr/core": "8.1.4", "@svgr/plugin-prettier": "8.1.4", "@svgr/plugin-svgo": "8.1.4", "camelcase": "^6.0.0", "semver": "^7.3.5" }, "engines": { "node": ">=14" } }, "node_modules/@tsconfig/cypress": { "version": "3.0.0", #"resolved": "https://registry.npmjs.org/@tsconfig/cypress/-/cypress-3.0.0.tgz", #"integrity": "sha512-...", "peerDependencies": { "typescript": ">=4.5" } }, "node_modules/@tsconfig/create-react-app": { "version": "2.0.1", #"resolved": "https://registry.npmjs.org/@tsconfig/create-react-app/-/create-react-app-2.0.1.tgz", #"integrity": "sha512-...", "peerDependencies": { "typescript": ">=3.8" } }, "node_modules/@tsconfig/node-lts-strictest": { "version": "20.1.1", #"resolved": "https://registry.npmjs.org/@tsconfig/node-lts-strictest/-/node-lts-strictest-20.1.1.tgz", #"integrity": "sha512-...", "peerDependencies": { "typescript": ">=4.8" } }, "node_modules/@types/babel__core": { "version": "7.20.3", #"resolved": "https://registry.npmjs.org/@types/babel__core/-/core-7.20.3.tgz", #"integrity": "sha512-...", "dependencies": { "@babel/parser": "*", "@types/babel__generator": "*", "@types/babel__template": "*", "@types/babel__traverse": "*", "@types/semver": "*" } }, "node_modules/@types/babel__generator": { "version": "7.6.8", #"resolved": "https://registry.npmjs.org/@types/babel__generator/-/generator-7.6.8.tgz", #"integrity": "sha512-...", }, "node_modules/@types/babel__template": { "version": "7.4.5", #"resolved": "https://registry.npmjs.org/@types/babel__template/-/template-7.4.5.tgz", #"integrity": "sha512-...", }, "node_modules/@types/babel__traverse": { "version": "7.20.5", #"resolved": "https://registry.npmjs.org/@types/babel__traverse/-/traverse-7.20.5.tgz", #"integrity": "sha512-...", "dependencies": { "@types/babel__parser": "*" } }, "node_modules/@types/chalk": { "version": "2.2.0", #"resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz", #"integrity": "sha512-...", }, "node_modules/@types/color-name": { "version": "1.1.3", #"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.3.tgz", #"integrity": "sha512-...", }, "node_modules/@types/eslint": { "version": "8.44.7", #"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.7.tgz", #"integrity": "sha512-...", "dependencies": { "@jest/types": "*", "@types/estree": "*", "@types/json-schema": "*", "@types/node": "*" } }, "node_modules/@types/estree": { "version": "2.0.0", #"resolved": "https://registry.npmjs.org/@types/estree/-/estree-2.0.0.tgz", #"integrity": "sha512-...", }, "node_modules/@types/glob": { "version": "8.1.0", #"resolved": "https://registry.npmjs.org/@types/glob/-/glob-8.1.0.tgz", #"integrity": "sha512-...", "dependencies": { "@types/node": "*" } }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.1", #"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", #"integrity": "sha512-...", }, "node_modules/@types/jest": { "version": "29.5.5", #"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.5.tgz", #"integrity": "sha512-...", "dependencies": { "@types/estree": "*", "@types/node": "*", "@types/promises-aplus": "*", "@types/testing-library__dom": "*", "@types/ungap__structured-clone": "*", "expect-type": "0.8.1" } }, "node_modules/@types/json-schema": { "version": "7.0.12", #"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", #"integrity": "sha512-...", }, "node_modules/@types/json5": { "version": "0.0.2", #"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.2.tgz", #"integrity": "sha512-...", }, "node_modules/@types/minimatch": { "version": "5.1.0", #"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.0.tgz", #"integrity": "sha512-...", }, "node_modules/@types/node": { "version": "20.8.9", #"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.9.tgz", #"integrity": "sha512-...", }, "node_modules/@types/parse-json": { "version": "4.0.0", #"resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", #"integrity": "sha512-...", }, "node_modules/@types/prettier": { "version": "2.7.3", #"resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", #"integrity": "sha512-...", }, "node_modules/@types/promises-aplus": { "version": "2.0.5", #"resolved": "https://registry.npmjs.org/@types/promises-aplus/-/promises-aplus-2.0.5.tgz", #"integrity": "sha512-...", "dependencies": { "@types/node": "*" } }, "node_modules/@types/react": { "version": "18.2.33", #"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.33.tgz", #"integrity": "sha512-...", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.5" } }, "node_modules/@types/react-dom": { "version": "18.2.14", #"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.14.tgz", #"integrity": "sha512-...", "dependencies": { "@types/react": "*" } }, "node_modules/@types/resolve": { "version": "1.20.2", #"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", #"integrity": "sha512-...", }, "node_modules/@types/scheduler": { "version": "0.16.4", #"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", #"integrity": "sha512-...", }, "node_modules/@types/semver": { "version": "7.5.3", #"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", #"integrity": "sha512-...", }, "node_modules/@types/stack-trace-parser": { "version": "1.3.2", #"resolved": "https://registry.npmjs.org/@types/stack-trace-parser/-/stack-trace-parser-1.3.2.tgz", #"integrity": "sha512-...", }, "node_modules/@types/testing-library__dom": { "version": "7.5.0", #"resolved": "https://registry.npmjs.org/@types/testing-library__dom/-/dom-7.5.0.tgz", #"integrity": "sha512-...", "dependencies": { "@types/node": "*" } }, "node_modules/@types/ungap__structured-clone": { "version": "0.3.0", #"resolved": "https://registry.npmjs.org/@types/ungap__structured-clone/-/structured-clone-0.3.0.tgz", #"integrity": "sha512-...", }, "node_modules/@vercel/nft": { "version": "0.25.0", #"resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.25.0.tgz", #"integrity": "sha512-...", "dependencies": { "@types/glob": "^8.0.0", "cacache": "^16.1.0", "esbuild": "0.19.5", "fast-glob": "^3.2.12", "ignore": "^7.0.0", "ora": "^5.4.1", "resolve": "^1.22.8", "walker": "^1.0.8" }, "engines": { "node": ">=16.7.0" } }, "node_modules/ajv": { "version": "6.12.6", #"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", #"integrity": "sha512-...", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" }, "engines": { "node": ">=6.9" } }, "node_modules/ansi-styles": { "version": "3.2.1", #"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", #"integrity": "sha512-...", "dependencies": { "color-convert": "^1.9.0" }, "engines": { "node": ">=4" } }, "node_modules/arg": { "version": "5.0.2", #"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", #"integrity": "sha512-...", "engines": { "node": ">=14" } }, "node_modules/assert": { "version": "1.5.0", #"resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", #"integrity": "sha512-...", "dependencies": { "ieee754": "^1.1.13", "util": "0.10.4" } }, "node_modules/autoprefixer": { "version": "10.4.16", #"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", #"integrity": "sha512-...", "dependencies": { "browserslist": "^4.22.1", "caniuse-lite": "1.0.30015751", "chokidar": "^3.5.3", "escalade": "^3.1.1", "nanoid": "^3.3.6", "picocolors": "^1.0.0", "postcss": "^8.4.31", "postcss-value-parser": "^6.0.5" }, "funding": { "url": "https://opencollective.com/postcss" }, "peerDependencies": { "postcss": "^8.1.0" } }, "node_modules/balanced-match": { "version": "1.0.2", #"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", #"integrity": "sha512-...", }, "node_modules/browserslist": { "version": "4.22.2", #"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", #"integrity": "sha512-...", "funding": { "type": "opencollective", "url": "https://opencollective.com/browserslist" }, "engines": { "node": ">=6" } }, "node_modules/cacache": { "version": "16.1.1", #"resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.1.tgz", #"integrity": "sha512-...", "dependencies": { "@npmcli/ci-detect": "^2.0.0", "@npmcli/fs": "^3.1.0", "@npmcli/move-file": "^2.0.0", "chownr": "^3.0.0", "fs-minipass": "^3.0.0", "lru-cache": "^7.1.5", "minipass": "^5.0.0", "minipass-collect": "^2.0.0", "minipass-fetch": "^2.0.3", "minipass-pipeline": "^1.2.0", "minipass-sized": "^2.0.0", "mkdirp": "^1.0.4", "rimraf": "^4.1.0", "ssri": "^9.0.0", "tar": "^6.1.11" }, "engines": { "node": ">=12" } }, "node_modules/camelcase": { "version": "6.3.0", #"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", #"integrity": "sha512-...", "engines": { "node": ">=10" } }, "node_modules/caniuse-lite": { "version": "1.0.30015751", #"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30015751.tgz", #"integrity": "sha512-...", }, "node_modules/chalk": { "version": "2.4.2", #"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", #"integrity": "sha512-...", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", "supports-color": "^5.3.0" }, "engines": { "node": ">=4" } }, "node_modules/chokidar": { "version": "3.5.3", #"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", #"integrity": "sha512-...", "dependencies": { "anymatch": "~3.1.3", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.3", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.16.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/chownr": { "version": "3.0.0", #"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", #"integrity": "sha512-...", "engines": { "node": ">=12" } }, "node_modules/class-variance-authority": { "version": "0.7.0", #"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz", #"integrity": "sha512-...", }, "node_modules/cli-boxes": { "version": "2.2.1", #"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", #"integrity": "sha512-...", "engines": { "node": ">=12" } }, "node_modules/clsx": { "version": "2.1.0", #"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", #"integrity": "sha512-...", }, "node_modules/color-convert": { "version": "1.9.3", #"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", #"integrity": "sha512-...", "dependencies": { "color-name": "1.1.3" }, "engines": { "node": ">=0.4.0" } }, "node_modules/color-name": { "version": "1.1.3", #"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", #"integrity": "sha512-...", "engines": { "node": ">=0.1.90" } }, export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }""", "src/lib/utils.js": """import { clsx } from "clsx" import { twMerge } from "tailwind-merge" export function cn(...inputs) { return twMerge(clsx(inputs)) }""" }, "post_process": "shadcn_setup" }, } def get_file_content(owner, repo_name, path, branch="main"): """Fetches file content from a GitHub repository.""" url = f"https://raw.githubusercontent.com/{owner}/{repo_name}/{branch}/{path}" try: response = requests.get(url) response.raise_for_status() return response.text except requests.exceptions.RequestException as e: return f"Error fetching file: {e}" def extract_repo_info(url): """Extracts owner and repo name from a GitHub URL.""" match = re.search(r"github\.com/([^/]+)/([^/]+)", url) return match.group(1), match.group(2) if match else (None, None) def analyze_file_content(content, file_path): """Analyzes file content and returns statistics.""" lines = content.splitlines() word_count = sum(len(line.split()) for line in lines) line_count = len(lines) file_extension = file_path.split('.')[-1].lower() if '.' in file_path else "unknown" return { "line_count": line_count, "word_count": word_count, "file_extension": file_extension, } def github_tool( action: str, repo_name: str = None, branch: str = "main", path: str = None, content: str = None, message: str = None, owner: str = None, vcs_url: str = None, title: str = None, body: str = None, base: str = None, head: str = None, issue_number: int = None, labels: str = None, tag: str = None, name: str = None, file_url: str = None, repo_url: str = None, template_name: str = None, template_params: dict = None, diff: str = None, diff_message: str = None, new_description: str = None, issue_title: str = None, issue_body: str = None, issue_state: str = None, **kwargs ): """Manages GitHub repositories.""" user = g.get_user() try: if action == "import_repository": if not all([owner, repo_name, vcs_url]): raise ValueError("Missing parameters: owner, repo_name, vcs_url") try: user.get_repo(repo_name) return "Repository already exists." except GithubException: pass headers = { 'Authorization': f'token {GITHUB_TOKEN}', 'Accept': 'application/vnd.github.v3+json', } import_url = f'https://api.github.com/repos/{owner}/{repo_name}/import' response = requests.put(import_url, json={'vcs_url': vcs_url, 'vcs': 'git'}, headers=headers) response.raise_for_status() return "Repository import started." elif action == "create_repository": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.create_repo(name=repo_name) return f"Repository **{repo_name}** created! [Open repository]({repo.html_url})" elif action == "create_project_from_template": if not all([repo_name, template_name]): raise ValueError("Missing parameters: repo_name, template_name") if template_name not in PROJECT_TEMPLATES: raise ValueError( f"Unknown template: {template_name}. Available: {', '.join(PROJECT_TEMPLATES.keys())}" ) repo = user.create_repo(name=repo_name) template = PROJECT_TEMPLATES[template_name] template_params_final = {} if "params" in template: for param_name, param_config in template["params"].items(): template_params_final[param_name] = template_params.get(param_name, param_config.get("default")) if template_params else param_config.get("default") repo_name_snake_case = repo_name.replace("-", "_") readme_filename = "README.md" env = jinja2.Environment() for file_path, file_content in template["files"].items(): final_file_path = file_path final_file_content = file_content if "rename_files" in template: for old_name, new_name_template in template["rename_files"].items(): if file_path == old_name: final_file_path = new_name_template.replace("{{repo_name_snake_case}}", repo_name_snake_case).replace("{{repo_name}}", repo_name).replace("{{readme_filename}}", readme_filename) template_render = env.from_string(final_file_content) final_file_content = template_render.render( repo_name=repo_name, repo_name_snake_case=repo_name_snake_case, readme_filename=readme_filename, **template_params_final ) repo.create_file( final_file_path, f"Create {final_file_path} from template {template_name}", final_file_content, branch="main", ) if "post_process" in template: post_process_action = template["post_process"] if post_process_action == "install_dependencies": print( f"Post-processing: install_dependencies for {repo_name} (Not fully implemented in this example).") elif post_process_action == "shadcn_setup": instructions = f""" **Konfiguracja Shadcn UI wymaga dodatkowych kroków po stronie klienta!** 1. **Sklonuj repozytorium:** `git clone https://github.com/{user.login}/{repo_name}.git` 2. **Przejdź do katalogu projektu:** `cd {repo_name}` 3. **Zainstaluj zależności:** `npm install` (lub `yarn install`, `pnpm install`) 4. **Zainicjuj Shadcn UI:** `npx shadcn-ui@latest init` 5. **Uruchom aplikację:** `npm run dev` (lub odpowiednia komenda dla Twojego menedżera pakietów) Po wykonaniu tych kroków, Twoja aplikacja Shadcn UI będzie w pełni skonfigurowana i gotowa do rozwoju. """ return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})\n\n{instructions}" else: print(f"Unknown post-process action: {post_process_action}") return f"Repository **{repo_name}** created from template **{template_name}**! [Open repository]({repo.html_url})" elif action == "create_file": if not all([repo_name, path, content, message]): raise ValueError("Missing parameters: repo_name, path, content, message") repo = user.get_repo(repo_name) repo.create_file(path, message, content, branch=branch) return f"File **`{path}`** created in repository **`{repo_name}`** on branch **`{branch}`**." elif action == "get_file": if not all([repo_name, path]): raise ValueError("Missing parameters: repo_name, path") repo = user.get_repo(repo_name) file_content = repo.get_contents(path, ref=branch) return ( f"File content of **`{path}`** from **`{repo_name}`**:\n\n`\n{file_content.decoded_content.decode()}\n`" ) elif action == "get_file_content_by_url": if not file_url: raise ValueError("Missing parameter: file_url") file_content = get_file_content(None, None, None, None) return f"File content from URL **`{file_url}`**:\n\n`\n{file_content}\n`" elif action == "delete_file": if not all([repo_name, path]): raise ValueError("Missing parameters: repo_name, path") repo = user.get_repo(repo_name) file_contents = repo.get_contents(path, ref=branch) repo.delete_file(path, "Delete file", file_contents.sha, branch=branch) return f"File **`{path}`** deleted from repository **`{repo_name}`** on branch **`{branch}`**." elif action == "update_file": if not all([repo_name, path, content, message]): raise ValueError("Missing parameters: repo_name, path, content, message") repo = user.get_repo(repo_name) file_contents = repo.get_contents(path, ref=branch) repo.update_file(path, message, content, file_contents.sha, branch=branch) return f"File **`{path}`** updated in repository **`{repo_name}`** on branch **`{branch}`**." elif action == "update_file_diff": if not all([repo_name, path, diff, diff_message]): raise ValueError("Missing parameters: repo_name, path, diff, diff_message") repo = user.get_repo(repo_name) file_contents = repo.get_contents(path, ref=branch) current_content_text = file_contents.decoded_content.decode() dmp = diff_match_patch() try: patches = dmp.patch_fromText(diff) except ValueError: raise ValueError("Invalid patch format. Please provide a valid patch in 'diff' format.") patched_content_tuple = dmp.patch_apply(patches, current_content_text) patched_content_text = patched_content_tuple[0] patch_results = patched_content_tuple[1] if not any(patch_results): raise ValueError("Failed to apply patch. Diff might be outdated or invalid.") repo.update_file(path, diff_message, patched_content_text, file_contents.sha, branch=branch) return f"File **`{path}`** updated using diff in repository **`{repo_name}`** on branch **`{branch}`**." elif action == "list_branches": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.get_repo(repo_name) branches = repo.get_branches() branch_list = "\n".join([f"- `{branch.name}`" for branch in branches]) return f"Branches in repository **`{repo_name}`**:\n{branch_list}" elif action == "create_branch": if not all([repo_name, base, head]): raise ValueError("Missing parameters: repo_name, base, head") repo = user.get_repo(repo_name) source_branch = repo.get_branch(base) repo.create_git_ref(ref=f"refs/heads/{head}", sha=source_branch.commit.sha) return f"Branch **`{head}`** created from **`{base}`** in repository **`{repo_name}`**." elif action == "delete_branch": if not all([repo_name, branch]): raise ValueError("Missing parameters: repo_name, branch") repo = user.get_repo(repo_name) repo.get_git_ref(f"heads/{branch}").delete() return f"Branch **`{branch}`** deleted from repository **`{repo_name}`**." elif action == "create_pull_request": if not all([repo_name, title, body, base, head]): raise ValueError("Missing parameters: repo_name, title, body, base, head") repo = user.get_repo(repo_name) pr = repo.create_pull(title=title, body=body, base=base, head=head) return f"Pull request created! [Open Pull Request]({pr.html_url})" elif action == "list_open_pull_requests": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.get_repo(repo_name) open_prs = repo.get_pulls(state='open') if not open_prs: return f"No open pull requests in repository **`{repo_name}`**." prs_list = "\n".join([f"- [{pr.title}]({pr.html_url})" for pr in open_prs]) return f"Open pull requests in repository **`{repo_name}`**:\n{prs_list}" elif action == "create_issue": if not all([repo_name, title, body]): raise ValueError("Missing parameters: repo_name, title, body") repo = user.get_repo(repo_name) issue = repo.create_issue(title=title, body=body) return f"Issue created! [Open Issue]({issue.html_url})" elif action == "list_issues": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.get_repo(repo_name) issues = repo.get_issues(state='open') if not issues: return f"No open issues in repository **`{repo_name}`**." issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues]) return f"Open issues in repository **`{repo_name}`**:\n{issues_list}" elif action == "add_label_to_issue": if not all([repo_name, issue_number, labels]): raise ValueError("Missing parameters: repo_name, issue_number, labels") repo = user.get_repo(repo_name) issue = repo.get_issue(number=int(issue_number)) for label in labels.split(","): issue.add_to_labels(label.strip()) return ( f"Labels **`{labels}`** added to issue **#{issue_number}** in repository **`{repo_name}`**." ) elif action == "close_issue": if not all([repo_name, issue_number]): raise ValueError("Missing parameters: repo_name, issue_number") repo = user.get_repo(repo_name) issue = repo.get_issue(number=int(issue_number)) issue.edit(state='closed') return f"Issue **#{issue_number}** closed in repository **`{repo_name}`**." elif action == "add_comment_to_issue": if not all([repo_name, issue_number, message]): raise ValueError("Missing parameters: repo_name, issue_number, message") repo = user.get_repo(repo_name) issue = repo.get_issue(number=int(issue_number)) issue.create_comment(body=message) return f"Comment added to issue **#{issue_number}** in repository **`{repo_name}`**." elif action == "create_release": if not all([repo_name, tag, name, message]): raise ValueError("Missing parameters: repo_name, tag, name, message") repo = user.get_repo(repo_name) release = repo.create_git_release(tag=tag, name=name, message=message) return ( f"Release **`{name}`** created in repository **`{repo_name}`**! [Open Release]({release.html_url})" ) elif action == "list_releases": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.get_repo(repo_name) releases = repo.get_releases() if not releases: return f"No releases in repository **`{repo_name}`**." releases_list = "\n".join([f"- [{release.tag_name}]({release.html_url})" for release in releases]) return f"Releases in repository **`{repo_name}`**:\n{releases_list}" elif action == "fork_repository": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = g.get_repo(repo_name) fork = user.create_fork(repo) return f"Repository **`{repo_name}`** forked! [Open fork]({fork.html_url})" elif action == "list_forks": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = g.get_repo(repo_name) forks = repo.get_forks() if not forks: return f"No forks of repository **`{repo_name}`**." forks_list = "\n".join([f"- [{fork.full_name}]({fork.html_url})" for fork in forks]) return f"Forks of repository **`{repo_name}`**:\n{forks_list}" elif action == "list_files": if not all([owner, repo_name]): raise ValueError("Missing parameters: owner, repo_name") repo = g.get_repo(f"{owner}/{repo_name}") contents = repo.get_contents("" if not path else path) if not contents: return f"No files in path **`{path}`** of repository **`{repo_name}`**." files_list = "\n".join([f"- [{content.name}]({content.download_url})" for content in contents]) return f"Files in path **`{path}`** of repository **`{repo_name}`**:\n{files_list}" elif action == "get_repository_info": if not all([owner, repo_name]): raise ValueError("Missing parameters: owner, repo_name") repo = g.get_repo(f"{owner}/{repo_name}") info = { "Name": repo.name, "Description": repo.description, "URL": repo.html_url, "Owner": repo.owner.login, "Default branch": repo.default_branch, "Language": repo.language, "Stars": repo.stargazers_count, "Forks": repo.forks_count, "Created at": str(repo.created_at), "Last updated": str(repo.updated_at), } info_md = "\n".join([f"- **{key}**: {value}" for key, value in info.items()]) return f"Repository info for **`{repo_name}`**:\n{info_md}" elif action == "get_file_content": if not all([owner, repo_name, path]): raise ValueError("Missing parameters: owner, repo_name, path") content_text = get_file_content(owner, repo_name, path, branch) return ( f"File content of **`{path}`** from repository **`{repo_name}`**:\n\n`\n{content_text}\n`" ) elif action == "analyze_repository_by_url": if not repo_url: raise ValueError("Missing parameter: repo_url") owner, repo_name = extract_repo_info(repo_url) if not owner or not repo_name: raise ValueError("Invalid repository URL") repo = g.get_repo(f"{owner}/{repo_name}") contents = repo.get_contents("") file_analyses = [] for content in contents: if content.type == "file": file_content = content.decoded_content.decode() analysis = analyze_file_content(file_content, content.path) file_analyses.append({ "name": content.name, "path": content.path, "analysis": analysis, }) analysis_md = "Repository file analysis:\n" + "\n".join([ f"- **{f['path']}**:\n" f" - Lines: {f['analysis']['line_count']}\n" f" - Words: {f['analysis']['word_count']}\n" f" - Extension: {f['analysis']['file_extension']}" for f in file_analyses ]) return analysis_md elif action == "analyze_repository_content": if not all([owner, repo_name]): raise ValueError("Missing parameters: owner, repo_name") repo = g.get_repo(f"{owner}/{repo_name}") contents = repo.get_contents("") file_analyses = [] for content in contents: if content.type == "file": file_content = get_file_content(owner, repo_name, content.path, branch) analysis = analyze_file_content(file_content, content.path) file_analyses.append({ "name": content.name, "path": content.path, "analysis": analysis, }) analysis_md = "Repository content analysis:\n" + "\n".join([ f"- **{f['path']}**:\n" f" - Lines: {f['analysis']['line_count']}\n" f" - Words: {f['analysis']['word_count']}\n" f" - Extension: {f['analysis']['file_extension']}" for f in file_analyses ]) return analysis_md elif action == "delete_repository": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.get_repo(repo_name) repo.delete() return f"Repository **`{repo_name}`** deleted!" elif action == "update_repository_description": if not all([repo_name, new_description]): raise ValueError("Missing parameters: repo_name, new_description") repo = user.get_repo(repo_name) repo.edit(description=new_description) return f"Repository **`{repo_name}`** description updated to: \"{new_description}\"" elif action == "edit_issue": if not all([repo_name, issue_number]): raise ValueError("Missing parameters: repo_name, issue_number") repo = user.get_repo(repo_name) issue = repo.get_issue(number=int(issue_number)) issue_update_params = {} if issue_title is not None: issue_update_params['title'] = issue_title if issue_body is not None: issue_update_params['body'] = issue_body if issue_state is not None: issue_update_params['state'] = issue_state if not issue_update_params: raise ValueError("No issue details to update provided (title, body, or state)") issue.edit(**issue_update_params) updated_fields = ", ".join(issue_update_params.keys()) return f"Issue **#{issue_number}** in repository **`{repo_name}`** updated fields: {updated_fields}" elif action == "list_closed_issues": if not repo_name: raise ValueError("Missing parameter: repo_name") repo = user.get_repo(repo_name) issues = repo.get_issues(state='closed') if not issues: return f"No closed issues in repository **`{repo_name}`**." issues_list = "\n".join([f"- [{issue.title}]({issue.html_url})" for issue in issues]) return f"Closed issues in repository **`{repo_name}`**:\n{issues_list}" elif action == "get_issue_details": if not all([repo_name, issue_number]): raise ValueError("Missing parameters: repo_name, issue_number") repo = user.get_repo(repo_name) issue = repo.get_issue(number=int(issue_number)) comments = issue.get_comments() details = f""" **Issue #{issue.number}: {issue.title}** State: {issue.state} Created At: {issue.created_at} Author: {issue.user.login} **Body:** {issue.body} **Comments:** """ if comments: for comment in comments: details += f""" --- **{comment.user.login}** at {comment.created_at}: {comment.body} **\n** """ else: details += "No comments." return details else: raise ValueError(f"Unknown action: {action}") except GithubException as e: return f"**GitHub Error:** {e}" except ValueError as e: return f"**Error:** {e}" except requests.exceptions.RequestException as e: return f"**Connection Error:** {e}" except Exception as e: return f"**Unexpected Error:** {e}" with gr.Blocks() as demo: gr.Markdown("# GitHub Tool Plugingit (Simplified Interface)") with gr.Column(): action = gr.Dropdown( choices=[ "import_repository", "create_repository", "create_project_from_template", "create_file", "get_file", "get_file_content_by_url", "delete_file", "update_file", "update_file_diff", "list_branches", "create_branch", "delete_branch", "create_pull_request", "list_open_pull_requests", "create_issue", "list_issues", "list_closed_issues", "get_issue_details", "add_label_to_issue", "close_issue", "add_comment_to_issue", "create_release", "list_releases", "fork_repository", "list_forks", "list_files", "get_repository_info", "analyze_repository_by_url", "analyze_repository_content", "delete_repository", "update_repository_description", "edit_issue" ], label="Select Action", ) repo_name = gr.Textbox(label="Repository Name") template_name = gr.Dropdown( choices=[""] + list(PROJECT_TEMPLATES.keys()), label="Project Template", value="", allow_custom_value=True, ) template_params_ui = {} with gr.Row(): for template_key, template_config in PROJECT_TEMPLATES.items(): if "params" in template_config: with gr.Column(visible=False, elem_classes=f"params_{template_key}") as params_section: for param_name, param_details in template_config["params"].items(): if param_details["type"] == "choice": template_params_ui[param_name] = gr.Dropdown( choices=param_details["choices"], label=param_details["description"] or param_name, value=param_details["default"] ) else: template_params_ui[param_name] = gr.Textbox( label=param_details["description"] or param_name, value=param_details["default"] if "default" in param_details else "" ) template_params_ui[template_key] = params_section branch = gr.Textbox(label="Branch", value="main") path = gr.Textbox(label="File Path") content = gr.Code(label="File Content", lines=5, language='python', visible=True) diff = gr.Code(label="Diff Content", lines=5, language="python", visible=False) message = gr.Textbox(label="Message/Comment", visible=True) diff_message = gr.Textbox(label="Diff Message", visible=False) owner = gr.Textbox(label="Owner") vcs_url = gr.Textbox(label="VCS URL") title = gr.Textbox(label="Title") body = gr.Textbox(label="Body") base = gr.Textbox(label="Base Branch") head = gr.Textbox(label="Head Branch/New Branch") issue_number = gr.Number(label="Issue Number", precision=0) labels = gr.Textbox(label="Labels (comma-separated)") tag = gr.Textbox(label="Tag") release_name = gr.Textbox(label="Release Name") file_url = gr.Textbox(label="File URL") repo_url = gr.Textbox(label="Repository URL") new_description = gr.Textbox(label="New Repository Description", visible=False) issue_title = gr.Textbox(label="New Issue Title", visible=False) issue_body = gr.Textbox(label="New Issue Body", visible=False, lines=3) issue_state = gr.Dropdown( label="New Issue State (open/closed)", choices=["open", "closed"], # Remove None from choices value=None, visible=False ) def show_template_params(template_name): visibility_map = {key: gr.Column.update(visible=False) for key in PROJECT_TEMPLATES if "params" in PROJECT_TEMPLATES[key]} if template_name and template_name in PROJECT_TEMPLATES and "params" in PROJECT_TEMPLATES[template_name]: visibility_map[template_name] = gr.Column.update(visible=True) return [visibility_map.get(key, gr.Column.update(visible=False)) for key in PROJECT_TEMPLATES if "params" in PROJECT_TEMPLATES[key]] template_param_visibility_outputs = [template_params_ui[key] for key in PROJECT_TEMPLATES if "params" in PROJECT_TEMPLATES[key]] template_name.change( show_template_params, inputs=[template_name], outputs=template_param_visibility_outputs ) run_button = gr.Button("Execute") output = gr.Markdown(label="Result") input_components = [ action, repo_name, branch, path, content, message, owner, vcs_url, title, body, base, head, issue_number, labels, tag, release_name, file_url, repo_url, template_name, new_description, issue_title, issue_body, issue_state, diff, diff_message ] for template_key in PROJECT_TEMPLATES: if "params" in PROJECT_TEMPLATES[template_key]: for param_name in template_params_ui: if param_name in PROJECT_TEMPLATES[template_key]["params"]: input_components.append(template_params_ui[param_name]) def show_hide_input_fields(action_name): visibility_map = { "repo_name": gr.Textbox.update(visible=False), "branch": gr.Textbox.update(visible=False), "path": gr.Textbox.update(visible=False), "content": gr.Code.update(visible=False), "diff": gr.Code.update(visible=False), "message": gr.Textbox.update(visible=False), "diff_message": gr.Textbox.update(visible=False), "owner": gr.Textbox.update(visible=False), "vcs_url": gr.Textbox.update(visible=False), "title": gr.Textbox.update(visible=False), "body": gr.Textbox.update(visible=False), "base": gr.Textbox.update(visible=False), "head": gr.Textbox.update(visible=False), "issue_number": gr.Number.update(visible=False), "labels": gr.Textbox.update(visible=False), "tag": gr.Textbox.update(visible=False), "release_name": gr.Textbox.update(visible=False), "file_url": gr.Textbox.update(visible=False), "repo_url": gr.Textbox.update(visible=False), "template_name": gr.Dropdown.update(visible=False), "new_description": gr.Textbox.update(visible=False), "issue_title": gr.Textbox.update(visible=False), "issue_body": gr.Textbox.update(visible=False), "issue_state": gr.Dropdown.update(visible=False), } if action_name in ["import_repository"]: visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "owner": gr.Textbox.update(visible=True), "vcs_url": gr.Textbox.update(visible=True)}) elif action_name in ["create_repository", "delete_repository", "list_branches", "list_open_pull_requests", "list_issues", "list_closed_issues", "list_releases", "list_forks"]: visibility_map.update({"repo_name": gr.Textbox.update(visible=True)}) elif action_name == "create_project_from_template": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "template_name": gr.Dropdown.update(visible=True)}) elif action_name in ["create_file", "get_file", "delete_file", "get_file_content"]: visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "path": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True)}) if action_name == "create_file": visibility_map.update({"content": gr.Code.update(visible=True), "message": gr.Textbox.update(visible=True)}) elif action_name == "update_file": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "path": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True), "content": gr.Code.update(visible=True), "message": gr.Textbox.update(visible=True)}) elif action_name == "update_file_diff": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "path": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True), "diff": gr.Code.update(visible=True), "diff_message": gr.Textbox.update(visible=True)}) elif action_name == "get_file_content_by_url": visibility_map.update({"file_url": gr.Textbox.update(visible=True)}) elif action_name in ["create_branch", "delete_branch"]: visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "branch": gr.Textbox.update(visible=True)}) if action_name == "create_branch": visibility_map.update({"base": gr.Textbox.update(visible=True), "head": gr.Textbox.update(visible=True)}) elif action_name == "create_pull_request": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "title": gr.Textbox.update(visible=True), "body": gr.Textbox.update(visible=True), "base": gr.Textbox.update(visible=True), "head": gr.Textbox.update(visible=True)}) elif action_name == "create_issue": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "title": gr.Textbox.update(visible=True), "body": gr.Textbox.update(visible=True)}) elif action_name == "add_label_to_issue": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "issue_number": gr.Number.update(visible=True), "labels": gr.Textbox.update(visible=True)}) elif action_name in ["close_issue", "add_comment_to_issue", "get_issue_details", "edit_issue"]: visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "issue_number": gr.Number.update(visible=True)}) if action_name == "add_comment_to_issue": visibility_map.update({"message": gr.Textbox.update(visible=True)}) if action_name == "edit_issue": visibility_map.update({"issue_title": gr.Textbox.update(visible=True), "issue_body": gr.Textbox.update(visible=True), "issue_state": gr.Dropdown.update(visible=True)}) elif action_name == "create_release": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "tag": gr.Textbox.update(visible=True), "release_name": gr.Textbox.update(visible=True), "message": gr.Textbox.update(visible=True)}) elif action_name == "fork_repository": visibility_map.update({"repo_name": gr.Textbox.update(visible=True)}) elif action_name in ["list_files", "get_repository_info", "analyze_repository_content"]: visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "owner": gr.Textbox.update(visible=True)}) elif action_name == "analyze_repository_by_url": visibility_map.update({"repo_url": gr.Textbox.update(visible=True)}) elif action_name == "update_repository_description": visibility_map.update({"repo_name": gr.Textbox.update(visible=True), "new_description": gr.Textbox.update(visible=True)}) return [visibility_map.get(key, gr.Textbox.update(visible=False)) for key in visibility_map] output_components_visibility = [ repo_name, branch, path, content, message, owner, vcs_url, title, body, base, head, issue_number, labels, tag, release_name, file_url, repo_url, template_name, new_description, issue_title, issue_body, issue_state, diff, diff_message ] action.change( show_hide_input_fields, inputs=[action], outputs=output_components_visibility ) run_button.click( github_tool, inputs=input_components, outputs=output, api_name="github_tool" ) demo.launch()