package main import ( "embed" "log" "log/slog" "os" "path/filepath" wraithapp "github.com/vstockwell/wraith/internal/app" "github.com/wailsapp/wails/v3/pkg/application" ) // version is set at build time via -ldflags "-X main.version=..." var version = "dev" //go:embed all:frontend/dist var assets embed.FS func main() { // Set up file logging so we can debug without a console window if logFile := setupFileLogging(); logFile != nil { defer logFile.Close() } slog.Info("starting Wraith", "version", version) wraith, err := wraithapp.New(version) if err != nil { log.Fatalf("failed to initialize: %v", err) } app := application.New(application.Options{ Name: "Wraith", Description: "SSH + RDP + SFTP Desktop Client", Services: []application.Service{ application.NewService(wraith), application.NewService(wraith.Connections), application.NewService(wraith.Themes), application.NewService(wraith.Settings), application.NewService(wraith.SSH), application.NewService(wraith.SFTP), application.NewService(wraith.RDP), application.NewService(wraith.Updater), }, Assets: application.AssetOptions{ Handler: application.BundledAssetFileServer(assets), }, }) // Wire Wails app reference for event emission (SSH output → frontend) wraith.SetWailsApp(app) app.Window.NewWithOptions(application.WebviewWindowOptions{ Title: "Wraith", Width: 1400, Height: 900, URL: "/", BackgroundColour: application.NewRGBA(13, 17, 23, 255), }) if err := app.Run(); err != nil { log.Fatal(err) } } // setupFileLogging configures slog to write to %APPDATA%\Wraith\wraith.log (Windows) // or ~/.local/share/wraith/wraith.log (macOS/Linux). Returns the file handle for deferred close. func setupFileLogging() *os.File { var logDir string if appData := os.Getenv("APPDATA"); appData != "" { logDir = filepath.Join(appData, "Wraith") } else if home, err := os.UserHomeDir(); err == nil { logDir = filepath.Join(home, ".local", "share", "wraith") } else { return nil } os.MkdirAll(logDir, 0755) logPath := filepath.Join(logDir, "wraith.log") f, err := os.OpenFile(logPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644) if err != nil { return nil } handler := slog.NewTextHandler(f, &slog.HandlerOptions{Level: slog.LevelDebug}) slog.SetDefault(slog.New(handler)) log.SetOutput(f) return f }