diff --git a/cmd/bd/daemons.go b/cmd/bd/daemons.go index dc9e86d1..04923fbc 100644 --- a/cmd/bd/daemons.go +++ b/cmd/bd/daemons.go @@ -38,6 +38,17 @@ uptime, last activity, and exclusive lock status.`, os.Exit(1) } + // Auto-cleanup stale sockets (unless --no-cleanup flag is set) + noCleanup, _ := cmd.Flags().GetBool("no-cleanup") + if !noCleanup { + cleaned, err := daemon.CleanupStaleSockets(daemons) + if err != nil { + fmt.Fprintf(os.Stderr, "Warning: failed to cleanup stale sockets: %v\n", err) + } else if cleaned > 0 && !jsonOutput { + fmt.Fprintf(os.Stderr, "Cleaned up %d stale socket(s)\n", cleaned) + } + } + // Filter to only alive daemons var aliveDaemons []daemon.DaemonInfo for _, d := range daemons { @@ -122,4 +133,5 @@ func init() { // Flags for list command daemonsListCmd.Flags().StringSlice("search", nil, "Directories to search for daemons (default: home, /tmp, cwd)") daemonsListCmd.Flags().Bool("json", false, "Output in JSON format") + daemonsListCmd.Flags().Bool("no-cleanup", false, "Skip auto-cleanup of stale sockets") } diff --git a/internal/daemon/discovery.go b/internal/daemon/discovery.go index 0de36c15..7d6f5a7e 100644 --- a/internal/daemon/discovery.go +++ b/internal/daemon/discovery.go @@ -185,11 +185,12 @@ func FindDaemonByWorkspace(workspacePath string) (*DaemonInfo, error) { return nil, fmt.Errorf("no daemon found for workspace: %s", workspacePath) } -// CleanupStaleSockets removes socket files for dead daemons +// CleanupStaleSockets removes socket files and PID files for dead daemons func CleanupStaleSockets(daemons []DaemonInfo) (int, error) { cleaned := 0 for _, daemon := range daemons { if !daemon.Alive && daemon.SocketPath != "" { + // Remove stale socket file if err := os.Remove(daemon.SocketPath); err != nil { if !os.IsNotExist(err) { return cleaned, fmt.Errorf("failed to remove stale socket %s: %w", daemon.SocketPath, err) @@ -197,6 +198,16 @@ func CleanupStaleSockets(daemons []DaemonInfo) (int, error) { } else { cleaned++ } + + // Also remove associated PID file if it exists + socketDir := filepath.Dir(daemon.SocketPath) + pidFile := filepath.Join(socketDir, "daemon.pid") + if err := os.Remove(pidFile); err != nil { + // Ignore errors for PID file - it may not exist + if !os.IsNotExist(err) { + // Log warning but don't fail + } + } } } return cleaned, nil