From 0ef41ef6427e2d583fb9b6f0d44295739469d1d8 Mon Sep 17 00:00:00 2001 From: Snider Date: Sun, 1 Feb 2026 12:09:32 +0000 Subject: [PATCH] feat(update): auto-restart after update to load new version Uses syscall.Exec on Unix to replace the current process with the updated binary, running --version to confirm. On Windows, falls back to a message asking to restart manually. Co-Authored-By: Claude Opus 4.5 --- pkg/updater/cmd.go | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/pkg/updater/cmd.go b/pkg/updater/cmd.go index 85ed3fcf..e72bf3bf 100644 --- a/pkg/updater/cmd.go +++ b/pkg/updater/cmd.go @@ -2,7 +2,9 @@ package updater import ( "fmt" + "os" "runtime" + "syscall" "github.com/host-uk/core/pkg/cli" "github.com/spf13/cobra" @@ -115,9 +117,8 @@ func runUpdate(cmd *cobra.Command, args []string) error { } cli.Print("%s Updated to %s\n", cli.SuccessStyle.Render(cli.Glyph(":check:")), release.TagName) - cli.Print("Restart the CLI to use the new version.\n") - return nil + return restartBinary() } // handleDevUpdate handles updates from the dev release (rolling prerelease) @@ -154,9 +155,8 @@ func handleDevUpdate(currentVersion string) error { } cli.Print("%s Updated to %s\n", cli.SuccessStyle.Render(cli.Glyph(":check:")), release.TagName) - cli.Print("Restart the CLI to use the new version.\n") - return nil + return restartBinary() } // handleDevTagUpdate fetches the dev release using the direct tag @@ -185,7 +185,36 @@ func handleDevTagUpdate(currentVersion string) error { } cli.Print("%s Updated to latest dev build\n", cli.SuccessStyle.Render(cli.Glyph(":check:"))) - cli.Print("Restart the CLI to use the new version.\n") + return restartBinary() +} + +// restartBinary re-executes the current binary to load the new version. +// On Unix systems, it uses syscall.Exec to replace the current process. +// On Windows, it prints a message to restart manually. +func restartBinary() error { + executable, err := os.Executable() + if err != nil { + cli.Print("Restart the CLI to use the new version.\n") + return nil + } + + // On Windows, exec doesn't work the same way - just ask to restart + if runtime.GOOS == "windows" { + cli.Print("Restart the CLI to use the new version.\n") + return nil + } + + cli.Print("\n%s Restarting...\n", cli.DimStyle.Render("→")) + + // Re-exec with --version to confirm the update + err = syscall.Exec(executable, []string{executable, "--version"}, os.Environ()) + if err != nil { + // If exec fails, just tell user to restart + cli.Print("Restart the CLI to use the new version.\n") + return nil + } + + // This line is never reached if exec succeeds return nil }