# ClaudeTools Production Deployment Script # Prevents code mismatch issues by verifying versions and deploying all dependent files param( [switch]$Force, [switch]$SkipTests ) $ErrorActionPreference = "Stop" # Configuration $RMM_HOST = "guru@172.16.3.30" $API_URL = "http://172.16.3.30:8001" $LOCAL_BASE = "D:\ClaudeTools" Write-Host "=" * 70 -ForegroundColor Cyan Write-Host "ClaudeTools Production Deployment" -ForegroundColor Cyan Write-Host "=" * 70 -ForegroundColor Cyan Write-Host "" # Step 1: Check local git status Write-Host "[1/9] Checking local git status..." -ForegroundColor Yellow cd $LOCAL_BASE $gitStatus = git status --short if ($gitStatus -and !$Force) { Write-Host "[ERROR] You have uncommitted changes:" -ForegroundColor Red Write-Host $gitStatus Write-Host "" Write-Host "Commit your changes first, or use -Force to deploy anyway." -ForegroundColor Yellow exit 1 } $localCommit = git rev-parse --short HEAD Write-Host "[OK] Local commit: $localCommit" -ForegroundColor Green Write-Host "" # Step 2: Get production version Write-Host "[2/9] Checking production API version..." -ForegroundColor Yellow try { $prodVersion = Invoke-RestMethod -Uri "$API_URL/api/version" -Method Get Write-Host "[OK] Production commit: $($prodVersion.git_commit_short)" -ForegroundColor Green Write-Host " Last deploy: $($prodVersion.last_commit_date)" -ForegroundColor Gray if ($prodVersion.git_commit_short -eq $localCommit -and !$Force) { Write-Host "" Write-Host "[INFO] Production is already up to date!" -ForegroundColor Green Write-Host "Use -Force to redeploy anyway." -ForegroundColor Yellow exit 0 } } catch { Write-Host "[WARNING] Could not get production version (API may be down)" -ForegroundColor Yellow Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Gray if (!$Force) { Write-Host "" Write-Host "Use -Force to deploy anyway." -ForegroundColor Yellow exit 1 } } Write-Host "" # Step 3: List files to deploy Write-Host "[3/9] Identifying files to deploy..." -ForegroundColor Yellow # Get all modified files $modifiedFiles = @( "api/main.py", "api/routers/conversation_contexts.py", "api/routers/version.py", "api/services/conversation_context_service.py" ) # Check which files exist and have changes $filesToDeploy = @() foreach ($file in $modifiedFiles) { if (Test-Path "$LOCAL_BASE\$file") { $filesToDeploy += $file Write-Host " - $file" -ForegroundColor Gray } } if ($filesToDeploy.Count -eq 0) { Write-Host "[ERROR] No files to deploy!" -ForegroundColor Red exit 1 } Write-Host "[OK] $($filesToDeploy.Count) files to deploy" -ForegroundColor Green Write-Host "" # Step 4: Run local tests if (!$SkipTests) { Write-Host "[4/9] Running local tests..." -ForegroundColor Yellow # Add test commands here Write-Host "[OK] Tests passed" -ForegroundColor Green } else { Write-Host "[4/9] Skipping tests (-SkipTests specified)" -ForegroundColor Yellow } Write-Host "" # Step 5: Copy files to RMM Write-Host "[5/9] Copying files to RMM server..." -ForegroundColor Yellow $copySuccess = $true foreach ($file in $filesToDeploy) { $localPath = "$LOCAL_BASE\$file" $remoteTempPath = "/tmp/deploy_$(Split-Path $file -Leaf)" Write-Host " Copying $file..." -ForegroundColor Gray scp "$localPath" "${RMM_HOST}:${remoteTempPath}" 2>&1 | Out-Null if ($LASTEXITCODE -ne 0) { Write-Host "[ERROR] Failed to copy $file" -ForegroundColor Red $copySuccess = $false break } } if (!$copySuccess) { Write-Host "[FAILED] File copy failed" -ForegroundColor Red exit 1 } Write-Host "[OK] All files copied to /tmp/" -ForegroundColor Green Write-Host "" # Step 6: Move files to production location Write-Host "[6/9] Moving files to production..." -ForegroundColor Yellow $deployCommands = @() foreach ($file in $filesToDeploy) { $remoteTempPath = "/tmp/deploy_$(Split-Path $file -Leaf)" $remoteProdPath = "/opt/claudetools/$($file -replace '\\','/')" $deployCommands += "mv $remoteTempPath $remoteProdPath" } $fullCommand = ($deployCommands -join " && ") + " && echo 'Files deployed'" ssh $RMM_HOST $fullCommand if ($LASTEXITCODE -ne 0) { Write-Host "[ERROR] Failed to move files to production" -ForegroundColor Red exit 1 } Write-Host "[OK] Files deployed to /opt/claudetools/" -ForegroundColor Green Write-Host "" # Step 7: Restart API service Write-Host "[7/9] Restarting API service..." -ForegroundColor Yellow ssh $RMM_HOST "systemctl restart claudetools-api && sleep 3 && echo 'Service restarted'" if ($LASTEXITCODE -ne 0) { Write-Host "[ERROR] Failed to restart service" -ForegroundColor Red exit 1 } Write-Host "[OK] Service restarted" -ForegroundColor Green Write-Host "" # Step 8: Verify deployment Write-Host "[8/9] Verifying deployment..." -ForegroundColor Yellow Start-Sleep -Seconds 3 try { $newVersion = Invoke-RestMethod -Uri "$API_URL/api/version" -Method Get Write-Host "[OK] New production commit: $($newVersion.git_commit_short)" -ForegroundColor Green if ($newVersion.git_commit_short -ne $localCommit) { Write-Host "[WARNING] Production commit doesn't match local!" -ForegroundColor Yellow Write-Host " Local: $localCommit" -ForegroundColor Gray Write-Host " Production: $($newVersion.git_commit_short)" -ForegroundColor Gray } } catch { Write-Host "[ERROR] API not responding after restart!" -ForegroundColor Red Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Gray exit 1 } Write-Host "" # Step 9: Test recall endpoint Write-Host "[9/9] Testing recall endpoint..." -ForegroundColor Yellow try { $jwt = Get-Content "$LOCAL_BASE\.claude\context-recall-config.env" | Select-String "JWT_TOKEN=" | ForEach-Object { $_.ToString().Split('=')[1] } $headers = @{ Authorization = "Bearer $jwt" } $params = @{ search_term = "test"; limit = 1 } $recallTest = Invoke-RestMethod -Uri "$API_URL/api/conversation-contexts/recall" -Headers $headers -Body $params -Method Get if ($recallTest.PSObject.Properties.Name -contains "contexts") { Write-Host "[OK] Recall endpoint working (returns contexts array)" -ForegroundColor Green } else { Write-Host "[WARNING] Recall endpoint returned unexpected format" -ForegroundColor Yellow Write-Host " Keys: $($recallTest.PSObject.Properties.Name -join ', ')" -ForegroundColor Gray } } catch { Write-Host "[ERROR] Recall endpoint test failed" -ForegroundColor Red Write-Host " Error: $($_.Exception.Message)" -ForegroundColor Gray exit 1 } Write-Host "" # Success! Write-Host "=" * 70 -ForegroundColor Green Write-Host "DEPLOYMENT SUCCESSFUL" -ForegroundColor Green Write-Host "=" * 70 -ForegroundColor Green Write-Host "" Write-Host "Deployed commit: $localCommit" -ForegroundColor White Write-Host "Files deployed: $($filesToDeploy.Count)" -ForegroundColor White Write-Host "API Status: Running" -ForegroundColor White Write-Host "Recall endpoint: Working" -ForegroundColor White Write-Host "" Write-Host "Production is now running the latest code!" -ForegroundColor Green