@@ -23,6 +23,7 @@ import (
2323 "github.com/pushchain/push-validator-cli/internal/process"
2424 syncmon "github.com/pushchain/push-validator-cli/internal/sync"
2525 ui "github.com/pushchain/push-validator-cli/internal/ui"
26+ "github.com/pushchain/push-validator-cli/internal/update"
2627 "github.com/pushchain/push-validator-cli/internal/validator"
2728)
2829
3637// rootCmd wires the CLI surface using Cobra. Persistent flags are
3738// applied to a loaded config in loadCfg(). Subcommands implement the
3839// actual operations (init, start/stop, sync, status, etc.).
40+ // updateCheckResult stores the result of background update check
41+ var updateCheckResult * update.CheckResult
42+
3943var rootCmd = & cobra.Command {
4044 Use : "push-validator" ,
4145 Short : "Push Validator" ,
@@ -51,6 +55,20 @@ var rootCmd = &cobra.Command{
5155 Quiet : flagQuiet ,
5256 Debug : flagDebug ,
5357 })
58+
59+ // Start background update check (non-blocking)
60+ // Skip for update command itself and help/version commands
61+ cmdName := cmd .Name ()
62+ if cmdName != "update" && cmdName != "help" && cmdName != "version" {
63+ go checkForUpdateBackground ()
64+ }
65+ },
66+ PersistentPostRun : func (cmd * cobra.Command , args []string ) {
67+ // Show update notification if available (after command completes)
68+ // Skip for update command itself
69+ if cmd .Name () != "update" && updateCheckResult != nil && updateCheckResult .UpdateAvailable {
70+ showUpdateNotification (updateCheckResult .LatestVersion )
71+ }
5472 },
5573}
5674
@@ -850,6 +868,7 @@ func handleDashboard(cfg config.Config) error {
850868 RPCTimeout : 5 * time .Second ,
851869 NoColor : flagNoColor ,
852870 NoEmoji : flagNoEmoji ,
871+ CLIVersion : Version ,
853872 Debug : false ,
854873 }
855874 return runDashboardInteractive (opts )
@@ -938,3 +957,69 @@ func isTerminalInteractive() bool {
938957 }
939958 return true
940959}
960+
961+ // checkForUpdateBackground performs a non-blocking update check.
962+ // Uses cache to avoid checking more than once per 24 hours.
963+ // Stores result in updateCheckResult global for use by PersistentPostRun.
964+ func checkForUpdateBackground () {
965+ cfg := loadCfg ()
966+
967+ // Check cache first (avoid network calls if recently checked)
968+ cache , err := update .LoadCache (cfg .HomeDir )
969+ if err == nil && update .IsCacheValid (cache ) {
970+ // Use cached result
971+ if cache .UpdateAvailable {
972+ updateCheckResult = & update.CheckResult {
973+ CurrentVersion : strings .TrimPrefix (Version , "v" ),
974+ LatestVersion : cache .LatestVersion ,
975+ UpdateAvailable : true ,
976+ }
977+ }
978+ return
979+ }
980+
981+ // Perform network check with timeout
982+ updater , err := update .NewUpdater (Version )
983+ if err != nil {
984+ return // Silently fail - don't disrupt user's command
985+ }
986+
987+ result , err := updater .Check ()
988+ if err != nil {
989+ return // Silently fail
990+ }
991+
992+ // Save to cache
993+ _ = update .SaveCache (cfg .HomeDir , & update.CacheEntry {
994+ CheckedAt : time .Now (),
995+ LatestVersion : result .LatestVersion ,
996+ UpdateAvailable : result .UpdateAvailable ,
997+ })
998+
999+ // Store result for notification
1000+ if result .UpdateAvailable {
1001+ updateCheckResult = result
1002+ }
1003+ }
1004+
1005+ // showUpdateNotification displays an update notification after command completes.
1006+ func showUpdateNotification (latestVersion string ) {
1007+ // Don't show in JSON/YAML output modes
1008+ if flagOutput == "json" || flagOutput == "yaml" {
1009+ return
1010+ }
1011+
1012+ // Don't show in quiet mode
1013+ if flagQuiet {
1014+ return
1015+ }
1016+
1017+ c := ui .NewColorConfig ()
1018+ c .Enabled = c .Enabled && ! flagNoColor
1019+
1020+ fmt .Println ()
1021+ fmt .Println (c .Warning ("─────────────────────────────────────────────────────────────" ))
1022+ fmt .Printf (c .Warning (" Update available: %s → %s\n " ), Version , latestVersion )
1023+ fmt .Println (c .Info (" Run: push-validator update" ))
1024+ fmt .Println (c .Warning ("─────────────────────────────────────────────────────────────" ))
1025+ }
0 commit comments