gh / app.py
adowu's picture
Update app.py
6b7ea31 verified
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'<HelloWorld {self.message}>'
@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": """<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>""",
"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(
<React.StrictMode>
<App />
</React.StrictMode>,
)""",
"src/App.jsx": """import React from 'react'
import './App.css'
function App() {
return (
<>
<h1>Hello from React!</h1>
</>
)
}
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": """<!DOCTYPE html>
<html>
<head>
<title>Simple Static Website</title>
</head>
<body>
<h1>Hello from Static Website!</h1>
<p>This is a basic HTML page.</p>
</body>
</html>""",
"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": """<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + Shadcn</title>
</head>
<body class="bg-background">
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>""",
"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(
<React.StrictMode>
<App />
</React.StrictMode>,
)""",
"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 (
<div className="container mx-auto py-10">
<h1 className="text-3xl font-bold text-center mb-5">
Witaj w aplikacji Shadcn UI!
</h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<Card>
<CardHeader>
<CardTitle>Karta 1</CardTitle>
<CardDescription>Prosta karta z Shadcn UI.</CardDescription>
</CardHeader>
<CardContent>
<p>Zawartość karty.</p>
<Button className="mt-4">Przycisk Akcji</Button>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Karta 2</CardTitle>
<CardDescription>Kolejna karta dla przykładu.</CardDescription>
</CardHeader>
<CardContent>
<p>Więcej zawartości.</p>
<Button variant="secondary" className="mt-4">Przycisk Wtórny</Button>
</CardContent>
</Card>
<Card className="lg:col-span-1 md:col-span-2">
<CardHeader>
<CardTitle>Dłuższa Karta</CardTitle>
<CardDescription>Karta zajmująca więcej miejsca.</CardDescription>
</CardHeader>
<CardContent>
<p>
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.
</p>
<Button variant="destructive" className="mt-4">Przycisk Destrukcyjny</Button>
</CardContent>
</Card>
</div>
</div>
)
}
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 (<Comp
className={cn(buttonVariants({ variant, size, className }))}
ref={ref} {...props} />)
})
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) => (<div
className={cn("rounded-lg border bg-card text-card-foreground shadow-sm", className)}
ref={ref}
{...props} />))
Card.displayName = "Card"
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (<div
className={cn("flex flex-col space-y-1.5 p-6", className)}
ref={ref}
{...props} />))
CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (<h3
className={cn("text-lg font-semibold leading-none tracking-tight", className)}
ref={ref}
{...props} />))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (<p
className={cn("text-sm text-muted-foreground", className)}
ref={ref}
{...props} />))
CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef(({ className, ...props }, ref) => (<div
className={cn("p-6 pt-0", className)}
ref={ref}
{...props} />))
CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (<div
className={cn("flex items-center p-6 pt-0", className)}
ref={ref}
{...props} />))
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 (
<div className={styles.container}>
<Head>
<title>Create Next App</title>
<link rel="icon" href="/favicon.ico" />
</Head>
<main className={styles.main}>
<h1 className={styles.title}>
Welcome to <a href="https://nextjs.org">Next.js!</a>
</h1>
<p className={styles.description}>
Get started by editing{' '}
<code className={styles.code}>pages/index.js</code>
</p>
</main>
<footer className={styles.footer}>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=default-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Powered by{' '}
<img src="/vercel.svg" alt="Vercel Logo" className={styles.logo} />
</a>
</footer>
</div>
)
}""",
"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 <Component {...pageProps} />
}
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()