@@ -13,6 +13,7 @@ import (
1313 "github.com/spf13/cobra"
1414
1515 "github.com/kevinelliott/agentmanager/internal/cli/output"
16+ "github.com/kevinelliott/agentmanager/internal/versionfetch"
1617 "github.com/kevinelliott/agentmanager/pkg/agent"
1718 "github.com/kevinelliott/agentmanager/pkg/catalog"
1819 "github.com/kevinelliott/agentmanager/pkg/config"
@@ -74,16 +75,19 @@ Results are cached for 1 hour by default. Use --refresh to force re-detection.`,
7475 ctx , cancel := context .WithTimeout (context .Background (), 120 * time .Second )
7576 defer cancel ()
7677
78+ // Single source of truth for no-color.
79+ noColor := output .NoColor (cfg , false )
80+
7781 // Create printer for colored output
78- printer := output .NewPrinter (cfg , cmd . Flag ( "no-color" ). Changed && cmd . Flag ( "no-color" ). Value . String () == "true" )
82+ printer := output .NewPrinter (cfg , noColor )
7983
8084 // Get current platform
8185 plat := platform .Current ()
8286
8387 // Create spinner for loading
8488 spinner := output .NewSpinner (
8589 output .WithMessage ("Loading..." ),
86- output .WithNoColor (! cfg . UI . UseColors ),
90+ output .WithNoColor (noColor ),
8791 )
8892 spinner .Start ()
8993
@@ -162,20 +166,10 @@ Results are cached for 1 hour by default. Use --refresh to force re-detection.`,
162166 // Update spinner for version checking
163167 spinner .UpdateMessage ("Checking for updates..." )
164168
165- // Check for latest versions
166- for _ , inst := range installations {
167- if agentDef , ok := agentDefMap [inst .AgentID ]; ok {
168- // Find the matching install method
169- methodStr := string (inst .Method )
170- if method , ok := agentDef .InstallMethods [methodStr ]; ok {
171- // Get latest version from package registry
172- latestVer , err := instMgr .GetLatestVersion (ctx , method )
173- if err == nil {
174- inst .LatestVersion = & latestVer
175- }
176- }
177- }
178- }
169+ // Fetch latest versions in parallel. Errors are intentionally
170+ // dropped here to preserve the existing silent-failure semantics
171+ // of `agent list`.
172+ _ = versionfetch .CheckLatestVersions (ctx , instMgr , installations , agentDefMap , versionfetch .DefaultConcurrency )
179173
180174 // Save last update check time
181175 _ = store .SetLastUpdateCheckTime (ctx , time .Now ()) //nolint:errcheck // best-effort timestamp; non-critical if this fails
@@ -441,29 +435,18 @@ Use --all to update all agents at once.`,
441435
442436 spinner .UpdateMessage ("Checking for updates..." )
443437
444- // Check for latest versions so HasUpdate() works correctly
445- var versionCheckErrors []string
446- for _ , installation := range installations {
447- if agentDef , ok := agentDefMap [installation .AgentID ]; ok {
448- methodStr := string (installation .Method )
449- if method , ok := agentDef .InstallMethods [methodStr ]; ok {
450- latestVer , err := inst .GetLatestVersion (ctx , method )
451- if err == nil {
452- installation .LatestVersion = & latestVer
453- } else {
454- versionCheckErrors = append (versionCheckErrors , fmt .Sprintf ("%s (%s): %v" , installation .AgentName , methodStr , err ))
455- }
456- }
457- }
458- }
438+ // Check for latest versions in parallel so HasUpdate() works correctly.
439+ // The returned per-index errors are aggregated and surfaced to the user.
440+ perIndexErrs := versionfetch .CheckLatestVersions (ctx , inst , installations , agentDefMap , versionfetch .DefaultConcurrency )
441+ versionCheckErrors := versionfetch .NonNilErrors (perIndexErrs )
459442
460443 spinner .Stop ()
461444
462445 // Surface version check failures so users know why updates may not be detected
463446 if len (versionCheckErrors ) > 0 && ! force {
464447 printer .Warning ("Could not check latest version for %d agent(s):" , len (versionCheckErrors ))
465448 for _ , e := range versionCheckErrors {
466- printer .Print (" - %s" , e )
449+ printer .Print (" - %s" , e . Error () )
467450 }
468451 printer .Print ("" )
469452 }
@@ -494,7 +477,7 @@ func updateAllAgents(ctx context.Context, installations []*agent.Installation, c
494477
495478 spinner := output .NewSpinner (
496479 output .WithMessage ("Checking for updates..." ),
497- output .WithNoColor (os . Getenv ( "NO_COLOR" ) != "" ),
480+ output .WithNoColor (printer . NoColor () ),
498481 )
499482 spinner .Start ()
500483
@@ -546,7 +529,7 @@ func updateAllAgents(ctx context.Context, installations []*agent.Installation, c
546529
547530 spinner := output .NewSpinner (
548531 output .WithMessage (fmt .Sprintf ("Updating %s via %s..." , installation .AgentName , installation .Method )),
549- output .WithNoColor (os . Getenv ( "NO_COLOR" ) != "" ),
532+ output .WithNoColor (printer . NoColor () ),
550533 )
551534 spinner .Start ()
552535
@@ -628,7 +611,7 @@ func updateSingleAgent(ctx context.Context, agentID string, installations []*age
628611
629612 spinner := output .NewSpinner (
630613 output .WithMessage (fmt .Sprintf ("Updating %s via %s..." , installation .AgentName , installation .Method )),
631- output .WithNoColor (os . Getenv ( "NO_COLOR" ) != "" ),
614+ output .WithNoColor (printer . NoColor () ),
632615 )
633616 spinner .Start ()
634617
@@ -952,7 +935,7 @@ results. The new detection results are then cached for future use.`,
952935 // Create spinner
953936 spinner := output .NewSpinner (
954937 output .WithMessage ("Clearing cache..." ),
955- output .WithNoColor (! cfg . UI . UseColors ),
938+ output .WithNoColor (output . NoColor ( cfg , false ) ),
956939 )
957940 spinner .Start ()
958941
@@ -1005,18 +988,9 @@ results. The new detection results are then cached for future use.`,
1005988
1006989 spinner .UpdateMessage ("Checking for updates..." )
1007990
1008- // Check for latest versions
1009- for _ , inst := range installations {
1010- if agentDef , ok := agentDefMap [inst .AgentID ]; ok {
1011- methodStr := string (inst .Method )
1012- if method , ok := agentDef .InstallMethods [methodStr ]; ok {
1013- latestVer , err := instMgr .GetLatestVersion (ctx , method )
1014- if err == nil {
1015- inst .LatestVersion = & latestVer
1016- }
1017- }
1018- }
1019- }
991+ // Check for latest versions in parallel. Errors are intentionally
992+ // dropped to preserve existing silent-failure semantics for refresh.
993+ _ = versionfetch .CheckLatestVersions (ctx , instMgr , installations , agentDefMap , versionfetch .DefaultConcurrency )
1020994
1021995 // Save to cache
1022996 if cfg .Detection .CacheEnabled {
0 commit comments