package utils import ( "fmt" "net" "os" "os/exec" "path/filepath" "runtime" "github.com/sipeed/picoclaw/pkg/config" "github.com/sipeed/picoclaw/pkg/logger" ) // GetPicoclawHome returns the picoclaw home directory. // Priority: $PICOCLAW_HOME > ~/.picoclaw func GetPicoclawHome() string { return config.GetHome() } // GetDefaultConfigPath returns the default path to the picoclaw config file. func GetDefaultConfigPath() string { if configPath := os.Getenv(config.EnvConfig); configPath != "" { return configPath } return filepath.Join(GetPicoclawHome(), "config.json") } // FindPicoclawBinary locates the picoclaw executable. // Search order: // 1. PICOCLAW_BINARY environment variable (explicit override) // 2. Same directory as the current executable // 3. Falls back to "picoclaw" and relies on $PATH func FindPicoclawBinary() string { binaryName := "picoclaw" if runtime.GOOS == "windows" { binaryName = "picoclaw.exe" } if p := os.Getenv(config.EnvBinary); p != "" { if info, _ := os.Stat(p); info != nil && !info.IsDir() { return p } } if exe, err := os.Executable(); err == nil { logger.Debugf("Trying to find picoclaw binary in %s", exe) candidate := filepath.Join(filepath.Dir(exe), binaryName) if info, err := os.Stat(candidate); err == nil && !info.IsDir() { return candidate } } return "picoclaw" } // GetLocalIPv4 returns a non-loopback local IPv4 address. func GetLocalIPv4() string { addrs, err := net.InterfaceAddrs() if err != nil { return "" } for _, a := range addrs { if ipnet, ok := a.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil { return ipnet.IP.String() } } return "" } // GetLocalIPv6 returns a non-loopback local IPv6 address. func GetLocalIPv6() string { addrs, err := net.InterfaceAddrs() if err != nil { return "" } for _, a := range addrs { ipnet, ok := a.(*net.IPNet) if !ok || ipnet.IP == nil { continue } ip := ipnet.IP if ip.IsLoopback() || ip.To4() != nil { continue } if ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() { continue } return ip.String() } return "" } // GetLocalIP returns a non-loopback local IPv4 address for backward compatibility. func GetLocalIP() string { return GetLocalIPv4() } // OpenBrowser automatically opens the given URL in the default browser. func OpenBrowser(url string) error { switch runtime.GOOS { case "linux": return exec.Command("xdg-open", url).Start() case "windows": return exec.Command("rundll32", "url.dll,FileProtocolHandler", url).Start() case "darwin": return exec.Command("open", url).Start() default: return fmt.Errorf("unsupported platform") } }