// Package platform detects the runtime OS and environment, // providing platform-specific paths and configuration defaults. package platform import ( "os" "path/filepath" "runtime" ) // Platform holds information about the current runtime environment. type Platform struct { OS string // "linux", "windows", "darwin" Arch string // "amd64", "arm64" IsTermux bool // Running inside Termux (ANDROID_ROOT set) IsWSL bool // Running inside WSL IsDocker bool // Running inside a Docker container IsWindows bool // runtime.GOOS == "windows" IsLinux bool // runtime.GOOS == "linux" IsDarwin bool // runtime.GOOS == "darwin" IsARM64 bool // runtime.GOARCH == "arm64" } // Detect returns the current platform information. func Detect() *Platform { p := &Platform{ OS: runtime.GOOS, Arch: runtime.GOARCH, IsWindows: runtime.GOOS == "windows", IsLinux: runtime.GOOS == "linux", IsDarwin: runtime.GOOS == "darwin", IsARM64: runtime.GOARCH == "arm64", } // Detect Termux if _, ok := os.LookupEnv("ANDROID_ROOT"); ok { p.IsTermux = true } // Detect WSL if _, err := os.Stat("/proc/sys/fs/binfmt_misc/WSL"); err == nil { p.IsWSL = true } // Detect Docker if _, err := os.Stat("/.dockerenv"); err == nil { p.IsDocker = true } return p } // DataDir returns the default application data directory. func (p *Platform) DataDir() string { home, _ := os.UserHomeDir() switch { case p.IsWindows: return filepath.Join(os.Getenv("APPDATA"), "Cyrene") case p.IsDarwin: return filepath.Join(home, "Library", "Application Support", "Cyrene") case p.IsTermux: return filepath.Join(home, "storage", "shared", "Cyrene") default: // Linux return filepath.Join(home, ".local", "share", "cyrene") } } // ConfigDir returns the default configuration directory. func (p *Platform) ConfigDir() string { home, _ := os.UserHomeDir() switch { case p.IsWindows: return filepath.Join(os.Getenv("APPDATA"), "Cyrene", "config") case p.IsDarwin: return filepath.Join(home, "Library", "Application Support", "Cyrene", "config") case p.IsTermux: return filepath.Join(home, ".config", "cyrene") default: // Linux return filepath.Join(home, ".config", "cyrene") } } // CacheDir returns the default cache directory. func (p *Platform) CacheDir() string { home, _ := os.UserHomeDir() switch { case p.IsWindows: return filepath.Join(os.Getenv("LOCALAPPDATA"), "Cyrene", "cache") case p.IsDarwin: return filepath.Join(home, "Library", "Caches", "Cyrene") default: // Linux / Termux return filepath.Join(home, ".cache", "cyrene") } } // EnsureDirs creates the data, config, and cache directories if they don't exist. func (p *Platform) EnsureDirs() error { for _, dir := range []string{p.DataDir(), p.ConfigDir(), p.CacheDir()} { if err := os.MkdirAll(dir, 0o755); err != nil { return err } } return nil } // DefaultNATSURL returns the default NATS connection URL. func (p *Platform) DefaultNATSURL() string { return "nats://localhost:4222" } // DefaultPGHost returns the default PostgreSQL host. func (p *Platform) DefaultPGHost() string { return "localhost" } // Summary returns a human-readable platform description. func (p *Platform) Summary() string { s := p.OS + "/" + p.Arch var tags []string if p.IsDocker { tags = append(tags, "docker") } if p.IsWSL { tags = append(tags, "wsl") } if p.IsTermux { tags = append(tags, "termux") } if len(tags) > 0 { s += " (" for i, t := range tags { if i > 0 { s += ", " } s += t } s += ")" } return s }