feat: add auto-update via winget (#349)

Drew Smirnoff created

Change summary

docs/docs/installation.md |  8 ++++++--
main.go                   | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+), 2 deletions(-)

Detailed changes

docs/docs/installation.md 🔗

@@ -102,6 +102,12 @@ You can download pre-compiled binaries from the [Releases page](https://github.c
 
 ## 🪟 Windows
 
+### Winget is the recommended way to install Matcha on Windows.
+
+```powershell
+winget install --id=floatpane.matcha
+```
+
 ### Manual Binary Download
 
 You can download pre-compiled binaries from the [Releases page](https://github.com/floatpane/matcha/releases).
@@ -117,8 +123,6 @@ You can download pre-compiled binaries from the [Releases page](https://github.c
     Type or paste the full path to the folder where your executable is located (e.g., C:\CLI Tools\MyTool\).
     Click "OK" on all open windows to save the changes.
 
-> Matcha will be added to WinGet as soons as possible!
-
 ### WSL
 
 You can run Matcha on Windows using [WSL (Windows Subsystem for Linux)](https://learn.microsoft.com/en-us/windows/wsl/install).

main.go 🔗

@@ -1950,6 +1950,25 @@ func detectInstalledVersion() string {
 		}
 	}
 
+	// Try WinGet (Windows)
+	if runtime.GOOS == "windows" {
+		if _, err := exec.LookPath("winget"); err == nil {
+			if out, err := exec.Command("winget", "list", "--id", "floatpane.matcha", "--disable-interactivity").Output(); err == nil {
+				lines := strings.Split(strings.TrimSpace(string(out)), "\n")
+				for _, line := range lines {
+					if strings.Contains(strings.ToLower(line), "floatpane.matcha") {
+						fields := strings.Fields(line)
+						for _, f := range fields {
+							if len(f) > 0 && f[0] >= '0' && f[0] <= '9' && strings.Contains(f, ".") {
+								return f
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
 	// Try snap (Linux)
 	if runtime.GOOS == "linux" {
 		if _, err := exec.LookPath("snap"); err == nil {
@@ -2148,6 +2167,23 @@ func runUpdateCLI() error {
 		}
 	}
 
+	// Detect WinGet
+	if _, err := exec.LookPath("winget"); err == nil {
+		cmdCheck := exec.Command("winget", "list", "--id", "floatpane.matcha", "--disable-interactivity")
+		if err := cmdCheck.Run(); err == nil {
+			fmt.Println("Detected WinGet package — attempting to upgrade.")
+			cmd := exec.Command("winget", "upgrade", "--id", "floatpane.matcha", "--disable-interactivity")
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			if err := cmd.Run(); err == nil {
+				fmt.Println("Successfully upgraded via WinGet.")
+				return nil
+			}
+			fmt.Printf("WinGet upgrade failed: %v\n", err)
+			// fallthrough
+		}
+	}
+
 	// Otherwise attempt to download the proper release asset and replace the binary.
 	osName := runtime.GOOS
 	arch := runtime.GOARCH