feat: agregar agente build-wails para apps desktop

Nuevo agente para crear y compilar aplicaciones Wails (Go + React).
Soporta compilación cross-platform: Linux, Windows, macOS.
Incluye script de creación de proyecto con DevFactory y frontend-lib integrados.
This commit is contained in:
2026-03-22 19:00:07 +01:00
parent 8f7dbcf196
commit 1529e55d25
8 changed files with 1113 additions and 0 deletions
@@ -0,0 +1,47 @@
# Dockerfile para compilar proyectos Wails en CI/CD
# Soporta Linux AMD64 y Windows AMD64 (cross-compile)
#
# Uso:
# docker build -t wails-builder -f Dockerfile.wails-builder .
# docker run -v $(pwd):/app wails-builder make build-all
FROM golang:1.22-bookworm
# Evitar prompts interactivos
ENV DEBIAN_FRONTEND=noninteractive
# Instalar dependencias de sistema
RUN apt-get update && apt-get install -y --no-install-recommends \
# Wails/Linux dependencies
libgtk-3-dev \
libwebkit2gtk-4.0-dev \
# Windows cross-compile
gcc-mingw-w64-x86-64 \
# NSIS para instaladores Windows
nsis \
# Node.js
nodejs \
npm \
# Utilidades
git \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Instalar pnpm
RUN npm install -g pnpm
# Instalar Wails
RUN go install github.com/wailsapp/wails/v2/cmd/wails@latest
# Instalar UPX para compresión (opcional)
RUN apt-get update && apt-get install -y --no-install-recommends upx \
&& rm -rf /var/lib/apt/lists/*
# Variables de entorno para cross-compile
ENV PATH="/go/bin:${PATH}"
ENV CGO_ENABLED=1
WORKDIR /app
# Entry point por defecto
CMD ["make", "build-all"]
@@ -0,0 +1,134 @@
# Makefile para proyecto Wails
# Uso: make [target]
APP_NAME := $(shell basename $(CURDIR))
VERSION := $(shell git describe --tags --always --dirty 2>/dev/null || echo "dev")
BUILD_DIR := build/bin
LDFLAGS := -ldflags="-s -w -X main.Version=$(VERSION)"
# Colores
GREEN := \033[0;32m
YELLOW := \033[1;33m
NC := \033[0m
.PHONY: help dev build build-linux build-windows build-all clean install doctor
help: ## Mostrar esta ayuda
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(GREEN)%-20s$(NC) %s\n", $$1, $$2}'
# ============================================
# DESARROLLO
# ============================================
dev: ## Iniciar en modo desarrollo con hot reload
@echo "$(GREEN)Starting dev mode...$(NC)"
wails dev
dev-debug: ## Desarrollo con DevTools abiertos
@echo "$(GREEN)Starting dev mode with DevTools...$(NC)"
wails dev -devtools
generate: ## Generar bindings Go <-> TypeScript
@echo "$(GREEN)Generating bindings...$(NC)"
wails generate module
# ============================================
# BUILD
# ============================================
build: ## Build para la plataforma actual
@echo "$(GREEN)Building for current platform...$(NC)"
wails build $(LDFLAGS)
build-prod: ## Build optimizado para producción
@echo "$(GREEN)Building optimized for production...$(NC)"
wails build -clean -trimpath $(LDFLAGS)
build-linux: ## Build para Linux AMD64
@echo "$(GREEN)Building for Linux AMD64...$(NC)"
wails build -platform linux/amd64 -clean -trimpath $(LDFLAGS)
build-linux-arm: ## Build para Linux ARM64
@echo "$(GREEN)Building for Linux ARM64...$(NC)"
wails build -platform linux/arm64 -clean -trimpath $(LDFLAGS)
build-windows: ## Build para Windows AMD64 (cross-compile)
@echo "$(GREEN)Building for Windows AMD64...$(NC)"
@echo "$(YELLOW)Requires: gcc-mingw-w64-x86-64$(NC)"
wails build -platform windows/amd64 -clean -trimpath $(LDFLAGS)
build-windows-nsis: ## Build para Windows con instalador NSIS
@echo "$(GREEN)Building Windows installer...$(NC)"
@echo "$(YELLOW)Requires: nsis$(NC)"
wails build -platform windows/amd64 -nsis -clean -trimpath $(LDFLAGS)
build-all: build-linux build-windows ## Build para Linux y Windows
@echo "$(GREEN)All builds completed!$(NC)"
@ls -lah $(BUILD_DIR)/
build-upx: ## Build con compresión UPX
@echo "$(GREEN)Building with UPX compression...$(NC)"
@echo "$(YELLOW)Note: May trigger antivirus false positives$(NC)"
wails build -upx -clean -trimpath $(LDFLAGS)
# ============================================
# UTILIDADES
# ============================================
clean: ## Limpiar archivos de build
@echo "$(GREEN)Cleaning build artifacts...$(NC)"
rm -rf $(BUILD_DIR)
rm -rf frontend/dist
rm -rf frontend/node_modules/.vite
install-deps: ## Instalar dependencias del frontend
@echo "$(GREEN)Installing frontend dependencies...$(NC)"
cd frontend && pnpm install
update-deps: ## Actualizar dependencias
@echo "$(GREEN)Updating dependencies...$(NC)"
go get -u ./...
cd frontend && pnpm update
doctor: ## Verificar instalación de Wails
@echo "$(GREEN)Running Wails doctor...$(NC)"
wails doctor
# ============================================
# CROSS-COMPILE SETUP
# ============================================
setup-windows-cross: ## Instalar herramientas para cross-compile a Windows
@echo "$(GREEN)Installing Windows cross-compile tools...$(NC)"
sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64 nsis
setup-linux-deps: ## Instalar dependencias de Linux para Wails
@echo "$(GREEN)Installing Linux dependencies...$(NC)"
sudo apt-get update
sudo apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev
# ============================================
# RELEASE
# ============================================
release: build-all ## Crear release con todos los binarios
@echo "$(GREEN)Creating release package...$(NC)"
@mkdir -p release
@cp $(BUILD_DIR)/$(APP_NAME) release/$(APP_NAME)-$(VERSION)-linux-amd64 2>/dev/null || true
@cp $(BUILD_DIR)/$(APP_NAME).exe release/$(APP_NAME)-$(VERSION)-windows-amd64.exe 2>/dev/null || true
@cd release && sha256sum * > checksums.txt
@echo "$(GREEN)Release files:$(NC)"
@ls -lah release/
# ============================================
# INFO
# ============================================
info: ## Mostrar información del proyecto
@echo "App: $(APP_NAME)"
@echo "Version: $(VERSION)"
@echo "Go: $(shell go version)"
@echo "Wails: $(shell wails version 2>/dev/null || echo 'not installed')"
@echo "Node: $(shell node --version 2>/dev/null || echo 'not installed')"
@echo "pnpm: $(shell pnpm --version 2>/dev/null || echo 'not installed')"
+111
View File
@@ -0,0 +1,111 @@
package main
import (
"context"
"fmt"
"runtime"
"github.com/lucasdataproyects/devfactory/core"
"github.com/wailsapp/wails/v2/pkg/runtime"
)
// App struct - métodos públicos se exponen al frontend
type App struct {
ctx context.Context
}
// NewApp crea una nueva instancia de App
func NewApp() *App {
return &App{}
}
// startup se llama cuando la app inicia
func (a *App) startup(ctx context.Context) {
a.ctx = ctx
}
// domReady se llama cuando el DOM está listo
func (a *App) domReady(ctx context.Context) {
// Inicializaciones que requieren el DOM
}
// shutdown se llama cuando la app se cierra
func (a *App) shutdown(ctx context.Context) {
// Cleanup resources
}
// ============================================
// MÉTODOS EXPUESTOS AL FRONTEND
// ============================================
// Greet retorna un saludo
func (a *App) Greet(name string) string {
return fmt.Sprintf("Hello %s, from Go!", name)
}
// GetSystemInfo retorna información del sistema
func (a *App) GetSystemInfo() map[string]string {
return map[string]string{
"os": runtime.GOOS,
"arch": runtime.GOARCH,
"cpus": fmt.Sprintf("%d", runtime.NumCPU()),
"goVersion": runtime.Version(),
}
}
// OpenFileDialog abre un diálogo para seleccionar archivo
func (a *App) OpenFileDialog() core.Result[string] {
file, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "Seleccionar archivo",
Filters: []runtime.FileFilter{
{DisplayName: "Todos los archivos", Pattern: "*.*"},
},
})
if err != nil {
return core.Err[string](err)
}
return core.Ok(file)
}
// SaveFileDialog abre un diálogo para guardar archivo
func (a *App) SaveFileDialog(defaultFilename string) core.Result[string] {
file, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
Title: "Guardar archivo",
DefaultFilename: defaultFilename,
})
if err != nil {
return core.Err[string](err)
}
return core.Ok(file)
}
// ShowMessage muestra un mensaje al usuario
func (a *App) ShowMessage(title, message string) {
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.InfoDialog,
Title: title,
Message: message,
})
}
// ShowError muestra un error al usuario
func (a *App) ShowError(title, message string) {
runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.ErrorDialog,
Title: title,
Message: message,
})
}
// Confirm muestra un diálogo de confirmación
func (a *App) Confirm(title, message string) bool {
result, _ := runtime.MessageDialog(a.ctx, runtime.MessageDialogOptions{
Type: runtime.QuestionDialog,
Title: title,
Message: message,
Buttons: []string{"Sí", "No"},
DefaultButton: "Sí",
CancelButton: "No",
})
return result == "Sí"
}
@@ -0,0 +1,210 @@
#!/bin/bash
# Script para crear un nuevo proyecto Wails con DevFactory + Frontend_Library
# Uso: ./create-wails-project.sh <nombre-proyecto> [directorio-destino]
set -e
# ============================================
# CONFIGURACIÓN
# ============================================
PROJECT_NAME="${1:-mi-wails-app}"
DEST_DIR="${2:-.}"
FULL_PATH="$DEST_DIR/$PROJECT_NAME"
DEVFACTORY_PATH="$HOME/.local_agentes/backend"
FRONTEND_LIB_PATH="$HOME/.local_agentes/frontend/frontend"
TEMPLATES_PATH="$(dirname "$0")"
# Colores
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() { echo -e "${GREEN}[✓]${NC} $1"; }
warn() { echo -e "${YELLOW}[!]${NC} $1"; }
error() { echo -e "${RED}[✗]${NC} $1"; exit 1; }
info() { echo -e "${BLUE}[i]${NC} $1"; }
# ============================================
# VALIDACIONES
# ============================================
info "Verificando requisitos..."
if ! command -v wails &> /dev/null; then
error "Wails no está instalado. Ejecuta: go install github.com/wailsapp/wails/v2/cmd/wails@latest"
fi
if ! command -v pnpm &> /dev/null; then
error "pnpm no está instalado. Ejecuta: npm install -g pnpm"
fi
if [ -d "$FULL_PATH" ]; then
error "El directorio $FULL_PATH ya existe"
fi
# ============================================
# CREAR PROYECTO
# ============================================
info "Creando proyecto Wails: $PROJECT_NAME"
# Crear proyecto base con Wails
wails init -n "$PROJECT_NAME" -t react-ts -d "$DEST_DIR"
cd "$FULL_PATH"
log "Proyecto base creado"
# ============================================
# CONFIGURAR GO.WORK (DevFactory)
# ============================================
info "Configurando go.work para DevFactory..."
if [ -d "$DEVFACTORY_PATH" ]; then
go work init
go work use . "$DEVFACTORY_PATH"
log "go.work configurado con DevFactory"
else
warn "DevFactory no encontrado en $DEVFACTORY_PATH"
warn "Configúralo manualmente con: go work use ~/.local_agentes/backend"
fi
# ============================================
# CONFIGURAR FRONTEND
# ============================================
info "Configurando frontend..."
cd frontend
# Cambiar a pnpm
rm -f package-lock.json yarn.lock
pnpm install
# Agregar frontend-lib si existe
if [ -d "$FRONTEND_LIB_PATH" ]; then
pnpm add "@anthropic/frontend-lib@link:$FRONTEND_LIB_PATH"
log "frontend-lib vinculado"
else
warn "Frontend_Library no encontrado en $FRONTEND_LIB_PATH"
fi
cd ..
# ============================================
# ACTUALIZAR wails.json
# ============================================
info "Actualizando wails.json..."
cat > wails.json << EOF
{
"\$schema": "https://wails.io/schemas/config.v2.json",
"name": "$PROJECT_NAME",
"outputfilename": "$PROJECT_NAME",
"frontend:dir": "frontend",
"frontend:install": "pnpm install",
"frontend:build": "pnpm build",
"frontend:dev:watcher": "pnpm dev",
"frontend:dev:serverUrl": "auto",
"wailsjsdir": "frontend/src/wailsjs",
"author": {
"name": "$(git config user.name 2>/dev/null || echo 'Developer')",
"email": "$(git config user.email 2>/dev/null || echo 'dev@example.com')"
},
"info": {
"companyName": "$PROJECT_NAME",
"productName": "$PROJECT_NAME",
"productVersion": "1.0.0",
"copyright": "Copyright $(date +%Y)",
"comments": "Built with Wails"
}
}
EOF
log "wails.json actualizado para pnpm"
# ============================================
# COPIAR MAKEFILE
# ============================================
if [ -f "$TEMPLATES_PATH/Makefile" ]; then
cp "$TEMPLATES_PATH/Makefile" ./Makefile
log "Makefile copiado"
fi
# ============================================
# CREAR .gitignore
# ============================================
cat > .gitignore << 'EOF'
# Build
build/bin/
frontend/dist/
# Dependencies
frontend/node_modules/
# Go
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
vendor/
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Wails
frontend/src/wailsjs/
# Env
.env
.env.local
EOF
log ".gitignore creado"
# ============================================
# INICIALIZAR GIT
# ============================================
if [ ! -d ".git" ]; then
git init
git add .
git commit -m "feat: initial Wails project with DevFactory + Frontend_Library"
log "Repositorio Git inicializado"
fi
# ============================================
# RESUMEN
# ============================================
echo ""
echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}"
echo -e "${GREEN} Proyecto Wails creado exitosamente!${NC}"
echo -e "${GREEN}═══════════════════════════════════════════════════════════════${NC}"
echo ""
echo -e " ${BLUE}Directorio:${NC} $FULL_PATH"
echo ""
echo -e " ${BLUE}Comandos disponibles:${NC}"
echo -e " make dev - Desarrollo con hot reload"
echo -e " make build - Build para plataforma actual"
echo -e " make build-linux - Build para Linux"
echo -e " make build-windows - Build para Windows"
echo -e " make build-all - Build para todas las plataformas"
echo -e " make help - Ver todos los comandos"
echo ""
echo -e " ${BLUE}Próximos pasos:${NC}"
echo -e " cd $FULL_PATH"
echo -e " make dev"
echo ""
# Verificar wails doctor
info "Ejecutando wails doctor..."
wails doctor || warn "Algunos requisitos pueden faltar. Revisa la salida anterior."
@@ -0,0 +1,8 @@
go 1.22
use (
.
// DevFactory - librería Go funcional
// Descomentar y ajustar path si usas DevFactory
// ~/.local_agentes/backend
)
@@ -0,0 +1,71 @@
package main
import (
"embed"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
"github.com/wailsapp/wails/v2/pkg/options/linux"
"github.com/wailsapp/wails/v2/pkg/options/mac"
"github.com/wailsapp/wails/v2/pkg/options/windows"
)
//go:embed all:frontend/dist
var assets embed.FS
func main() {
app := NewApp()
err := wails.Run(&options.App{
Title: "{{APP_TITLE}}",
Width: 1280,
Height: 800,
MinWidth: 800,
MinHeight: 600,
AssetServer: &assetserver.Options{
Assets: assets,
},
BackgroundColour: &options.RGBA{R: 15, G: 23, B: 42, A: 1}, // slate-900
OnStartup: app.startup,
OnShutdown: app.shutdown,
OnDomReady: app.domReady,
Bind: []interface{}{
app,
},
// Windows options
Windows: &windows.Options{
WebviewIsTransparent: false,
WindowIsTranslucent: false,
DisableWindowIcon: false,
DisableFramelessWindowDecorations: false,
WebviewUserDataPath: "",
Theme: windows.SystemDefault,
},
// Linux options
Linux: &linux.Options{
ProgramName: "{{APP_NAME}}",
WebviewGpuPolicy: linux.WebviewGpuPolicyAlways,
WindowIsTranslucent: false,
},
// macOS options
Mac: &mac.Options{
TitleBar: &mac.TitleBar{
TitlebarAppearsTransparent: true,
HideTitle: false,
HideTitleBar: false,
FullSizeContent: false,
UseToolbar: false,
HideToolbarSeparator: true,
},
About: &mac.AboutInfo{
Title: "{{APP_TITLE}}",
Message: "Built with Wails + React",
},
},
})
if err != nil {
println("Error:", err.Error())
}
}
@@ -0,0 +1,22 @@
{
"$schema": "https://wails.io/schemas/config.v2.json",
"name": "{{APP_NAME}}",
"outputfilename": "{{APP_NAME}}",
"frontend:dir": "frontend",
"frontend:install": "pnpm install",
"frontend:build": "pnpm build",
"frontend:dev:watcher": "pnpm dev",
"frontend:dev:serverUrl": "auto",
"wailsjsdir": "frontend/src/wailsjs",
"author": {
"name": "{{AUTHOR_NAME}}",
"email": "{{AUTHOR_EMAIL}}"
},
"info": {
"companyName": "{{COMPANY_NAME}}",
"productName": "{{PRODUCT_NAME}}",
"productVersion": "1.0.0",
"copyright": "Copyright {{YEAR}}",
"comments": "Built with Wails"
}
}