scripts/modules/vscode/setup-vscode.ps1
# strangeloop Setup - VS Code Integration Module # Version: 1.0.0 param( [string]${project-path}, [string]${project-name}, [string]${loop-name}, [string]$Platform = "Windows", [switch]${what-if} ) # Import shared modules $SharedPath = Split-Path $PSScriptRoot | Join-Path -ChildPath "shared" Import-Module "$SharedPath\write-functions.ps1" -Force -DisableNameChecking Import-Module "$SharedPath\test-functions.ps1" -Force -DisableNameChecking function Test-VSCodeInstallation { <# .SYNOPSIS Tests if VS Code is installed and accessible .OUTPUTS Boolean indicating if VS Code is available #> try { # Check if 'code' command is available $codeVersion = & code --version 2>$null if ($LASTEXITCODE -eq 0 -and $codeVersion) { return $true } # Check common installation paths $commonPaths = @( "$env:LOCALAPPDATA\Programs\Microsoft VS Code\Code.exe", "$env:PROGRAMFILES\Microsoft VS Code\Code.exe", "${env:PROGRAMFILES(X86)}\Microsoft VS Code\Code.exe" ) foreach ($path in $commonPaths) { if (Test-Path $path) { return $true } } return $false } catch { return $false } } function Get-VSCodeExtensions { <# .SYNOPSIS Gets list of installed VS Code extensions .OUTPUTS Array of installed extension IDs #> try { $extensions = & code --list-extensions 2>$null if ($LASTEXITCODE -eq 0) { return $extensions } return @() } catch { return @() } } function Install-VSCodeExtension { <# .SYNOPSIS Installs a VS Code extension .PARAMETER ExtensionId The extension ID to install .PARAMETER what-if Shows what would be done without actually performing the actions .OUTPUTS Boolean indicating success #> param( [Parameter(Mandatory)] [string]$ExtensionId, [switch]${what-if} ) try { if (${what-if}) { Write-Host "what if: Would install VS Code extension: $ExtensionId" -ForegroundColor Yellow return $true } else { { Write-Progress "Installing VS Code extension: $ExtensionId" } $result = & code --install-extension $ExtensionId --force 2>&1 if ($LASTEXITCODE -eq 0) { { Write-Success "Extension installed: $ExtensionId" } return $true } else { { Write-Warning "Failed to install extension $ExtensionId`: $result" } return $false } } } catch { { Write-Warning "Error installing extension $ExtensionId`: $($_.Exception.Message)" } return $false } } function Get-RecommendedExtensions { <# .SYNOPSIS Gets recommended extensions based on loop type .PARAMETER LoopName The name of the loop .OUTPUTS Array of recommended extension IDs #> param( [string]$LoopName ) $baseExtensions = @( "ms-vscode.PowerShell", # PowerShell support "ms-azuretools.vscode-azureresourcegroups" # Azure tools ) $loopSpecificExtensions = @() switch -Regex ($LoopName) { "python|flask" { $loopSpecificExtensions += @( "ms-python.python", "ms-python.autopep8", "ms-python.flake8", "ms-python.pylint" ) } "csharp|dotnet|asp" { $loopSpecificExtensions += @( "ms-dotnettools.csharp", "ms-dotnettools.vscode-dotnet-runtime" # Note: Removed ms-vscode.vscode-nuget-package-manager as it doesn't exist ) } "mcp" { $loopSpecificExtensions += @( # MCP projects typically use JSON configuration ) } "langgraph|agent" { $loopSpecificExtensions += @( "ms-python.python", "ms-toolsai.jupyter" ) } } return $baseExtensions + $loopSpecificExtensions } function Open-ProjectInVSCode { <# .SYNOPSIS Opens a project directory in VS Code .PARAMETER ProjectPath Full path to the project directory (Windows path or WSL path) .PARAMETER RequiresWSL Whether this is a WSL project .PARAMETER what-if Shows what would be done without actually performing the actions .OUTPUTS Boolean indicating success #> param( [Parameter(Mandatory)] [string]$ProjectPath, [switch]$RequiresWSL, [switch]${what-if} ) try { if (${what-if}) { if ($RequiresWSL) { Write-Host "what if: Would open WSL project in VS Code: $ProjectPath" -ForegroundColor Yellow Write-Host "what if: Would execute 'wsl -- bash -c \"cd '$ProjectPath' && code .\"'" -ForegroundColor Yellow } else { Write-Host "what if: Would open Windows project in VS Code: $ProjectPath" -ForegroundColor Yellow Write-Host "what if: Would execute 'code \"$ProjectPath\"'" -ForegroundColor Yellow } return $true } if ($RequiresWSL) { # Open WSL project in VS Code { Write-Progress "Opening WSL project in VS Code..." } # Handle different path formats for WSL $wslPath = $ProjectPath -replace '^WSL: ', '' # If it's a Windows path, suggest using WSL home directory instead if ($wslPath -match '^[A-Za-z]:') { Write-Warning "Windows path provided for WSL loop. WSL projects should be in WSL filesystem." # Extract just the project name from the Windows path $projectName = Split-Path $wslPath -Leaf try { $wslUser = & wsl -- whoami 2>$null if ($wslUser) { $wslPath = "/home/$($wslUser.Trim())/AdsSnR_Containers/services/$projectName" } else { $wslPath = "/home/\$USER/AdsSnR_Containers/services/$projectName" } } catch { $wslPath = "/home/\$USER/AdsSnR_Containers/services/$projectName" } Write-Host " Using WSL path: $wslPath" -ForegroundColor Yellow } # Convert $USER variable to absolute path if needed if ($wslPath.Contains('$USER')) { # Get the absolute path from WSL by expanding the $USER variable $absolutePath = wsl -- bash -c "echo `"$wslPath`"" 2>$null if ($LASTEXITCODE -eq 0 -and $absolutePath) { $expandedPath = $absolutePath.Trim() Write-Host " Expanded WSL path: $expandedPath" -ForegroundColor Gray # Use the expanded absolute path for the code command $wslPath = $expandedPath } else { { Write-Warning "Could not expand WSL path, using original: $wslPath" } } } # Use the default WSL distribution try { { Write-Progress "Opening project in VS Code..." } Write-Host " Running WSL command: cd '$wslPath' && code ." -ForegroundColor Gray # Use default WSL distribution (no -d parameter) $result = wsl -- bash -c "cd '$wslPath' && code ." 2>&1 $success = ($LASTEXITCODE -eq 0) } catch { $success = $false $result = "Failed to open VS Code: $($_.Exception.Message)" } } else { # Open Windows project in VS Code (preserve current directory) { Write-Progress "Opening project in VS Code..." } # Use direct command execution to ensure proper path handling try { # Quote the path to handle spaces and special characters $quotedPath = "`"$ProjectPath`"" # Use Invoke-Expression to properly execute the command $output = Invoke-Expression "code $quotedPath" 2>&1 # Check if the command executed without errors if ($LASTEXITCODE -eq 0 -or $LASTEXITCODE -eq $null) { $result = "VS Code started successfully" $success = $true } else { $result = "VS Code command failed with exit code: $LASTEXITCODE" $success = $false } } catch { $result = "Failed to start VS Code: $($_.Exception.Message)" $success = $false } } if ($success -or ($result -match "successfully")) { { Write-Success "Project opened in VS Code" } return $true } else { { Write-Warning "Failed to open project in VS Code: $result" } return $false } } catch { { Write-Warning "Error opening project in VS Code: $($_.Exception.Message)" } return $false } } function Get-VSCodeOpeningPreference { <# .SYNOPSIS Prompts user whether to open the project in VS Code .OUTPUTS Boolean indicating whether to open VS Code #> Write-Host "" Write-Host "📝 " -ForegroundColor Blue -NoNewline $response = Read-UserPrompt -Prompt "Open project in VS Code?" -ValidValues @("y","n") return Test-YesResponse $response } function Initialize-VSCodeIntegration { <# .SYNOPSIS Main function to setup VS Code integration .PARAMETER project-path Parent directory path where the project was created .PARAMETER project-name Name of the project (subdirectory within project-path) .PARAMETER loop-name Name of the loop template .PARAMETER Platform Target platform (Windows or WSL) .PARAMETER what-if Shows what would be done without actually performing the actions .OUTPUTS Boolean indicating success #> param( [string]${project-path}, [string]${project-name}, [string]${loop-name}, [string]$Platform = "Windows", [switch]${what-if} ) Write-Step "Setting up VS Code Integration..." if (${what-if}) { Write-Host "what if: Would check VS Code installation" -ForegroundColor Yellow Write-Host "what if: Would get list of currently installed VS Code extensions" -ForegroundColor Yellow if ($Platform -eq "WSL") { Write-Host "what if: Would install WSL extension for VS Code" -ForegroundColor Yellow } if (${loop-name}) { $recommendedExtensions = Get-RecommendedExtensions -LoopName ${loop-name} Write-Host "what if: Would install these VS Code extensions: $($recommendedExtensions -join ', ')" -ForegroundColor Yellow } if (${project-path} -and ${project-name}) { Write-Host "what if: Would open project in VS Code" -ForegroundColor Yellow } return $true } # Debug: Show what parameters were received Write-Host "📋 VSCode Integration Parameters:" -ForegroundColor Cyan Write-Host " ProjectPath: ${project-path}" -ForegroundColor Gray Write-Host " ProjectName: ${project-name}" -ForegroundColor Gray Write-Host " LoopName: ${loop-name}" -ForegroundColor Gray Write-Host " Platform: $Platform" -ForegroundColor Gray try { # Test VS Code installation Write-Progress "Checking VS Code installation..." if (-not (Test-VSCodeInstallation)) { Write-Warning "VS Code is not installed or not accessible via 'code' command" Write-Info "Please ensure VS Code is installed and added to PATH" return $false } Write-Success "VS Code is available" # Get current extensions $installedExtensions = Get-VSCodeExtensions # Install WSL extension if running on WSL platform if ($Platform -eq "WSL") { $wslExtension = "ms-vscode-remote.remote-wsl" if ($wslExtension -notin $installedExtensions) { Write-Progress "Installing WSL extension for VS Code..." $wslInstallResult = Install-VSCodeExtension -ExtensionId $wslExtension -what-if:${what-if} if (-not $wslInstallResult) { Write-Warning "Failed to install WSL extension, but continuing..." } } else { Write-Success "WSL extension already installed" } } # Install recommended extensions based on loop type if (${loop-name}) { $recommendedExtensions = Get-RecommendedExtensions -LoopName ${loop-name} foreach ($extension in $recommendedExtensions) { if ($extension -notin $installedExtensions) { $null = Install-VSCodeExtension -ExtensionId $extension -what-if:${what-if} # Continue even if some extensions fail to install } } } # Open project directory in VS Code if path is provided and user wants to if (${project-path} -and ${project-name}) { # Assign to local variables for easier handling $projectPath = $null $projectName = $null if ($PSBoundParameters.ContainsKey('project-path')) { $projectPath = $PSBoundParameters['project-path'] } if ($PSBoundParameters.ContainsKey('project-name')) { $projectName = $PSBoundParameters['project-name'] } if ($Platform -eq "WSL") { # Always use forward slashes for WSL, handle nulls safely $cleanProjectPath = if ($projectPath) { $projectPath.TrimEnd('/') } else { '' } $cleanProjectName = if ($projectName) { $projectName.TrimStart('/') } else { '' } $fullProjectPath = "$cleanProjectPath/$cleanProjectName" } else { $fullProjectPath = Join-Path $projectPath $projectName } # Check if the path exists using platform-appropriate method $pathExists = $false if ($Platform -eq "WSL") { # For WSL platform, test path existence in WSL $pathExistsInWSL = wsl test -d "$fullProjectPath" 2>$null $pathExists = ($LASTEXITCODE -eq 0) } else { # For Windows platform, use PowerShell Test-Path $pathExists = Test-Path $fullProjectPath } $shouldOpenVSCode = Get-VSCodeOpeningPreference if ($pathExists) { if ($shouldOpenVSCode) { Write-Host "🚀 Opening project in VS Code: $fullProjectPath" -ForegroundColor Green $openResult = Open-ProjectInVSCode -ProjectPath $fullProjectPath -RequiresWSL:($Platform -eq "WSL") -what-if:${what-if} if (-not $openResult) { Write-Warning "Failed to open project in VS Code, but setup completed" } } else { Write-Info "Skipping VS Code project opening" } } else { Write-Warning "Project path does not exist: $fullProjectPath" Write-Info "Platform: $Platform" if ($Platform -eq "WSL") { Write-Info "Tip: For WSL projects, ensure the path exists in the WSL filesystem" Write-Info "You can check with: wsl ls -la '$fullProjectPath'" } else { Write-Info "You can check with: Test-Path '$fullProjectPath'" } } } elseif (${project-path} -and -not ${project-name}) { # Handle case where project-path is already the full path to the project Write-Info "Using provided project path as full project directory" $fullProjectPath = ${project-path} # Check path existence based on the platform $pathExists = $false if ($Platform -eq "WSL") { # For WSL platform, test path existence in WSL $pathExistsInWSL = wsl test -d "$fullProjectPath" 2>$null $pathExists = ($LASTEXITCODE -eq 0) } else { # For Windows platform, use PowerShell Test-Path $pathExists = Test-Path $fullProjectPath } # Verify the path exists if ($pathExists) { $shouldOpenVSCode = Get-VSCodeOpeningPreference if ($shouldOpenVSCode) { Write-Host "🚀 Opening project in VS Code: $fullProjectPath" -ForegroundColor Green $openResult = Open-ProjectInVSCode -ProjectPath $fullProjectPath -RequiresWSL:($Platform -eq "WSL") -what-if:${what-if} if (-not $openResult) { Write-Warning "Failed to open project in VS Code, but setup completed" } } else { Write-Info "Skipping VS Code project opening" } } else { Write-Warning "Project path does not exist: $fullProjectPath" Write-Info "Platform: $Platform" if ($Platform -eq "WSL") { Write-Info "Tip: For WSL projects, ensure the path exists in the WSL filesystem" Write-Info "You can check with: wsl ls -la '$fullProjectPath'" } else { Write-Info "You can check with: Test-Path '$fullProjectPath'" } } } else { Write-Warning "No project path provided to VSCode integration" } Write-Success "VS Code integration setup completed" return $true } catch { Write-Error "VS Code integration setup failed: $($_.Exception.Message)" return $false } } # Main execution if ($MyInvocation.InvocationName -ne '.') { $result = Initialize-VSCodeIntegration -project-path ${project-path} -project-name ${project-name} -loop-name ${loop-name} -Platform $Platform -what-if:${what-if} if ($result) { Write-Success "VS Code integration completed successfully" return $result } else { Write-Error "VS Code integration failed" return $false } } |