# install.ps1 — One-line installer for codebase-memory-mcp (Windows). # # Usage: see README.md for install instructions. # # Environment: # CBM_DOWNLOAD_URL Override base URL for downloads (for testing) $ErrorActionPreference = "Stop" # Enforce TLS 1.2+ (older PowerShell defaults to TLS 1.0 which GitHub rejects) [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -bor [Net.SecurityProtocolType]::Tls13 $Repo = "DeusData/codebase-memory-mcp" $InstallDir = "$env:LOCALAPPDATA\Programs\codebase-memory-mcp" $BinName = "codebase-memory-mcp.exe" $BaseUrl = if ($env:CBM_DOWNLOAD_URL) { $env:CBM_DOWNLOAD_URL } else { "https://github.com/$Repo/releases/latest/download" } # Security: reject non-HTTPS download URLs (defense-in-depth) if (-not $BaseUrl.StartsWith("https://") -and -not $BaseUrl.StartsWith("http://localhost") -and -not $BaseUrl.StartsWith("http://127.0.0.1")) { Write-Host "error: refusing non-HTTPS download URL: $BaseUrl" -ForegroundColor Red exit 1 } # Detect variant from args (--ui or --standard) $Variant = "standard" $SkipConfig = $false foreach ($arg in $args) { if ($arg -eq "--ui") { $Variant = "ui" } if ($arg -eq "--standard") { $Variant = "standard" } if ($arg -eq "--skip-config") { $SkipConfig = $true } if ($arg -like "--dir=*") { $InstallDir = $arg.Substring(6) } } # Detect the OS architecture. RuntimeInformation.OSArchitecture reports the real # OS arch (Arm64) even from an x64 process running under emulation on ARM64 -- # unlike $env:PROCESSOR_ARCHITECTURE, which reports the emulated "AMD64", and # PROCESSOR_ARCHITEW6432, which is unset for 64-bit emulated processes. Fall back # to the env vars only if the .NET API is somehow unavailable. if ($env:CBM_ARCH) { # Explicit override wins — used by CI/tests, and an escape hatch under x64 # emulation on ARM64 where no in-process detection is reliable. $Arch = $env:CBM_ARCH } else { try { $osArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture $Arch = if ($osArch -eq 'Arm64') { "arm64" } else { "amd64" } } catch { if ($env:PROCESSOR_ARCHITECTURE -eq "ARM64" -or $env:PROCESSOR_ARCHITEW6432 -eq "ARM64") { $Arch = "arm64" } else { $Arch = "amd64" } } } Write-Host "codebase-memory-mcp installer (Windows)" Write-Host " variant: $Variant" Write-Host " arch: $Arch" Write-Host " target: $InstallDir\$BinName" Write-Host "" # Build download URL if ($Variant -eq "ui") { $Archive = "codebase-memory-mcp-ui-windows-$Arch.zip" } else { $Archive = "codebase-memory-mcp-windows-$Arch.zip" } $Url = "$BaseUrl/$Archive" # Download $TmpDir = Join-Path ([System.IO.Path]::GetTempPath()) "cbm-install-$(Get-Random)" New-Item -ItemType Directory -Path $TmpDir -Force | Out-Null Write-Host "Downloading $Archive..." try { Invoke-WebRequest -Uri $Url -OutFile "$TmpDir\$Archive" -UseBasicParsing } catch { Write-Host "error: download failed: $_" -ForegroundColor Red Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue exit 1 } # Checksum verification $ChecksumUrl = "$BaseUrl/checksums.txt" try { Invoke-WebRequest -Uri $ChecksumUrl -OutFile "$TmpDir\checksums.txt" -UseBasicParsing $checksumLine = Get-Content "$TmpDir\checksums.txt" | Where-Object { $_ -like "*$Archive*" } if ($checksumLine) { $expected = ($checksumLine -split '\s+')[0] $actual = (Get-FileHash -Path "$TmpDir\$Archive" -Algorithm SHA256).Hash.ToLower() if ($expected -ne $actual) { Write-Host "error: CHECKSUM MISMATCH!" -ForegroundColor Red Write-Host " expected: $expected" Write-Host " actual: $actual" Remove-Item -Recurse -Force $TmpDir exit 1 } Write-Host "Checksum verified." } } catch { Write-Host "warning: could not verify checksum (non-fatal)" } # Extract Write-Host "Extracting..." Expand-Archive -Path "$TmpDir\$Archive" -DestinationPath $TmpDir -Force $DlBin = Join-Path $TmpDir $BinName if (-not (Test-Path $DlBin)) { # UI variant may have different name in zip $UiBin = Join-Path $TmpDir "codebase-memory-mcp-ui.exe" if (Test-Path $UiBin) { Rename-Item $UiBin $BinName $DlBin = Join-Path $TmpDir $BinName } else { Write-Host "error: binary not found after extraction" -ForegroundColor Red Remove-Item -Recurse -Force $TmpDir exit 1 } } # Install New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null $Dest = Join-Path $InstallDir $BinName # Handle replace-if-running (rename-aside) if (Test-Path $Dest) { $OldDest = "$Dest.old" Remove-Item $OldDest -Force -ErrorAction SilentlyContinue try { Rename-Item $Dest $OldDest -ErrorAction Stop } catch { Write-Host "warning: could not rename existing binary (may be in use)" } } Copy-Item $DlBin $Dest -Force # Verify try { $ver = & $Dest --version 2>&1 Write-Host "Installed: $ver" } catch { Write-Host "error: installed binary failed to run" -ForegroundColor Red Remove-Item -Recurse -Force $TmpDir exit 1 } # Configure agents if ($SkipConfig) { Write-Host "" Write-Host "Skipping agent configuration (--skip-config)" } else { Write-Host "" Write-Host "Configuring coding agents..." & $Dest install -y 2>&1 | Write-Host if ($LASTEXITCODE -ne 0) { Write-Host "" Write-Host "error: agent configuration failed (exit code $LASTEXITCODE)" -ForegroundColor Red Write-Host "The binary was installed, but no coding agents were configured." Write-Host "Run manually to configure: `"$Dest`" install" exit 1 } } # Add to PATH (user scope, no admin needed) $UserPath = [Environment]::GetEnvironmentVariable("PATH", "User") if ($UserPath -notlike "*$InstallDir*") { [Environment]::SetEnvironmentVariable("PATH", "$UserPath;$InstallDir", "User") $env:PATH = "$env:PATH;$InstallDir" Write-Host "Added $InstallDir to user PATH" } # Cleanup Remove-Item -Recurse -Force $TmpDir -ErrorAction SilentlyContinue Write-Host "" Write-Host "Done! Restart your terminal and coding agent to start using codebase-memory-mcp."