Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/cli/cmd/adb_expose_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func ExecuteAdbExpose(cmd *cobra.Command, opts *AdbExposeOptions, args []string)
return fmt.Errorf("failed to get API key: %v", err)
}

logPath := fmt.Sprintf("%s/gbox-adb-expose-%s-%d.log", config.GetGboxHome(), opts.BoxID, localPort)
logPath := fmt.Sprintf("%s/gbox-adb-expose-%s-%d.log", config.GetGboxCliHome(), opts.BoxID, localPort)
if shouldReturn, err := adb_expose.DaemonizeIfNeeded(opts.Foreground, logPath, opts.BoxID, true); shouldReturn {
return err
}
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/cmd/device_connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ func ExecuteDeviceConnect(cmd *cobra.Command, opts *DeviceConnectOptions, args [

func isServiceRunning() (bool, error) {
// First check if PID file exists
deviceProxyHome := config.GetDeviceProxyHome()
pidFile := filepath.Join(deviceProxyHome, "device-proxy.pid")
cliCacheHome := config.GetGboxCliHome()
pidFile := filepath.Join(cliCacheHome, "device-proxy.pid")

if _, err := os.Stat(pidFile); os.IsNotExist(err) {
return false, nil
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/cmd/device_connect_kill_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ func NewDeviceConnectKillServerCommand() *cobra.Command {

func ExecuteDeviceConnectKillServer(cmd *cobra.Command, opts *DeviceConnectKillServerOptions) error {
// Check if PID file exists first
deviceProxyHome := config.GetDeviceProxyHome()
pidFile := filepath.Join(deviceProxyHome, "device-proxy.pid")
cliCacheHome := config.GetGboxCliHome()
pidFile := filepath.Join(cliCacheHome, "device-proxy.pid")

pidFileExists := false
var pidFromFile int
Expand Down
121 changes: 69 additions & 52 deletions packages/cli/cmd/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func NewPruneCommand() *cobra.Command {
func runPrune(opts *PruneOptions) error {
// Get cache directories
gboxHome := config.GetGboxHome()
deviceProxyHome := config.GetDeviceProxyHome()
cliHome := config.GetGboxCliHome()

// Ask for confirmation if not forced
if !opts.Force {
Expand All @@ -63,26 +63,29 @@ func runPrune(opts *PruneOptions) error {
var cleanedItems []string
var errors []error

// Prune device proxy cache
if err := pruneDeviceProxyCache(deviceProxyHome, &cleanedItems, &errors); err != nil {
errors = append(errors, fmt.Errorf("failed to prune device proxy cache: %v", err))
// Prune CLI cache directory (contains all cache files)
if err := pruneData(cliHome, opts.All, &cleanedItems, &errors); err != nil {
errors = append(errors, fmt.Errorf("failed to prune CLI cache: %v", err))
}

// Prune other cache files in gbox home
if err := pruneGboxCache(gboxHome, opts.All, &cleanedItems, &errors); err != nil {
errors = append(errors, fmt.Errorf("failed to prune gbox cache: %v", err))
// Prune device-proxy directory (created by device proxy binary at runtime)
deviceProxyHome := filepath.Join(gboxHome, "device-proxy")
if err := pruneDeviceProxyHome(deviceProxyHome, &cleanedItems, &errors); err != nil {
errors = append(errors, fmt.Errorf("failed to prune device-proxy directory: %v", err))
}

// Report results
if len(cleanedItems) > 0 {
fmt.Println("\nCleaned cache items:")
for _, item := range cleanedItems {
fmt.Printf(" - %s\n", item)
// Prune credentials and profiles from gbox home (only if --all is specified)
if opts.All {
if err := pruneCredentialsAndProfiles(gboxHome, &cleanedItems, &errors); err != nil {
errors = append(errors, fmt.Errorf("failed to prune credentials and profiles: %v", err))
}
} else {
fmt.Println("\nNo cache items found to clean.")
}

// Report results
if len(cleanedItems) <= 0 {
fmt.Println("\nNo cache items found to clean.")
}

if len(errors) > 0 {
fmt.Println("\nErrors encountered:")
for _, err := range errors {
Expand All @@ -95,14 +98,14 @@ func runPrune(opts *PruneOptions) error {
return nil
}

// pruneDeviceProxyCache prunes device proxy related cache files
func pruneDeviceProxyCache(deviceProxyHome string, cleanedItems *[]string, errors *[]error) error {
if _, err := os.Stat(deviceProxyHome); os.IsNotExist(err) {
// pruneData prunes all CLI cache files from the unified cache directory
func pruneData(cliHome string, cleanCredentials bool, cleanedItems *[]string, errors *[]error) error {
if _, err := os.Stat(cliHome); os.IsNotExist(err) {
return nil // Directory doesn't exist, nothing to clean
}

// Clean version cache file
versionCachePath := filepath.Join(deviceProxyHome, "version.json")
versionCachePath := filepath.Join(cliHome, "version.json")
if err := os.Remove(versionCachePath); err == nil {
*cleanedItems = append(*cleanedItems, versionCachePath)
} else if !os.IsNotExist(err) {
Expand All @@ -114,15 +117,15 @@ func pruneDeviceProxyCache(deviceProxyHome string, cleanedItems *[]string, error
if runtime.GOOS == "windows" {
binaryName += ".exe"
}
binaryPath := filepath.Join(deviceProxyHome, binaryName)
binaryPath := filepath.Join(cliHome, binaryName)
if err := os.Remove(binaryPath); err == nil {
*cleanedItems = append(*cleanedItems, binaryPath)
} else if !os.IsNotExist(err) {
*errors = append(*errors, fmt.Errorf("failed to remove device proxy binary: %v", err))
}

// Clean any downloaded asset files (tar.gz, zip, etc.)
entries, err := os.ReadDir(deviceProxyHome)
entries, err := os.ReadDir(cliHome)
if err != nil {
return err
}
Expand All @@ -135,7 +138,7 @@ func pruneDeviceProxyCache(deviceProxyHome string, cleanedItems *[]string, error
fileName := entry.Name()
// Check if it's a downloaded asset file
if isAssetFile(fileName) {
assetPath := filepath.Join(deviceProxyHome, fileName)
assetPath := filepath.Join(cliHome, fileName)
if err := os.Remove(assetPath); err == nil {
*cleanedItems = append(*cleanedItems, assetPath)
} else if !os.IsNotExist(err) {
Expand All @@ -144,37 +147,10 @@ func pruneDeviceProxyCache(deviceProxyHome string, cleanedItems *[]string, error
}
}

return nil
}

// pruneGboxCache prunes other gbox cache files
func pruneGboxCache(gboxHome string, cleanCredentials bool, cleanedItems *[]string, errors *[]error) error {
if _, err := os.Stat(gboxHome); os.IsNotExist(err) {
return nil // Directory doesn't exist, nothing to clean
}

// Clean credentials file only if --all is specified
if cleanCredentials {
credentialsPath := filepath.Join(gboxHome, "credentials.json")
if err := os.Remove(credentialsPath); err == nil {
*cleanedItems = append(*cleanedItems, credentialsPath)
} else if !os.IsNotExist(err) {
*errors = append(*errors, fmt.Errorf("failed to remove credentials file: %v", err))
}

// Clean profiles file only if --all is specified
profilesPath := filepath.Join(gboxHome, "profiles.toml")
if err := os.Remove(profilesPath); err == nil {
*cleanedItems = append(*cleanedItems, profilesPath)
} else if !os.IsNotExist(err) {
*errors = append(*errors, fmt.Errorf("failed to remove profiles file: %v", err))
}
}

// Clean log files
logPatterns := []string{"gbox-adb-expose-*.log", "*.log"}
logPatterns := []string{"gbox-adb-expose-*.log", "device-proxy.log", "*.log"}
for _, pattern := range logPatterns {
matches, err := filepath.Glob(filepath.Join(gboxHome, pattern))
matches, err := filepath.Glob(filepath.Join(cliHome, pattern))
if err != nil {
*errors = append(*errors, fmt.Errorf("failed to glob log files with pattern %s: %v", pattern, err))
continue
Expand All @@ -190,9 +166,9 @@ func pruneGboxCache(gboxHome string, cleanCredentials bool, cleanedItems *[]stri
}

// Clean PID files
pidPatterns := []string{"gbox-adb-expose-*.pid", "*.pid"}
pidPatterns := []string{"gbox-adb-expose-*.pid", "device-proxy.pid", "*.pid"}
for _, pattern := range pidPatterns {
matches, err := filepath.Glob(filepath.Join(gboxHome, pattern))
matches, err := filepath.Glob(filepath.Join(cliHome, pattern))
if err != nil {
*errors = append(*errors, fmt.Errorf("failed to glob PID files with pattern %s: %v", pattern, err))
continue
Expand All @@ -210,6 +186,47 @@ func pruneGboxCache(gboxHome string, cleanCredentials bool, cleanedItems *[]stri
return nil
}

// pruneDeviceProxyHome prunes the device-proxy directory created by device proxy binary at runtime
func pruneDeviceProxyHome(deviceProxyHome string, cleanedItems *[]string, errors *[]error) error {
if _, err := os.Stat(deviceProxyHome); os.IsNotExist(err) {
return nil // Directory doesn't exist, nothing to clean
}

// Remove the entire device-proxy directory and all its contents
if err := os.RemoveAll(deviceProxyHome); err != nil {
*errors = append(*errors, fmt.Errorf("failed to remove device-proxy directory: %v", err))
return err
}

*cleanedItems = append(*cleanedItems, deviceProxyHome)
return nil
}

// pruneCredentialsAndProfiles prunes credentials and profiles from gbox home
func pruneCredentialsAndProfiles(gboxHome string, cleanedItems *[]string, errors *[]error) error {
if _, err := os.Stat(gboxHome); os.IsNotExist(err) {
return nil // Directory doesn't exist, nothing to clean
}

// Clean credentials file
credentialsPath := filepath.Join(gboxHome, "credentials.json")
if err := os.Remove(credentialsPath); err == nil {
*cleanedItems = append(*cleanedItems, credentialsPath)
} else if !os.IsNotExist(err) {
*errors = append(*errors, fmt.Errorf("failed to remove credentials file: %v", err))
}

// Clean profiles file
profilesPath := filepath.Join(gboxHome, "profiles.toml")
if err := os.Remove(profilesPath); err == nil {
*cleanedItems = append(*cleanedItems, profilesPath)
} else if !os.IsNotExist(err) {
*errors = append(*errors, fmt.Errorf("failed to remove profiles file: %v", err))
}

return nil
}

// isAssetFile checks if a file is a downloaded asset file
func isAssetFile(fileName string) bool {
assetExtensions := []string{".tar.gz", ".zip", ".exe", ".dmg", ".deb", ".rpm"}
Expand Down
15 changes: 8 additions & 7 deletions packages/cli/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func init() {
v.BindEnv("mcp.server.url", "MCP_SERVER_URL") // Bind MCP server URL env var
v.BindEnv("gbox.home", "GBOX_HOME")
v.BindEnv("device_proxy.home", "DEVICE_PROXY_HOME")
v.BindEnv("cli.cache.home", "GBOX_CLI_HOME") // Bind CLI cache home env var
v.BindEnv("profile.path", "GBOX_PROFILE_PATH") // Bind profile path env var
v.BindEnv("github.client_secret", "GBOX_GITHUB_CLIENT_SECRET")

Expand Down Expand Up @@ -112,13 +113,13 @@ func GetGboxHome() string {
return v.GetString("gbox.home")
}

// GetDeviceProxyHome returns the device proxy home directory
func GetDeviceProxyHome() string {
// Check if device_proxy.home is explicitly set
if deviceProxyHome := v.GetString("device_proxy.home"); deviceProxyHome != "" {
return deviceProxyHome
// GetGboxCliHome returns the CLI cache directory
func GetGboxCliHome() string {
// Check if cli.cache.home is explicitly set
if cliCacheHome := v.GetString("cli.cache.home"); cliCacheHome != "" {
return cliCacheHome
}

// Otherwise, use gbox.home + "/device-proxy"
return filepath.Join(GetGboxHome(), "device-proxy")
// Otherwise, use gbox.home + "/cli"
return filepath.Join(GetGboxHome(), "cli")
}
8 changes: 4 additions & 4 deletions packages/cli/internal/adb_expose/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type PidInfo struct {
}

func ensureGboxDir() error {
dir := config.GetGboxHome()
dir := config.GetGboxCliHome()
return os.MkdirAll(dir, 0700)
}

Expand All @@ -38,11 +38,11 @@ const pidFileNameSuffix = ".pid"
const logFileNameSuffix = ".log"

func pidFilePath(boxId string, localPort int) string {
return config.GetGboxHome() + "/" + pidFileNamePrefix + boxId + "-" + strconv.Itoa(localPort) + pidFileNameSuffix
return config.GetGboxCliHome() + "/" + pidFileNamePrefix + boxId + "-" + strconv.Itoa(localPort) + pidFileNameSuffix
}

func logFilePath(boxId string, localPort int) string {
return config.GetGboxHome() + "/" + pidFileNamePrefix + boxId + "-" + strconv.Itoa(localPort) + logFileNameSuffix
return config.GetGboxCliHome() + "/" + pidFileNamePrefix + boxId + "-" + strconv.Itoa(localPort) + logFileNameSuffix
}

const pidFilePattern = "gbox-adb-expose-*.pid"
Expand Down Expand Up @@ -92,7 +92,7 @@ func RemoveLogFile(boxId string, localPort int) error {
}

func ListPidFiles() ([]PidInfo, error) {
dir := config.GetGboxHome()
dir := config.GetGboxCliHome()
files, err := filepath.Glob(dir + "/" + pidFilePattern)
if err != nil {
return nil, err
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/internal/device_connect/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ func FindDeviceProxyBinary() (string, error) {
}
}

// Priority 3: Check device proxy home directory (where we download binaries)
deviceProxyHome := config.GetDeviceProxyHome()
deviceProxyBinaryPath := filepath.Join(deviceProxyHome, binaryName)
// Priority 3: Check CLI cache directory (where we download binaries)
cliCacheHome := config.GetGboxCliHome()
deviceProxyBinaryPath := filepath.Join(cliCacheHome, binaryName)
if debug {
fmt.Fprintf(os.Stderr, "[DEBUG] Checking device proxy home: %s\n", deviceProxyBinaryPath)
}
Expand Down
13 changes: 7 additions & 6 deletions packages/cli/internal/device_connect/daemon_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ func StartDeviceProxyService() error {
return fmt.Errorf("device proxy binary not found: %v", err)
}

// Create device proxy home directory
deviceProxyHome := config.GetDeviceProxyHome()
if err := os.MkdirAll(deviceProxyHome, 0755); err != nil {
return fmt.Errorf("failed to create device proxy home directory: %v", err)
// Create CLI cache directory
cliCacheHome := config.GetGboxCliHome()
if err := os.MkdirAll(cliCacheHome, 0755); err != nil {
return fmt.Errorf("failed to create CLI cache directory: %v", err)
}

// Create log file
logFile := filepath.Join(deviceProxyHome, "device-proxy.log")
logFile := filepath.Join(cliCacheHome, "device-proxy.log")
logFd, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return fmt.Errorf("failed to create log file: %v", err)
}
defer logFd.Close()

// Create PID file path
pidFile := filepath.Join(deviceProxyHome, "device-proxy.pid")
pidFile := filepath.Join(cliCacheHome, "device-proxy.pid")

// Get API key from current profile
apiKey, err := profile.Default.GetEffectiveAPIKey()
Expand All @@ -53,6 +53,7 @@ func StartDeviceProxyService() error {
cmd.Stdout = logFd
cmd.Stderr = logFd
cmd.Env = env
cmd.Dir = cliCacheHome // Set working directory to CLI cache home

// Set process group to make child process independent
cmd.SysProcAttr = &syscall.SysProcAttr{
Expand Down
13 changes: 7 additions & 6 deletions packages/cli/internal/device_connect/daemon_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,22 @@ func StartDeviceProxyService() error {
return fmt.Errorf("device proxy binary not found: %v", err)
}

// Create device proxy home directory
deviceProxyHome := config.GetDeviceProxyHome()
if err := os.MkdirAll(deviceProxyHome, 0755); err != nil {
return fmt.Errorf("failed to create device proxy home directory: %v", err)
// Create CLI cache directory
cliCacheHome := config.GetGboxCliHome()
if err := os.MkdirAll(cliCacheHome, 0755); err != nil {
return fmt.Errorf("failed to create CLI cache directory: %v", err)
}

// Create log file
logFile := filepath.Join(deviceProxyHome, "device-proxy.log")
logFile := filepath.Join(cliCacheHome, "device-proxy.log")
logFd, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
if err != nil {
return fmt.Errorf("failed to create log file: %v", err)
}
defer logFd.Close()

// Create PID file path
pidFile := filepath.Join(deviceProxyHome, "device-proxy.pid")
pidFile := filepath.Join(cliCacheHome, "device-proxy.pid")

// Get API key from current profile
apiKey, err := profile.Default.GetEffectiveAPIKey()
Expand All @@ -53,6 +53,7 @@ func StartDeviceProxyService() error {
cmd.Stdout = logFd
cmd.Stderr = logFd
cmd.Env = env
cmd.Dir = cliCacheHome // Set working directory to CLI cache home

// Set process group to make child process independent (Windows doesn't support Setpgid)
cmd.SysProcAttr = &syscall.SysProcAttr{}
Expand Down
Loading
Loading