327 lines
10 KiB
PowerShell
327 lines
10 KiB
PowerShell
# codebase-memory-mcp setup script (Windows)
|
|
# Default: download pre-built native Windows binary
|
|
# -FromSource: build from source inside WSL (requires Go + gcc in WSL)
|
|
|
|
param(
|
|
[switch]$FromSource,
|
|
[switch]$Help
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$Repo = "DeusData/codebase-memory-mcp"
|
|
$BinaryName = "codebase-memory-mcp"
|
|
$InstallDir = Join-Path $env:LOCALAPPDATA "codebase-memory-mcp"
|
|
|
|
# --- Helpers ---
|
|
|
|
function Write-Ok($msg) { Write-Host " $msg" -ForegroundColor Green }
|
|
function Write-Fail($msg) { Write-Host " $msg" -ForegroundColor Red }
|
|
function Write-Warn($msg) { Write-Host " $msg" -ForegroundColor Yellow }
|
|
|
|
function Read-SettingsJson($Path) {
|
|
# PS5.1-compatible: ConvertFrom-Json returns PSCustomObject, not Hashtable.
|
|
# We convert to ordered hashtable manually.
|
|
if (-not (Test-Path $Path)) {
|
|
return @{}
|
|
}
|
|
$raw = Get-Content $Path -Raw
|
|
if (-not $raw -or $raw.Trim() -eq "") {
|
|
return @{}
|
|
}
|
|
$obj = $raw | ConvertFrom-Json
|
|
$ht = [ordered]@{}
|
|
foreach ($prop in $obj.PSObject.Properties) {
|
|
if ($prop.Value -is [System.Management.Automation.PSCustomObject]) {
|
|
$inner = [ordered]@{}
|
|
foreach ($p in $prop.Value.PSObject.Properties) {
|
|
$inner[$p.Name] = $p.Value
|
|
}
|
|
$ht[$prop.Name] = $inner
|
|
} else {
|
|
$ht[$prop.Name] = $prop.Value
|
|
}
|
|
}
|
|
return $ht
|
|
}
|
|
|
|
function Write-SettingsJson($Path, $Settings) {
|
|
# Back up existing file before writing
|
|
if (Test-Path $Path) {
|
|
Copy-Item $Path "$Path.bak" -Force
|
|
}
|
|
$Settings | ConvertTo-Json -Depth 10 | Set-Content $Path -Encoding UTF8
|
|
}
|
|
|
|
function Configure-ClaudeCode($McpConfig) {
|
|
Write-Host ""
|
|
$answer = Read-Host "Configure Claude Code to use codebase-memory-mcp? [y/N]"
|
|
|
|
if ($answer -match '^[Yy]$') {
|
|
$settingsPath = Join-Path $env:USERPROFILE ".claude\settings.json"
|
|
$settingsDir = Split-Path $settingsPath -Parent
|
|
|
|
if (-not (Test-Path $settingsDir)) {
|
|
New-Item -ItemType Directory -Path $settingsDir -Force | Out-Null
|
|
}
|
|
|
|
$settings = Read-SettingsJson $settingsPath
|
|
|
|
if (-not $settings.Contains("mcpServers")) {
|
|
$settings["mcpServers"] = [ordered]@{}
|
|
}
|
|
|
|
$settings["mcpServers"]["codebase-memory-mcp"] = $McpConfig
|
|
Write-SettingsJson $settingsPath $settings
|
|
Write-Ok "Updated $settingsPath"
|
|
} else {
|
|
Write-Host ""
|
|
Write-Host " Add this to your .mcp.json or %USERPROFILE%\.claude\settings.json:" -ForegroundColor White
|
|
Write-Host ""
|
|
$snippet = @{ mcpServers = @{ "codebase-memory-mcp" = $McpConfig } }
|
|
$snippet | ConvertTo-Json -Depth 10 | Write-Host
|
|
}
|
|
}
|
|
|
|
function Test-WSL {
|
|
try {
|
|
$null = wsl.exe --status 2>&1
|
|
if ($LASTEXITCODE -ne 0) { return $false }
|
|
return $true
|
|
} catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
function Get-WSLDistro {
|
|
$output = wsl.exe -l -v 2>&1 | Out-String
|
|
$lines = $output -split "`n" | Where-Object { $_ -match '\S' } | Select-Object -Skip 1
|
|
foreach ($line in $lines) {
|
|
$clean = $line -replace '\x00', '' -replace '^\s+', ''
|
|
if ($clean -match '^\*?\s*(\S+)\s+') {
|
|
$name = $Matches[1]
|
|
if ($name -ne "NAME" -and $name -ne "") {
|
|
return $name
|
|
}
|
|
}
|
|
}
|
|
return $null
|
|
}
|
|
|
|
function Invoke-WSL {
|
|
param([string]$Command)
|
|
$result = wsl.exe -- bash -c $Command 2>&1
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "WSL command failed: $Command`n$result"
|
|
}
|
|
return $result
|
|
}
|
|
|
|
# --- Main ---
|
|
|
|
if ($Help) {
|
|
Write-Host ""
|
|
Write-Host "Usage: .\setup-windows.ps1 [-FromSource] [-Help]"
|
|
Write-Host ""
|
|
Write-Host " Default: Download pre-built Windows binary"
|
|
Write-Host " -FromSource: Build from source inside WSL (requires Go 1.23+ and gcc in WSL)"
|
|
Write-Host ""
|
|
exit 0
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "codebase-memory-mcp installer (Windows)" -ForegroundColor White
|
|
Write-Host ""
|
|
|
|
if ($FromSource) {
|
|
# --- Build from source via WSL ---
|
|
Write-Host "Checking WSL2 (required for building from source)..." -ForegroundColor White
|
|
|
|
if (-not (Test-WSL)) {
|
|
Write-Fail "WSL2 is not available. Required for building from source (CGO needs gcc)."
|
|
Write-Host ""
|
|
Write-Host " Install WSL2:" -ForegroundColor Yellow
|
|
Write-Host " wsl --install -d Ubuntu"
|
|
Write-Host " Then restart your computer and run this script again."
|
|
Write-Host ""
|
|
Write-Host " Alternatively, download a pre-built binary (no WSL needed):" -ForegroundColor Yellow
|
|
Write-Host " .\setup-windows.ps1"
|
|
exit 1
|
|
}
|
|
Write-Ok "WSL2 is available"
|
|
|
|
$distro = Get-WSLDistro
|
|
if (-not $distro) {
|
|
Write-Fail "No WSL Linux distribution found."
|
|
Write-Host ""
|
|
Write-Host " Install Ubuntu:" -ForegroundColor Yellow
|
|
Write-Host " wsl --install -d Ubuntu"
|
|
exit 1
|
|
}
|
|
Write-Ok "WSL distro: $distro"
|
|
|
|
$wslUser = (Invoke-WSL "whoami").Trim()
|
|
Write-Ok "WSL user: $wslUser"
|
|
|
|
Write-Host ""
|
|
Write-Host "Checking prerequisites inside WSL..." -ForegroundColor White
|
|
|
|
# Check for gcc
|
|
try {
|
|
Invoke-WSL "command -v gcc" | Out-Null
|
|
Write-Ok "gcc found"
|
|
} catch {
|
|
Write-Warn "gcc not found. Installing build-essential..."
|
|
Invoke-WSL "sudo apt-get update && sudo apt-get install -y build-essential"
|
|
}
|
|
|
|
# Check for Go
|
|
try {
|
|
$goVersion = Invoke-WSL "go version"
|
|
Write-Ok "Go: $goVersion"
|
|
} catch {
|
|
Write-Fail "Go not found in WSL."
|
|
Write-Host ""
|
|
Write-Host " Install Go 1.23+ inside WSL:" -ForegroundColor Yellow
|
|
Write-Host " See https://go.dev/dl/ for Linux amd64 tarball"
|
|
exit 1
|
|
}
|
|
|
|
# Check for git
|
|
try {
|
|
Invoke-WSL "command -v git" | Out-Null
|
|
Write-Ok "git found"
|
|
} catch {
|
|
Write-Fail "git not found in WSL. Install with: sudo apt install git"
|
|
exit 1
|
|
}
|
|
|
|
# Clone or update
|
|
Write-Host ""
|
|
$sourceDir = "/home/$wslUser/.local/share/codebase-memory-mcp"
|
|
try {
|
|
Invoke-WSL "test -d $sourceDir/.git" | Out-Null
|
|
Write-Host "Updating source..." -ForegroundColor White
|
|
Invoke-WSL "git -C $sourceDir pull --ff-only"
|
|
} catch {
|
|
Write-Host "Cloning repository..." -ForegroundColor White
|
|
Invoke-WSL "mkdir -p /home/$wslUser/.local/share && git clone https://github.com/$Repo.git $sourceDir"
|
|
}
|
|
Write-Ok "Source at $sourceDir"
|
|
|
|
# Build
|
|
Write-Host ""
|
|
Write-Host "Building binary (this may take a minute)..." -ForegroundColor White
|
|
$wslBinaryPath = "/home/$wslUser/.local/bin/$BinaryName"
|
|
Invoke-WSL "mkdir -p /home/$wslUser/.local/bin && cd $sourceDir && scripts/build.sh && cp build/c/codebase-memory-mcp $wslBinaryPath"
|
|
Write-Ok "Built to $wslBinaryPath (inside WSL)"
|
|
|
|
# Verify
|
|
try {
|
|
Invoke-WSL "test -x $wslBinaryPath" | Out-Null
|
|
Write-Ok "Binary is executable"
|
|
} catch {
|
|
Write-Fail "Binary at $wslBinaryPath is not executable"
|
|
exit 1
|
|
}
|
|
|
|
# Configure — WSL binary needs wsl.exe wrapper
|
|
$mcpConfig = [ordered]@{
|
|
type = "stdio"
|
|
command = "wsl.exe"
|
|
args = @("-d", $distro, "--", $wslBinaryPath)
|
|
}
|
|
|
|
Configure-ClaudeCode $mcpConfig
|
|
|
|
Write-Host ""
|
|
Write-Ok "Done! Restart Claude Code and verify with /mcp"
|
|
Write-Host ""
|
|
Write-Host " To uninstall:" -ForegroundColor White
|
|
Write-Host " wsl.exe -- rm $wslBinaryPath"
|
|
Write-Host " wsl.exe -- rm -rf $sourceDir"
|
|
Write-Host " wsl.exe -- rm -rf ~/.cache/codebase-memory-mcp/"
|
|
|
|
} else {
|
|
# --- Download pre-built native Windows binary ---
|
|
Write-Host "Fetching latest release..." -ForegroundColor White
|
|
|
|
$releaseUrl = "https://api.github.com/repos/$Repo/releases/latest"
|
|
$release = Invoke-RestMethod -Uri $releaseUrl -Headers @{ "User-Agent" = "codebase-memory-mcp-setup" }
|
|
$tag = $release.tag_name
|
|
|
|
if (-not $tag) {
|
|
Write-Fail "Could not determine latest release."
|
|
Write-Host " Check: https://github.com/$Repo/releases"
|
|
exit 1
|
|
}
|
|
Write-Ok "Latest release: $tag"
|
|
|
|
$asset = "codebase-memory-mcp-windows-amd64.zip"
|
|
$downloadUrl = "https://github.com/$Repo/releases/download/$tag/$asset"
|
|
|
|
Write-Host "Downloading $asset..." -ForegroundColor White
|
|
|
|
# Create install directory
|
|
if (-not (Test-Path $InstallDir)) {
|
|
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
|
}
|
|
|
|
$tmpZip = Join-Path $env:TEMP $asset
|
|
Invoke-WebRequest -Uri $downloadUrl -OutFile $tmpZip -UseBasicParsing
|
|
|
|
# Extract
|
|
Expand-Archive -Path $tmpZip -DestinationPath $InstallDir -Force
|
|
Remove-Item $tmpZip -Force
|
|
|
|
$binaryPath = Join-Path $InstallDir "$BinaryName.exe"
|
|
|
|
if (-not (Test-Path $binaryPath)) {
|
|
Write-Fail "Binary not found at $binaryPath after extraction"
|
|
exit 1
|
|
}
|
|
Write-Ok "Installed to $binaryPath"
|
|
|
|
# Verify binary runs
|
|
try {
|
|
$verOut = & $binaryPath --version 2>&1
|
|
Write-Ok "Version: $verOut"
|
|
} catch {
|
|
Write-Warn "Could not verify binary version (may still work)"
|
|
}
|
|
|
|
# SmartScreen note
|
|
Write-Host ""
|
|
Write-Warn "Windows SmartScreen may show a warning when the binary runs for the first time."
|
|
Write-Host " This is normal for unsigned open-source binaries." -ForegroundColor Yellow
|
|
Write-Host " Click 'More info' then 'Run anyway' to proceed." -ForegroundColor Yellow
|
|
Write-Host " Verify checksums at: https://github.com/$Repo/releases" -ForegroundColor Yellow
|
|
|
|
# Check if install dir is on PATH
|
|
$userPath = [Environment]::GetEnvironmentVariable("Path", "User")
|
|
if ($userPath -notlike "*$InstallDir*") {
|
|
Write-Host ""
|
|
Write-Warn "$InstallDir is not on your PATH."
|
|
$addPath = Read-Host " Add it to your user PATH? [y/N]"
|
|
if ($addPath -match '^[Yy]$') {
|
|
[Environment]::SetEnvironmentVariable("Path", "$userPath;$InstallDir", "User")
|
|
Write-Ok "Added to user PATH (restart your terminal to take effect)"
|
|
}
|
|
}
|
|
|
|
# Configure Claude Code
|
|
$mcpConfig = [ordered]@{
|
|
type = "stdio"
|
|
command = $binaryPath
|
|
}
|
|
|
|
Configure-ClaudeCode $mcpConfig
|
|
|
|
Write-Host ""
|
|
Write-Ok "Done! Restart Claude Code and verify with /mcp"
|
|
Write-Host ""
|
|
Write-Host " To uninstall:" -ForegroundColor White
|
|
Write-Host " Remove-Item -Recurse -Force '$InstallDir'"
|
|
Write-Host " Remove-Item -Recurse -Force `"$env:LOCALAPPDATA\codebase-memory-mcp`" # graph database"
|
|
}
|