|
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 |
|
|
|
|
|
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN') |
|
if not GITHUB_TOKEN: |
|
raise ValueError("GITHUB_TOKEN environment variable not set!") |
|
g = Github(GITHUB_TOKEN) |
|
|
|
|
|
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"], |
|
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() |