package main import ( "fmt" "log" "os" "github.com/gin-gonic/gin" "sproutclaw-web/internal/config" "sproutclaw-web/internal/db" "sproutclaw-web/internal/handlers" "sproutclaw-web/internal/middleware" "sproutclaw-web/internal/rpc" "sproutclaw-web/internal/static" ) func main() { cfg := config.New() log.Printf("[sproutclaw-web] port=%d agent-dir=%s repo-root=%s", cfg.Port, cfg.AgentDir, cfg.RepoRoot) // Database (stores in backend/data) database, err := db.Init(cfg.DataDir) if err != nil { log.Fatalf("db init: %v", err) } defer database.Close() log.Printf("[sproutclaw-web] db: %s", database.DbPath) // pi CLI RPC client piClient, err := rpc.NewClient(cfg.PiCmd, cfg.PiArgs, cfg.RepoRoot, cfg.AgentDir, func(code int) { if code != 0 { log.Printf("[sproutclaw-web] pi CLI exited with code %d, shutting down", code) os.Exit(1) } os.Exit(0) }) if err != nil { log.Fatalf("pi client: %v", err) } defer piClient.Stop() // Gin router gin.SetMode(gin.ReleaseMode) r := gin.New() r.Use(gin.Logger(), gin.Recovery()) r.Use(middleware.CORS()) // API routes api := r.Group("/api") handlers.RegisterChat(api, piClient) handlers.RegisterSessions(api, cfg, database, piClient) handlers.RegisterModels(api, cfg, piClient) handlers.RegisterCommands(api, cfg) handlers.RegisterWebuiConfig(api, database) handlers.RegisterSettings(api, cfg, database, piClient) handlers.RegisterTerminal(api, cfg) handlers.RegisterExtensionUI(api, piClient) // Static files (production: frontend/dist/) static.Register(r, cfg.FrontendDist) addr := fmt.Sprintf("0.0.0.0:%d", cfg.Port) log.Printf("[sproutclaw-web] listening on http://0.0.0.0:%d (LAN: http://<本机IP>:%d)", cfg.Port, cfg.Port) if err := r.Run(addr); err != nil { log.Fatalf("server: %v", err) } }