param( [string]$Token = "TQExdmXUMwhPlV58YfgueAscatHrZBKnI1W63Dq7", [string]$InstallRoot = "$env:USERPROFILE\Desktop\Vigthoria Code\vigthoria-desktop-bridge-mvp-20260520-v013-live", [string]$Server = "root@78.46.154.201", [int]$Port = 49160 ) $ErrorActionPreference = "Stop" $LogDir = Join-Path $env:TEMP "vigthoria-desktop-bridge" $BridgeOut = Join-Path $LogDir "bridge-out.log" $BridgeErr = Join-Path $LogDir "bridge-err.log" $TunnelOut = Join-Path $LogDir "tunnel-out.log" $TunnelErr = Join-Path $LogDir "tunnel-err.log" New-Item -ItemType Directory -Path $LogDir -Force | Out-Null function Stop-LocalPort([int]$PortNumber) { $listeners = @(Get-NetTCPConnection -LocalPort $PortNumber -State Listen -ErrorAction SilentlyContinue | Select-Object -ExpandProperty OwningProcess -Unique) foreach ($pidValue in $listeners) { if ($pidValue) { Write-Host "Stopping local PID $pidValue on port $PortNumber" taskkill /F /PID $pidValue 2>$null | Out-Null } } } function Wait-LocalHealth([int]$PortNumber) { for ($i = 1; $i -le 20; $i++) { try { $health = Invoke-RestMethod -Uri "http://127.0.0.1:$PortNumber/health" -TimeoutSec 2 Write-Host "Local bridge health OK on ${PortNumber}: $($health.service)" return $true } catch { Start-Sleep -Milliseconds 500 } } return $false } if (!(Test-Path (Join-Path $InstallRoot "src\local-desktop-bridge.js"))) { throw "Bridge install not found: $InstallRoot" } Set-Location $InstallRoot Write-Host "Stopping local bridge/tunnel processes on port $Port..." Stop-LocalPort $Port Start-Sleep -Seconds 2 Remove-Item $BridgeOut,$BridgeErr,$TunnelOut,$TunnelErr -ErrorAction SilentlyContinue $env:VIGTHORIA_DESKTOP_TOKEN = $Token $env:VIGTHORIA_DESKTOP_ALLOW_CONTROL = "1" $env:VIGTHORIA_DESKTOP_PORT = "$Port" Remove-Item Env:\VIGTHORIA_DESKTOP_HEALTH_SCREEN -ErrorAction SilentlyContinue Write-Host "Starting bridge detached on 127.0.0.1:$Port..." $bridge = Start-Process -FilePath "node.exe" -ArgumentList @(".\src\local-desktop-bridge.js") -WorkingDirectory $InstallRoot -WindowStyle Minimized -RedirectStandardOutput $BridgeOut -RedirectStandardError $BridgeErr -PassThru Write-Host "Bridge PID: $($bridge.Id)" if (!(Wait-LocalHealth $Port)) { Write-Host "Local bridge health FAILED. stdout:" Get-Content $BridgeOut -ErrorAction SilentlyContinue Write-Host "stderr:" Get-Content $BridgeErr -ErrorAction SilentlyContinue throw "Local bridge did not answer /health on port $Port" } Write-Host "Clearing server reverse tunnel port $Port..." & ssh.exe $Server "fuser -k $Port/tcp 2>/dev/null || true; ss -tlnp | grep :$Port || true" Write-Host "Starting reverse SSH tunnel detached..." $tunnelArgs = @( "-N", "-o", "ExitOnForwardFailure=yes", "-o", "ServerAliveInterval=30", "-o", "ServerAliveCountMax=3", "-R", "127.0.0.1:$Port`:127.0.0.1:$Port", $Server ) $tunnel = Start-Process -FilePath "ssh.exe" -ArgumentList $tunnelArgs -WindowStyle Minimized -RedirectStandardOutput $TunnelOut -RedirectStandardError $TunnelErr -PassThru Write-Host "Tunnel PID: $($tunnel.Id)" Start-Sleep -Seconds 3 Write-Host "Verifying from server through reverse tunnel..." $remoteCommand = "curl --max-time 10 -fsS http://127.0.0.1:$Port/health" & ssh.exe $Server $remoteCommand if ($LASTEXITCODE -ne 0) { Write-Host "Server verification failed. Tunnel stderr:" Get-Content $TunnelErr -ErrorAction SilentlyContinue throw "Server could not reach bridge through tunnel" } Write-Host "SUCCESS: bridge and tunnel are running detached. You may leave this shell open or close it." Write-Host "Bridge log: $BridgeOut" Write-Host "Bridge err: $BridgeErr" Write-Host "Tunnel log: $TunnelOut" Write-Host "Tunnel err: $TunnelErr"