From df41ab2c884b9b77ed6b39c616b9d6a76353b976 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:22:30 +0000 Subject: [PATCH 1/2] Fix Windows upgrade process to uninstall existing CLI before installation Co-Authored-By: jhaynie@agentuity.com --- cmd/project.go | 2 +- internal/mcp/config.go | 6 ++--- internal/util/upgrade.go | 58 +++++++++++++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 10 deletions(-) diff --git a/cmd/project.go b/cmd/project.go index 1fa589fa..1397f238 100644 --- a/cmd/project.go +++ b/cmd/project.go @@ -754,7 +754,7 @@ Examples: if len(orgs) > 1 { for _, orgId := range orgs { fmt.Println() - fmt.Println(tui.Bold(orgNames[orgId]) + " " + tui.Muted("(" + orgId + ")")) + fmt.Println(tui.Bold(orgNames[orgId]) + " " + tui.Muted("("+orgId+")")) fmt.Println() headers := []string{tui.Title("Project Id"), tui.Title("Name"), tui.Title("Description")} diff --git a/internal/mcp/config.go b/internal/mcp/config.go index 51f288e7..ae0342d1 100644 --- a/internal/mcp/config.go +++ b/internal/mcp/config.go @@ -29,6 +29,7 @@ type MCPClientApplicationConfig struct { Windows []string Linux []string } + func toPathArray(path string) []string { if path == "" { return []string{} @@ -36,7 +37,6 @@ func toPathArray(path string) []string { return []string{path} } - type MCPClientConfig struct { Name string ConfigLocation string @@ -130,7 +130,7 @@ func Detect(all bool) ([]MCPClientConfig, error) { case "linux": filepaths = config.Application.Linux } - + for _, filepath := range filepaths { if filepath == "$PATH" { if config.Command != "" { @@ -236,7 +236,7 @@ func Install(ctx context.Context, logger logger.Logger) error { if installed == 0 { tui.ShowSuccess("All MCP clients are up-to-date") } - + return nil } diff --git a/internal/util/upgrade.go b/internal/util/upgrade.go index 45b6b0d1..60f03c0f 100644 --- a/internal/util/upgrade.go +++ b/internal/util/upgrade.go @@ -506,6 +506,46 @@ func upgradeWithWindowsMsi(ctx context.Context, version string) error { } defer os.RemoveAll(tempDir) + var uninstallErr error + uninstallAction := func() { + uninstallScriptPath := filepath.Join(tempDir, "uninstall.ps1") + uninstallScript := ` +$products = Get-CimInstance -Class Win32_Product | Where-Object { $_.Name -like "*Agentuity*" } +if ($products) { + foreach ($product in $products) { + Write-Output "Uninstalling: $($product.Name) ($($product.IdentifyingNumber))" + $result = $product | Invoke-CimMethod -MethodName Uninstall + if ($result.ReturnValue -eq 0) { + Write-Output "Successfully uninstalled $($product.Name)" + } else { + Write-Output "Failed to uninstall $($product.Name) with return code $($result.ReturnValue)" + exit 1 + } + } + exit 0 +} else { + Write-Output "No existing Agentuity installation found" + exit 0 +} +` + if err := os.WriteFile(uninstallScriptPath, []byte(uninstallScript), 0644); err != nil { + uninstallErr = fmt.Errorf("failed to create uninstall script: %w", err) + return + } + + uninstallCmd := exec.CommandContext(ctx, "powershell", "-ExecutionPolicy", "Bypass", "-File", uninstallScriptPath) + output, err := uninstallCmd.CombinedOutput() + if err != nil { + uninstallErr = fmt.Errorf("failed to run uninstall script: %w, output: %s", err, string(output)) + return + } + tui.ShowSuccess("Uninstall step completed: %s", strings.TrimSpace(string(output))) + } + tui.ShowSpinner("Checking for existing installations...", uninstallAction) + if uninstallErr != nil { + tui.ShowWarning("Uninstall failed, continuing with installation: %v", uninstallErr) + } + installerName := getMsiInstallerName() installerURL := fmt.Sprintf("https://github.com/agentuity/cli/releases/download/%s/%s", version, installerName) installerPath := filepath.Join(tempDir, installerName) @@ -523,12 +563,18 @@ func upgradeWithWindowsMsi(ctx context.Context, version string) error { var installErr error installAction := func() { - updateCmd := exec.CommandContext(ctx, "msiexec", "/update", installerPath, "/qn") - if err := updateCmd.Run(); err != nil { - tui.ShowWarning("Update approach failed, trying install with reinstall: %v", err) - installCmd := exec.CommandContext(ctx, "msiexec", "/i", installerPath, "/qn", "REINSTALLMODE=amus", "REINSTALL=ALL") - if err := installCmd.Run(); err != nil { - installErr = fmt.Errorf("failed to run MSI installer: %w", err) + installCmd := exec.CommandContext(ctx, "msiexec", "/i", installerPath, "/qn", "/norestart") + if err := installCmd.Run(); err != nil { + tui.ShowWarning("Direct install failed, trying with update approach: %v", err) + + updateCmd := exec.CommandContext(ctx, "msiexec", "/update", installerPath, "/qn") + if err := updateCmd.Run(); err != nil { + tui.ShowWarning("Update approach failed, trying install with reinstall: %v", err) + + reinstallCmd := exec.CommandContext(ctx, "msiexec", "/i", installerPath, "/qn", "REINSTALLMODE=amus", "REINSTALL=ALL") + if err := reinstallCmd.Run(); err != nil { + installErr = fmt.Errorf("failed to run MSI installer: %w", err) + } } } } From 897b57542b87507db5eb1a4f4898e38063292b9e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 29 Apr 2025 19:27:55 +0000 Subject: [PATCH 2/2] Make CLI command immediately available in PowerShell after installation Co-Authored-By: jhaynie@agentuity.com --- install.ps1 | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/install.ps1 b/install.ps1 index f4f26ab3..364d022e 100644 --- a/install.ps1 +++ b/install.ps1 @@ -283,6 +283,31 @@ function Add-ToPath { # Also update current session $env:PATH = "$env:PATH;$PathToAdd" } + + # Refresh PowerShell's command discovery to make the command immediately available + # This creates a temporary function with the same name as the executable to force PowerShell to refresh + $exeName = "agentuity" + $tempFunctionName = "global:$exeName" + + # Remove any existing function with this name first + if (Get-Command $exeName -ErrorAction SilentlyContinue) { + if ((Get-Command $exeName).CommandType -eq "Function") { + Remove-Item -Path "Function:\$exeName" -ErrorAction SilentlyContinue + } + } + + # Create a temporary function that will redirect to the actual executable + $scriptBlock = { + param($argumentList) + & "$PathToAdd\$exeName.exe" @argumentList + # Remove this function after first use to ensure future calls use the actual executable + Remove-Item -Path "Function:\$exeName" -ErrorAction SilentlyContinue + } + + # Register the function + Set-Item -Path $tempFunctionName -Value $scriptBlock -Force + + Write-Success "Command '$exeName' is now available in the current PowerShell session" } catch { Write-Error "Failed to update PATH: $_"