#!/usr/bin/env bash set -euo pipefail # ============================================================================= # setup-frontend.sh — Inicializa proyecto React/Vite o Wails desktop # Coherente con Frontend_Library + DevFactory + build-wails agent # ============================================================================= # --- Colores --- RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_ok() { echo -e "${GREEN}[OK]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_step() { echo -e "${CYAN}[STEP]${NC} $1"; } # --- Parámetros --- PROJECT_NAME="" WAILS_MODE=false TARGET_PATH="." while [[ $# -gt 0 ]]; do case "$1" in --wails) WAILS_MODE=true; shift ;; --path) TARGET_PATH="$2"; shift 2 ;; -*) log_error "Flag desconocido: $1"; echo "STATUS: ERROR"; exit 1 ;; *) PROJECT_NAME="$1"; shift ;; esac done # --- Rutas de librerías --- FRONTEND_LIB="$HOME/.local_agentes/frontend/frontend" DEVFACTORY_PATH="$HOME/.local_agentes/backend" TEMPLATES_DIR="$HOME/.local_agentes/frontend/templates/base" WAILS_TEMPLATES="$HOME/.claude/agents/build-wails/templates" # --- Validar nombre --- if [[ -z "$PROJECT_NAME" ]]; then log_error "Uso: setup-frontend.sh [--wails] [--path /ruta]" echo "STATUS: ERROR" exit 1 fi # Normalizar PROJECT_NAME=$(echo "$PROJECT_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g') PROJECT_DIR="$TARGET_PATH/$PROJECT_NAME" # --- Check estado existente --- if [[ -f "$PROJECT_DIR/package.json" ]] || [[ -f "$PROJECT_DIR/wails.json" ]]; then log_warn "El proyecto $PROJECT_NAME ya existe en $PROJECT_DIR" echo "STATUS: CONFIGURED" exit 0 fi # --- Verificar dependencias --- log_step "Verificando dependencias..." if ! command -v pnpm &>/dev/null; then log_error "pnpm no está instalado. Instala con: npm install -g pnpm" echo "STATUS: ERROR" exit 1 fi log_ok "pnpm $(pnpm --version) encontrado" if ! command -v node &>/dev/null; then log_error "Node.js no encontrado" echo "STATUS: ERROR" exit 1 fi log_ok "Node $(node --version) encontrado" if [[ "$WAILS_MODE" == true ]]; then if ! command -v wails &>/dev/null; then log_error "Wails no está instalado. Instala con: go install github.com/wailsapp/wails/v2/cmd/wails@latest" echo "STATUS: ERROR" exit 1 fi log_ok "Wails $(wails version 2>/dev/null | head -1 || echo 'v2.x') encontrado" if ! command -v go &>/dev/null; then log_error "Go no encontrado (requerido para Wails)" echo "STATUS: ERROR" exit 1 fi log_ok "Go $(go version | grep -oP '\d+\.\d+' | head -1) encontrado" fi if [[ ! -d "$FRONTEND_LIB" ]]; then log_warn "Frontend_Library no encontrada en $FRONTEND_LIB — se creará sin link" HAS_FRONTEND_LIB=false else log_ok "Frontend_Library encontrada" HAS_FRONTEND_LIB=true fi # ============================================================================ # MODO WAILS — Desktop app (Go + React) # ============================================================================ if [[ "$WAILS_MODE" == true ]]; then log_step "Creando proyecto Wails '$PROJECT_NAME'..." # Usar wails init con template react-ts wails init -n "$PROJECT_NAME" -t react-ts -d "$TARGET_PATH" 2>/dev/null cd "$PROJECT_DIR" # --- go.work con DevFactory --- if [[ -d "$DEVFACTORY_PATH" ]]; then log_step "Configurando go.work con DevFactory..." cat > go.work << EOF go 1.22 use ( . $DEVFACTORY_PATH ) EOF log_ok "DevFactory enlazado via go.work" fi # --- Configurar frontend con pnpm --- log_step "Configurando frontend con pnpm..." cd frontend # Reemplazar npm por pnpm en wails.json cd .. if [[ -f "wails.json" ]]; then sed -i 's/"npm install"/"pnpm install"/g' wails.json sed -i 's/"npm run dev"/"pnpm dev"/g' wails.json sed -i 's/"npm run build"/"pnpm build"/g' wails.json fi cd frontend # Instalar con pnpm rm -f package-lock.json 2>/dev/null || true pnpm install # --- Linkear Frontend_Library --- if [[ "$HAS_FRONTEND_LIB" == true ]]; then log_step "Linkeando Frontend_Library..." pnpm add "@anthropic/frontend-lib@link:$FRONTEND_LIB" log_ok "@anthropic/frontend-lib linkeada" fi # --- Instalar Tailwind CSS 4 --- log_step "Instalando Tailwind CSS 4..." pnpm add -D tailwindcss @tailwindcss/vite # --- Configurar vite.config.ts con dedupe y tailwind --- log_step "Configurando Vite (dedupe + tailwind)..." cat > vite.config.ts << 'VEOF' import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import { resolve } from 'path' export default defineConfig({ plugins: [react(), tailwindcss()], resolve: { alias: { '@': resolve(__dirname, './src'), '@wails': resolve(__dirname, './wailsjs'), }, dedupe: ['react', 'react-dom'], }, }) VEOF # --- CSS base con Tailwind --- cat > src/style.css << 'CSSEOF' @import "tailwindcss"; CSSEOF # --- Instalar Phosphor Icons --- pnpm add @phosphor-icons/react cd .. # --- Makefile (basado en build-wails agent) --- log_step "Generando Makefile..." cat > Makefile << 'MKEOF' .PHONY: dev dev-debug build build-prod build-linux build-windows build-all clean generate doctor APP_NAME := $(shell basename $(CURDIR)) ## dev: Desarrollo con hot reload dev: wails dev ## dev-debug: Desarrollo con DevTools dev-debug: wails dev -devtools ## build: Build para plataforma actual build: wails build ## build-prod: Build optimizado para producción build-prod: wails build -clean -trimpath -ldflags="-s -w" ## build-linux: Build para Linux AMD64 build-linux: wails build -platform linux/amd64 ## build-windows: Cross-compile para Windows build-windows: wails build -platform windows/amd64 ## build-all: Linux + Windows build-all: build-linux build-windows ## generate: Regenerar bindings TypeScript generate: wails generate module ## clean: Limpiar artefactos clean: rm -rf build/bin frontend/dist ## doctor: Verificar instalación doctor: wails doctor ## help: Muestra esta ayuda help: @grep -E '^## ' Makefile | sed 's/## //' | column -t -s ':' MKEOF # --- .gitignore --- cat >> .gitignore << 'EOF' node_modules/ frontend/dist/ build/bin/ *.exe EOF # --- Resumen Wails --- echo "" log_ok "Proyecto Wails '$PROJECT_NAME' creado en $PROJECT_DIR" echo "" echo -e "${CYAN}Estructura:${NC}" echo " $PROJECT_NAME/" echo " ├── main.go, app.go — Backend Go" echo " ├── go.work — Enlace a DevFactory" echo " ├── frontend/ — React + TypeScript + Vite" echo " │ ├── src/ — Componentes React" echo " │ └── wailsjs/ — Bindings auto-generados" echo " ├── Makefile — dev, build, build-all" echo " └── wails.json — Configuración Wails" echo "" echo -e "${CYAN}Comandos:${NC}" echo " make dev — Desarrollo con hot reload" echo " make build — Compilar app desktop" echo " make build-all — Linux + Windows" echo " make generate — Regenerar bindings TS" echo "" if [[ "$HAS_FRONTEND_LIB" == true ]]; then echo -e "${CYAN}Frontend_Library:${NC}" echo " import { Button, Card } from '@anthropic/frontend-lib'" echo " import { useTheme } from '@anthropic/frontend-lib/hooks'" echo "" fi echo "STATUS: READY" exit 0 fi # ============================================================================ # MODO WEBAPP — React + Vite (sin Wails) # ============================================================================ log_step "Creando proyecto webapp '$PROJECT_NAME'..." mkdir -p "$PROJECT_DIR" cd "$PROJECT_DIR" # --- Usar template de Frontend_Library si existe --- if [[ -d "$TEMPLATES_DIR" ]]; then log_step "Usando template de Frontend_Library..." cp -r "$TEMPLATES_DIR"/* . cp -r "$TEMPLATES_DIR"/.[!.]* . 2>/dev/null || true else log_step "Creando desde cero con Vite..." # package.json cat > package.json << PKGEOF { "name": "$PROJECT_NAME", "private": true, "version": "0.1.0", "type": "module", "scripts": { "dev": "vite", "build": "tsc -b && vite build", "preview": "vite preview" } } PKGEOF # Instalar dependencias base pnpm add react react-dom pnpm add -D typescript @types/react @types/react-dom pnpm add -D vite @vitejs/plugin-react pnpm add -D tailwindcss @tailwindcss/vite # tsconfig.json cat > tsconfig.json << 'TSEOF' { "compilerOptions": { "target": "ES2023", "lib": ["ES2023", "DOM", "DOM.Iterable"], "module": "ESNext", "moduleResolution": "bundler", "jsx": "react-jsx", "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "paths": { "@/*": ["./src/*"] }, "skipLibCheck": true }, "include": ["src"] } TSEOF # vite.config.ts cat > vite.config.ts << 'VEOF' import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import { resolve } from 'path' export default defineConfig({ plugins: [react(), tailwindcss()], resolve: { alias: { '@': resolve(__dirname, './src') }, dedupe: ['react', 'react-dom'], }, }) VEOF # index.html cat > index.html << HTMLEOF $PROJECT_NAME
HTMLEOF # src/ mkdir -p src cat > src/main.tsx << 'TSXEOF' import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' import App from './App' import './app.css' createRoot(document.getElementById('root')!).render( , ) TSXEOF cat > src/App.tsx << 'TSXEOF' function App() { return (

Ready

) } export default App TSXEOF cat > src/app.css << 'CSSEOF' @import "tailwindcss"; CSSEOF fi # --- Linkear Frontend_Library --- if [[ "$HAS_FRONTEND_LIB" == true ]]; then log_step "Linkeando Frontend_Library..." pnpm add "@anthropic/frontend-lib@link:$FRONTEND_LIB" log_ok "@anthropic/frontend-lib linkeada" fi # --- Phosphor Icons --- pnpm add @phosphor-icons/react # --- .gitignore --- cat > .gitignore << 'EOF' node_modules/ dist/ .vite/ *.local EOF # --- Resumen Webapp --- echo "" log_ok "Proyecto webapp '$PROJECT_NAME' creado en $PROJECT_DIR" echo "" echo -e "${CYAN}Estructura:${NC}" echo " $PROJECT_NAME/" echo " ├── src/" echo " │ ├── App.tsx — Componente principal" echo " │ ├── main.tsx — Entry point" echo " │ └── app.css — Tailwind CSS" echo " ├── vite.config.ts — Vite + Tailwind + dedupe" echo " ├── tsconfig.json — TypeScript strict" echo " └── package.json — pnpm" echo "" echo -e "${CYAN}Comandos:${NC}" echo " pnpm dev — Servidor de desarrollo" echo " pnpm build — Build de producción" echo " pnpm preview — Preview del build" echo "" if [[ "$HAS_FRONTEND_LIB" == true ]]; then echo -e "${CYAN}Frontend_Library:${NC}" echo " import { Button, Card } from '@anthropic/frontend-lib'" echo " import { useTheme } from '@anthropic/frontend-lib/hooks'" echo "" fi echo "STATUS: READY"